diff options
92 files changed, 4178 insertions, 2439 deletions
diff --git a/Android.bp b/Android.bp index ecf6deeeb432..36ed8656cfbc 100644 --- a/Android.bp +++ b/Android.bp @@ -350,6 +350,7 @@ java_defaults { "tv_tuner_resource_manager_aidl_interface-java", "soundtrigger_middleware-aidl-java", "modules-utils-preconditions", + "modules-utils-synchronous-result-receiver", "modules-utils-os", "framework-permission-aidl-java", ], diff --git a/core/api/current.txt b/core/api/current.txt index 6aeed38e0adb..4f96abe2323e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9178,10 +9178,10 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void disconnect(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean discoverServices(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean executeReliableWrite(); - method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); - method public int getConnectionState(android.bluetooth.BluetoothDevice); + method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice); method public android.bluetooth.BluetoothDevice getDevice(); - method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]); + method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]); method public android.bluetooth.BluetoothGattService getService(java.util.UUID); method public java.util.List<android.bluetooth.BluetoothGattService> getServices(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic); @@ -10091,6 +10091,7 @@ package android.content { method @Nullable public String getPackageName(); method public int getUid(); method public boolean isTrusted(@NonNull android.content.Context); + method @NonNull public static android.content.AttributionSource myAttributionSource(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.AttributionSource> CREATOR; } @@ -21541,6 +21542,7 @@ package android.media { public class MediaActionSound { ctor public MediaActionSound(); method public void load(int); + method public static boolean mustPlayShutterSound(); method public void play(int); method public void release(); field public static final int FOCUS_COMPLETE = 1; // 0x1 @@ -25723,11 +25725,14 @@ package android.media.tv { field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2"; field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3"; field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4"; + field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; field public static final String COLUMN_LONG_DESCRIPTION = "long_description"; + field public static final String COLUMN_MULTI_SERIES_ID = "multi_series_id"; field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri"; field public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited"; field public static final String COLUMN_REVIEW_RATING = "review_rating"; field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style"; + field public static final String COLUMN_SCRAMBLED = "scrambled"; field public static final String COLUMN_SEARCHABLE = "searchable"; field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number"; field @Deprecated public static final String COLUMN_SEASON_NUMBER = "season_number"; @@ -25787,7 +25792,9 @@ package android.media.tv { field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2"; field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3"; field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4"; + field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; field public static final String COLUMN_LONG_DESCRIPTION = "long_description"; + field public static final String COLUMN_MULTI_SERIES_ID = "multi_series_id"; field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri"; field public static final String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes"; field public static final String COLUMN_RECORDING_DATA_URI = "recording_data_uri"; @@ -38284,7 +38291,8 @@ package android.service.carrier { method @Deprecated public final void notifyCarrierNetworkChange(boolean); method public final void notifyCarrierNetworkChange(int, boolean); method @CallSuper public android.os.IBinder onBind(android.content.Intent); - method public abstract android.os.PersistableBundle onLoadConfig(android.service.carrier.CarrierIdentifier); + method @Deprecated public abstract android.os.PersistableBundle onLoadConfig(android.service.carrier.CarrierIdentifier); + method @Nullable public android.os.PersistableBundle onLoadConfig(int, @Nullable android.service.carrier.CarrierIdentifier); field public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService"; } diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 81b4ee80a1d2..a646a681afc1 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -113,6 +113,8 @@ package android.media { public class AudioManager { method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int); 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 setA2dpSuspended(boolean); method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean); @@ -202,6 +204,10 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR; } + public final class IpSecManager { + field public static final int DIRECTION_FWD = 2; // 0x2 + } + public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { method public int getResourceId(); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index da9a4c50d3cb..bb454a642ff1 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -12001,6 +12001,7 @@ package android.telephony { } public class TelephonyManager { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String); @@ -12025,6 +12026,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageName(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageNameForLogicalSlot(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); @@ -12093,6 +12096,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>); @@ -12268,6 +12272,10 @@ package android.telephony { field public static final int RESULT_SUCCESS = 0; // 0x0 } + public static interface TelephonyManager.CarrierPrivilegesListener { + method public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]); + } + public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { method public int getErrorCode(); field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2 diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 0171f0a5a327..f9739a489453 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -130,6 +130,7 @@ import android.net.EthernetManager; import android.net.IEthernetManager; import android.net.IIpSecService; import android.net.INetworkPolicyManager; +import android.net.INetworkStatsService; import android.net.IPacProxyManager; import android.net.IVpnManager; import android.net.IpSecManager; @@ -981,7 +982,11 @@ public final class SystemServiceRegistry { new CachedServiceFetcher<NetworkStatsManager>() { @Override public NetworkStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException { - return new NetworkStatsManager(ctx.getOuterContext()); + // TODO: Replace with an initializer in the module, see + // {@code ConnectivityFrameworkInitializer}. + final INetworkStatsService service = INetworkStatsService.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); + return new NetworkStatsManager(ctx.getOuterContext(), service); }}); registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class, diff --git a/core/java/android/app/cloudsearch/OWNERS b/core/java/android/app/cloudsearch/OWNERS new file mode 100644 index 000000000000..aa4da3b4bee0 --- /dev/null +++ b/core/java/android/app/cloudsearch/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 758286 + +huiwu@google.com +srazdan@google.com diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index d66dc637743d..8b9cec17a196 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,17 +32,19 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** @@ -271,7 +275,7 @@ public final class BluetoothA2dp implements BluetoothProfile { IBluetoothA2dp.class.getName()) { @Override public IBluetoothA2dp getServiceInterface(IBinder service) { - return IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothA2dp.Stub.asInterface(service); } }; @@ -322,17 +326,21 @@ public final class BluetoothA2dp implements BluetoothProfile { @UnsupportedAppUsage public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - return service.connect(device); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connectWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -364,17 +372,21 @@ public final class BluetoothA2dp implements BluetoothProfile { @UnsupportedAppUsage public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - return service.disconnect(device); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnectWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -385,19 +397,24 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevicesWithAttribution(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevicesWithAttribution(mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -408,20 +425,25 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStatesWithAttribution(states, + mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStatesWithAttribution(states, - mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -432,18 +454,21 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @BtProfileState int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getConnectionState(device); + final IBluetoothA2dp service = getService(); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionStateWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; } + return defaultValue; } /** @@ -471,18 +496,21 @@ public final class BluetoothA2dp implements BluetoothProfile { @UnsupportedAppUsage(trackingBug = 171933273) public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && ((device == null) || isValidDevice(device))) { - return service.setActiveDevice(device, mAttributionSource); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && ((device == null) || isValidDevice(device))) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setActiveDevice(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -499,18 +527,24 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothDevice getActiveDevice() { if (VDBG) log("getActiveDevice()"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + final BluetoothDevice defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<BluetoothDevice> recv = + new SynchronousResultReceiver(); + service.getActiveDevice(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getActiveDevice(mAttributionSource), mAttributionSource); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return null; } + return defaultValue; } /** @@ -555,22 +589,23 @@ public final class BluetoothA2dp implements BluetoothProfile { public boolean setConnectionPolicy(@NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -589,19 +624,7 @@ public final class BluetoothA2dp implements BluetoothProfile { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - return BluetoothAdapter.connectionPolicyToPriority( - service.getPriority(device, mAttributionSource)); - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.PRIORITY_OFF; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.PRIORITY_OFF; - } + return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); } /** @@ -623,18 +646,21 @@ public final class BluetoothA2dp implements BluetoothProfile { }) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getConnectionPolicy(device, mAttributionSource); + final IBluetoothA2dp service = getService(); + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } + return defaultValue; } /** @@ -646,17 +672,21 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresNoPermission public boolean isAvrcpAbsoluteVolumeSupported() { if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { - return service.isAvrcpAbsoluteVolumeSupported(); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isAvrcpAbsoluteVolumeSupported(recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e); - return false; } + return defaultValue; } /** @@ -669,14 +699,16 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setAvrcpAbsoluteVolume(int volume) { if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { service.setAvrcpAbsoluteVolume(volume, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e); } } @@ -689,18 +721,22 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(BluetoothDevice device) { - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.isA2dpPlaying(device, mAttributionSource); + if (DBG) log("isA2dpPlaying(" + device + ")"); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isA2dpPlaying(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -729,8 +765,7 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * Gets the current codec status (configuration and capability). * - * @param device the remote Bluetooth device. If null, use the current - * active A2DP Bluetooth device. + * @param device the remote Bluetooth device. * @return the current codec status * @hide */ @@ -742,26 +777,28 @@ public final class BluetoothA2dp implements BluetoothProfile { public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) { if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")"); verifyDeviceNotNull(device, "getCodecStatus"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { - return service.getCodecStatus(device, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + final IBluetoothA2dp service = getService(); + final BluetoothCodecStatus defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<BluetoothCodecStatus> recv = + new SynchronousResultReceiver(); + service.getCodecStatus(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return null; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getCodecStatus()", e); - return null; } + return defaultValue; } /** * Sets the codec configuration preference. * - * @param device the remote Bluetooth device. If null, use the current - * active A2DP Bluetooth device. + * @param device the remote Bluetooth device. * @param codecConfig the codec configuration preference * @hide */ @@ -777,24 +814,23 @@ public final class BluetoothA2dp implements BluetoothProfile { Log.e(TAG, "setCodecConfigPreference: Codec config can't be null"); throw new IllegalArgumentException("codecConfig cannot be null"); } - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { service.setCodecConfigPreference(device, codecConfig, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e); - return; } } /** * Enables the optional codecs. * - * @param device the remote Bluetooth device. If null, use the currect - * active A2DP Bluetooth device. + * @param device the remote Bluetooth device. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -810,8 +846,7 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * Disables the optional codecs. * - * @param device the remote Bluetooth device. If null, use the currect - * active A2DP Bluetooth device. + * @param device the remote Bluetooth device. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -827,26 +862,25 @@ public final class BluetoothA2dp implements BluetoothProfile { /** * Enables or disables the optional codecs. * - * @param device the remote Bluetooth device. If null, use the currect - * active A2DP Bluetooth device. + * @param device the remote Bluetooth device. * @param enable if true, enable the optional codecs, other disable them */ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) { - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { + final IBluetoothA2dp service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { if (enable) { service.enableOptionalCodecs(device, mAttributionSource); } else { service.disableOptionalCodecs(device, mAttributionSource); } + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e); - return; } } @@ -864,18 +898,23 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @OptionalCodecsSupportStatus public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) { + if (DBG) log("isOptionalCodecsSupported(" + device + ")"); verifyDeviceNotNull(device, "isOptionalCodecsSupported"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - return service.supportsOptionalCodecs(device, mAttributionSource); + final IBluetoothA2dp service = getService(); + final int defaultValue = OPTIONAL_CODECS_SUPPORT_UNKNOWN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.supportsOptionalCodecs(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return OPTIONAL_CODECS_SUPPORT_UNKNOWN; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in supportsOptionalCodecs()", e); - return OPTIONAL_CODECS_SUPPORT_UNKNOWN; } + return defaultValue; } /** @@ -892,18 +931,23 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @OptionalCodecsPreferenceStatus public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) { + if (DBG) log("isOptionalCodecsEnabled(" + device + ")"); verifyDeviceNotNull(device, "isOptionalCodecsEnabled"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - return service.getOptionalCodecsEnabled(device, mAttributionSource); + final IBluetoothA2dp service = getService(); + final int defaultValue = OPTIONAL_CODECS_PREF_UNKNOWN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getOptionalCodecsEnabled(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return OPTIONAL_CODECS_PREF_UNKNOWN; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getOptionalCodecsEnabled()", e); - return OPTIONAL_CODECS_PREF_UNKNOWN; } + return defaultValue; } /** @@ -921,24 +965,24 @@ public final class BluetoothA2dp implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device, @OptionalCodecsPreferenceStatus int value) { + if (DBG) log("setOptionalCodecsEnabled(" + device + ")"); verifyDeviceNotNull(device, "setOptionalCodecsEnabled"); - try { - if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN - && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED - && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { - Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value); - return; - } - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { + if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN + && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED + && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { + Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value); + return; + } + final IBluetoothA2dp service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { service.setOptionalCodecsEnabled(device, value, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return; } } @@ -961,17 +1005,21 @@ public final class BluetoothA2dp implements BluetoothProfile { }) public @Type int getDynamicBufferSupport() { if (VDBG) log("getDynamicBufferSupport()"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { - return service.getDynamicBufferSupport(mAttributionSource); + final IBluetoothA2dp service = getService(); + final int defaultValue = DYNAMIC_BUFFER_SUPPORT_NONE; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getDynamicBufferSupport(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return DYNAMIC_BUFFER_SUPPORT_NONE; - } catch (RemoteException e) { - Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e); - return DYNAMIC_BUFFER_SUPPORT_NONE; } + return defaultValue; } /** @@ -992,17 +1040,22 @@ public final class BluetoothA2dp implements BluetoothProfile { }) public @Nullable BufferConstraints getBufferConstraints() { if (VDBG) log("getBufferConstraints()"); - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { - return service.getBufferConstraints(mAttributionSource); + final IBluetoothA2dp service = getService(); + final BufferConstraints defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<BufferConstraints> recv = + new SynchronousResultReceiver(); + service.getBufferConstraints(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return null; } + return defaultValue; } /** @@ -1027,17 +1080,21 @@ public final class BluetoothA2dp implements BluetoothProfile { Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value); return false; } - try { - final IBluetoothA2dp service = getService(); - if (service != null && isEnabled()) { - return service.setBufferLengthMillis(codec, value, mAttributionSource); + final IBluetoothA2dp service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setBufferLengthMillis(codec, value, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; } + return defaultValue; } /** diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java index 924dc55f31a0..59416818ceb3 100755 --- a/core/java/android/bluetooth/BluetoothA2dpSink.java +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -29,14 +31,16 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth A2DP Sink @@ -86,7 +90,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile { "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) { @Override public IBluetoothA2dpSink getServiceInterface(IBinder service) { - return IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothA2dpSink.Stub.asInterface(service); } }; @@ -140,16 +144,20 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -181,16 +189,20 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -204,17 +216,23 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -228,18 +246,23 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -251,18 +274,22 @@ public final class BluetoothA2dpSink implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { - if (VDBG) log("getState(" + device + ")"); + if (VDBG) log("getConnectionState(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -282,16 +309,21 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { if (VDBG) log("getAudioConfig(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final BluetoothAudioConfig defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getAudioConfig(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return null; + final SynchronousResultReceiver<BluetoothAudioConfig> recv = + new SynchronousResultReceiver(); + service.getAudioConfig(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; + return defaultValue; } /** @@ -337,20 +369,22 @@ public final class BluetoothA2dpSink implements BluetoothProfile { @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -393,16 +427,20 @@ public final class BluetoothA2dpSink implements BluetoothProfile { public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } /** @@ -420,17 +458,22 @@ public final class BluetoothA2dpSink implements BluetoothProfile { android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) public boolean isAudioPlaying(@NonNull BluetoothDevice device) { + if (VDBG) log("isAudioPlaying(" + device + ")"); final IBluetoothA2dpSink service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.isA2dpPlaying(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isA2dpPlaying(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 5612e7cf56ce..9b37457c9907 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -786,7 +786,7 @@ public final class BluetoothAdapter { @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - sAdapter = createAdapter(BluetoothManager.resolveAttributionSource(null)); + sAdapter = createAdapter(AttributionSource.myAttributionSource()); } return sAdapter; } diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java index 536dfb0a66dd..81fc3e11e9e1 100644 --- a/core/java/android/bluetooth/BluetoothAvrcpController.java +++ b/core/java/android/bluetooth/BluetoothAvrcpController.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -23,13 +25,15 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently @@ -93,8 +97,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile { "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) { @Override public IBluetoothAvrcpController getServiceInterface(IBinder service) { - return IBluetoothAvrcpController.Stub.asInterface( - Binder.allowBlocking(service)); + return IBluetoothAvrcpController.Stub.asInterface(service); } }; @@ -130,19 +133,24 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -153,20 +161,24 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -177,18 +189,21 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothAvrcpController service = getService(); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -201,17 +216,22 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) { if (DBG) Log.d(TAG, "getPlayerSettings"); BluetoothAvrcpPlayerSettings settings = null; - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final BluetoothAvrcpPlayerSettings defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - settings = service.getPlayerSettings(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in getMetadata() " + e); - return null; + final SynchronousResultReceiver<BluetoothAvrcpPlayerSettings> recv = + new SynchronousResultReceiver(); + service.getPlayerSettings(device, mAttributionSource, recv); + settings = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return settings; + return defaultValue; } /** @@ -222,18 +242,21 @@ public final class BluetoothAvrcpController implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) { if (DBG) Log.d(TAG, "setPlayerApplicationSetting"); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.setPlayerApplicationSetting(plAppSetting, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in setPlayerApplicationSetting() " + e); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setPlayerApplicationSetting(plAppSetting, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -245,18 +268,20 @@ public final class BluetoothAvrcpController implements BluetoothProfile { public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) { Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = " + keyState); - final IBluetoothAvrcpController service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothAvrcpController service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource); - return; - } catch (RemoteException e) { - Log.e(TAG, "Error talking to BT service in sendGroupNavigationCmd()", e); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); return; + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java index f0a8df0fa72f..ba57ec472a6e 100644 --- a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java +++ b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java @@ -17,6 +17,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; @@ -27,13 +29,14 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; import android.util.CloseGuard; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -41,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.Executor; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth CSIP set coordinator. @@ -229,8 +233,7 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto IBluetoothCsipSetCoordinator.class.getName()) { @Override public IBluetoothCsipSetCoordinator getServiceInterface(IBinder service) { - return IBluetoothCsipSetCoordinator.Stub.asInterface( - Binder.allowBlocking(service)); + return IBluetoothCsipSetCoordinator.Stub.asInterface(service); } }; @@ -283,26 +286,27 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto public @Nullable UUID groupLock(int groupId, @Nullable @CallbackExecutor Executor executor, @Nullable ClientLockCallback cb) { - if (VDBG) { - log("groupLockSet()"); - } + if (VDBG) log("groupLockSet()"); final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled()) { - IBluetoothCsipSetCoordinatorLockCallback delegate = null; - if ((executor != null) && (cb != null)) { - delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb); - } - return service.groupLock(groupId, delegate, mAttributionSource).getUuid(); + final UUID defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + IBluetoothCsipSetCoordinatorLockCallback delegate = null; + if ((executor != null) && (cb != null)) { + delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb); } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + try { + final SynchronousResultReceiver<ParcelUuid> recv = new SynchronousResultReceiver(); + service.groupLock(groupId, delegate, mAttributionSource, recv); + final ParcelUuid ret = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + return ret == null ? defaultValue : ret.getUuid(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return null; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return null; } + return defaultValue; } /** @@ -315,27 +319,26 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean groupUnlock(@NonNull UUID lockUuid) { - if (VDBG) { - log("groupLockSet()"); - } + if (VDBG) log("groupLockSet()"); if (lockUuid == null) { return false; } - final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled()) { - service.groupUnlock(new ParcelUuid(lockUuid), mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.groupUnlock(new ParcelUuid(lockUuid), mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); return true; + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -348,22 +351,22 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public @NonNull Map getGroupUuidMapByDevice(@Nullable BluetoothDevice device) { - if (VDBG) { - log("getGroupUuidMapByDevice()"); - } + if (VDBG) log("getGroupUuidMapByDevice()"); final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled()) { - return service.getGroupUuidMapByDevice(device, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + final Map defaultValue = new HashMap<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Map> recv = new SynchronousResultReceiver(); + service.getGroupUuidMapByDevice(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return new HashMap<>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new HashMap<>(); } + return defaultValue; } /** @@ -376,22 +379,23 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public @NonNull List<Integer> getAllGroupIds(@Nullable ParcelUuid uuid) { - if (VDBG) { - log("getAllGroupIds()"); - } + if (VDBG) log("getAllGroupIds()"); final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled()) { - return service.getAllGroupIds(uuid, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + final List<Integer> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<Integer>> recv = + new SynchronousResultReceiver(); + service.getAllGroupIds(uuid, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return new ArrayList<Integer>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<Integer>(); } + return defaultValue; } /** @@ -399,22 +403,23 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto */ @Override public @NonNull List<BluetoothDevice> getConnectedDevices() { - if (VDBG) { - log("getConnectedDevices()"); - } + if (VDBG) log("getConnectedDevices()"); final IBluetoothCsipSetCoordinator service = getService(); - if (service != null && isEnabled()) { - try { - return service.getConnectedDevices(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); - } - } + final List<BluetoothDevice> defaultValue = new ArrayList<>(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -422,24 +427,24 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto */ @Override public - @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( - @NonNull int[] states) { - if (VDBG) { - log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")"); - } + @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[] states) { + if (VDBG) log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")"); final IBluetoothCsipSetCoordinator service = getService(); - if (service != null && isEnabled()) { - try { - return service.getDevicesMatchingConnectionStates(states, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); - } - } + final List<BluetoothDevice> defaultValue = new ArrayList<>(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -447,24 +452,23 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto */ @Override public - @BluetoothProfile.BtProfileState int getConnectionState( - @Nullable BluetoothDevice device) { - if (VDBG) { - log("getState(" + device + ")"); - } + @BluetoothProfile.BtProfileState int getConnectionState(@Nullable BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); final IBluetoothCsipSetCoordinator service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; - } - } + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -484,26 +488,24 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy( @Nullable BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { - if (DBG) { - log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - } + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -521,22 +523,22 @@ public final class BluetoothCsipSetCoordinator implements BluetoothProfile, Auto @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) { - if (VDBG) { - log("getConnectionPolicy(" + device + ")"); - } + if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothCsipSetCoordinator service = getService(); - try { - if (service != null && isEnabled() && isValidDevice(device)) { - return service.getConnectionPolicy(device, mAttributionSource); - } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 9ff4dc3bb125..93f026860856 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1177,7 +1177,7 @@ public final class BluetoothDevice implements Parcelable, Attributable { mAddress = address; mAddressType = ADDRESS_TYPE_PUBLIC; - mAttributionSource = BluetoothManager.resolveAttributionSource(null); + mAttributionSource = AttributionSource.myAttributionSource(); } /** {@hide} */ diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 4e7c01ad2db1..fe8d1ba80e33 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -1806,32 +1806,33 @@ public final class BluetoothGatt implements BluetoothProfile { } /** - * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} + * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} * with {@link BluetoothProfile#GATT} as argument - * * @throws UnsupportedOperationException */ @Override @RequiresNoPermission + @Deprecated public int getConnectionState(BluetoothDevice device) { throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead."); } /** - * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} + * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)} * with {@link BluetoothProfile#GATT} as argument * * @throws UnsupportedOperationException */ @Override @RequiresNoPermission + @Deprecated public List<BluetoothDevice> getConnectedDevices() { throw new UnsupportedOperationException( "Use BluetoothManager#getConnectedDevices instead."); } /** - * Not supported - please use + * @deprecated Not supported - please use * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])} * with {@link BluetoothProfile#GATT} as first argument * @@ -1839,6 +1840,7 @@ public final class BluetoothGatt implements BluetoothProfile { */ @Override @RequiresNoPermission + @Deprecated public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { throw new UnsupportedOperationException( "Use BluetoothManager#getDevicesMatchingConnectionStates instead."); diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 3bdfd2859bc2..1b141c9afaca 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -31,7 +33,6 @@ import android.content.AttributionSource; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; -import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -41,8 +42,11 @@ import android.os.RemoteException; import android.util.CloseGuard; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * Public API for controlling the Bluetooth Headset Service. This includes both @@ -479,16 +483,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.connect(device); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connectWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -520,16 +528,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnectWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -541,18 +553,23 @@ public final class BluetoothHeadset implements BluetoothProfile { public List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevicesWithAttribution(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevicesWithAttribution(mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -564,18 +581,23 @@ public final class BluetoothHeadset implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -587,16 +609,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getConnectionState(" + device + ")"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionStateWithAttribution(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -623,23 +649,7 @@ public final class BluetoothHeadset implements BluetoothProfile { }) public boolean setPriority(BluetoothDevice device, int priority) { if (DBG) log("setPriority(" + device + ", " + priority + ")"); - final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { - if (priority != BluetoothProfile.PRIORITY_OFF - && priority != BluetoothProfile.PRIORITY_ON) { - return false; - } - try { - return service.setPriority( - device, BluetoothAdapter.priorityToConnectionPolicy(priority), - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; - } - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); } /** @@ -665,20 +675,22 @@ public final class BluetoothHeadset implements BluetoothProfile { @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -698,18 +710,7 @@ public final class BluetoothHeadset implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getPriority(BluetoothDevice device) { if (VDBG) log("getPriority(" + device + ")"); - final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return BluetoothAdapter.connectionPolicyToPriority( - service.getPriority(device, mAttributionSource)); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.PRIORITY_OFF; - } - } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.PRIORITY_OFF; + return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); } /** @@ -732,16 +733,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } /** @@ -756,15 +761,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean isNoiseReductionSupported(@NonNull BluetoothDevice device) { if (DBG) log("isNoiseReductionSupported()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.isNoiseReductionSupported(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isNoiseReductionSupported(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -779,15 +789,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean isVoiceRecognitionSupported(@NonNull BluetoothDevice device) { if (DBG) log("isVoiceRecognitionSupported()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.isVoiceRecognitionSupported(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isVoiceRecognitionSupported(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -818,15 +833,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean startVoiceRecognition(BluetoothDevice device) { if (DBG) log("startVoiceRecognition()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.startVoiceRecognition(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.startVoiceRecognition(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -847,15 +867,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean stopVoiceRecognition(BluetoothDevice device) { if (DBG) log("stopVoiceRecognition()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.stopVoiceRecognition(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.stopVoiceRecognition(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -870,15 +895,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean isAudioConnected(BluetoothDevice device) { if (VDBG) log("isAudioConnected()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.isAudioConnected(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isAudioConnected(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -904,17 +934,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public int getAudioState(BluetoothDevice device) { if (VDBG) log("getAudioState"); final IBluetoothHeadset service = mService; - if (service != null && !isDisabled()) { + final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (!isDisabled()) { try { - return service.getAudioState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getAudioState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; + return defaultValue; } /** @@ -932,15 +965,17 @@ public final class BluetoothHeadset implements BluetoothProfile { public void setAudioRouteAllowed(boolean allowed) { if (VDBG) log("setAudioRouteAllowed"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.setAudioRouteAllowed(allowed, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setAudioRouteAllowed(allowed, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } } @@ -955,17 +990,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean getAudioRouteAllowed() { if (VDBG) log("getAudioRouteAllowed"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getAudioRouteAllowed(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getAudioRouteAllowed(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -980,15 +1018,17 @@ public final class BluetoothHeadset implements BluetoothProfile { public void setForceScoAudio(boolean forced) { if (VDBG) log("setForceScoAudio " + String.valueOf(forced)); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.setForceScoAudio(forced, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setForceScoAudio(forced, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } } @@ -1005,16 +1045,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean isAudioOn() { if (VDBG) log("isAudioOn()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.isAudioOn(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isAudioOn(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - + return defaultValue; } /** @@ -1039,18 +1083,22 @@ public final class BluetoothHeadset implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connectAudio() { + if (VDBG) log("connectAudio()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.connectAudio(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connectAudio(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1068,18 +1116,22 @@ public final class BluetoothHeadset implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnectAudio() { + if (VDBG) log("disconnectAudio()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.disconnectAudio(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnectAudio(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1113,17 +1165,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean startScoUsingVirtualVoiceCall() { if (DBG) log("startScoUsingVirtualVoiceCall()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.startScoUsingVirtualVoiceCall(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.startScoUsingVirtualVoiceCall(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1148,17 +1203,20 @@ public final class BluetoothHeadset implements BluetoothProfile { public boolean stopScoUsingVirtualVoiceCall() { if (DBG) log("stopScoUsingVirtualVoiceCall()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.stopScoUsingVirtualVoiceCall(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.stopScoUsingVirtualVoiceCall(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1178,16 +1236,16 @@ public final class BluetoothHeadset implements BluetoothProfile { public void phoneStateChanged(int numActive, int numHeld, int callState, String number, int type, String name) { final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { service.phoneStateChanged(numActive, numHeld, callState, number, type, name, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + } catch (RemoteException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } } @@ -1204,16 +1262,18 @@ public final class BluetoothHeadset implements BluetoothProfile { public void clccResponse(int index, int direction, int status, int mode, boolean mpty, String number, int type) { final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); service.clccResponse(index, direction, status, mode, mpty, number, type, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } } @@ -1245,18 +1305,21 @@ public final class BluetoothHeadset implements BluetoothProfile { throw new IllegalArgumentException("command is null"); } final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.sendVendorSpecificResultCode(device, command, arg, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - } - } + final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendVendorSpecificResultCode(device, command, arg, + mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -1290,17 +1353,20 @@ public final class BluetoothHeadset implements BluetoothProfile { Log.d(TAG, "setActiveDevice: " + device); } final IBluetoothHeadset service = mService; - if (service != null && isEnabled() && (device == null || isValidDevice(device))) { - try { - return service.setActiveDevice(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - } - } + final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && (device == null || isValidDevice(device))) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setActiveDevice(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -1316,22 +1382,25 @@ public final class BluetoothHeadset implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothDevice getActiveDevice() { - if (VDBG) { - Log.d(TAG, "getActiveDevice"); - } + if (VDBG) Log.d(TAG, "getActiveDevice"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { + final BluetoothDevice defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<BluetoothDevice> recv = + new SynchronousResultReceiver(); + service.getActiveDevice(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getActiveDevice(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return null; + return defaultValue; } /** @@ -1346,21 +1415,22 @@ public final class BluetoothHeadset implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInbandRingingEnabled() { - if (DBG) { - log("isInbandRingingEnabled()"); - } + if (DBG) log("isInbandRingingEnabled()"); final IBluetoothHeadset service = mService; - if (service != null && isEnabled()) { - try { - return service.isInbandRingingEnabled(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - } - } + final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isInbandRingingEnabled(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -1380,7 +1450,7 @@ public final class BluetoothHeadset implements BluetoothProfile { @Override public void onServiceConnected(ComponentName className, IBinder service) { if (DBG) Log.d(TAG, "Proxy object connected"); - mService = IBluetoothHeadset.Stub.asInterface(Binder.allowBlocking(service)); + mService = IBluetoothHeadset.Stub.asInterface(service); mHandler.sendMessage(mHandler.obtainMessage( MESSAGE_HEADSET_SERVICE_CONNECTED)); } diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java index 2ef37101e23d..7d7a7f798bb9 100644 --- a/core/java/android/bluetooth/BluetoothHeadsetClient.java +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -25,15 +27,17 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * Public API to control Hands Free Profile (HFP role only). @@ -432,7 +436,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { "BluetoothHeadsetClient", IBluetoothHeadsetClient.class.getName()) { @Override public IBluetoothHeadsetClient getServiceInterface(IBinder service) { - return IBluetoothHeadsetClient.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothHeadsetClient.Stub.asInterface(service); } }; @@ -479,18 +483,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -507,18 +514,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -531,19 +541,24 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothHeadsetClient service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -558,20 +573,24 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothHeadsetClient service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -585,18 +604,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { if (VDBG) log("getConnectionState(" + device + ")"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -634,22 +656,23 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { public boolean setConnectionPolicy(@NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -686,18 +709,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final @ConnectionPolicy int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } /** @@ -715,17 +741,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean startVoiceRecognition(BluetoothDevice device) { if (DBG) log("startVoiceRecognition()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.startVoiceRecognition(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.startVoiceRecognition(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -739,20 +769,23 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { */ @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) - public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, - String atCommand) { + public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) { if (DBG) log("sendVendorSpecificCommand()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.sendVendorAtCommand(device, vendorId, atCommand, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendVendorAtCommand(device, vendorId, atCommand, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -770,17 +803,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean stopVoiceRecognition(BluetoothDevice device) { if (DBG) log("stopVoiceRecognition()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.stopVoiceRecognition(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.stopVoiceRecognition(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -793,18 +830,24 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { if (DBG) log("getCurrentCalls()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final List<BluetoothHeadsetClientCall> defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { + final SynchronousResultReceiver<List<BluetoothHeadsetClientCall>> recv = + new SynchronousResultReceiver(); + service.getCurrentCalls(device, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getCurrentCalls(device, mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; + return defaultValue; } /** @@ -817,17 +860,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Bundle getCurrentAgEvents(BluetoothDevice device) { if (DBG) log("getCurrentAgEvents()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final Bundle defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getCurrentAgEvents(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Bundle> recv = new SynchronousResultReceiver(); + service.getCurrentAgEvents(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; + return defaultValue; } /** @@ -844,17 +891,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean acceptCall(BluetoothDevice device, int flag) { if (DBG) log("acceptCall()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.acceptCall(device, flag, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.acceptCall(device, flag, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -868,17 +919,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean holdCall(BluetoothDevice device) { if (DBG) log("holdCall()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.holdCall(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.holdCall(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -897,17 +952,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean rejectCall(BluetoothDevice device) { if (DBG) log("rejectCall()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.rejectCall(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.rejectCall(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -930,17 +989,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { if (DBG) log("terminateCall()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.terminateCall(device, call, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.terminateCall(device, call, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -961,17 +1024,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enterPrivateMode(BluetoothDevice device, int index) { if (DBG) log("enterPrivateMode()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.enterPrivateMode(device, index, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.enterPrivateMode(device, index, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -991,17 +1058,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean explicitCallTransfer(BluetoothDevice device) { if (DBG) log("explicitCallTransfer()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.explicitCallTransfer(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.explicitCallTransfer(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -1017,18 +1088,24 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { if (DBG) log("dial()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final BluetoothHeadsetClientCall defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { + final SynchronousResultReceiver<BluetoothHeadsetClientCall> recv = + new SynchronousResultReceiver(); + service.dial(device, number, mAttributionSource, recv); return Attributable.setAttributionSource( - service.dial(device, number, mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return null; + return defaultValue; } /** @@ -1045,17 +1122,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendDTMF(BluetoothDevice device, byte code) { if (DBG) log("sendDTMF()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.sendDTMF(device, code, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendDTMF(device, code, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -1074,17 +1155,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean getLastVoiceTagNumber(BluetoothDevice device) { if (DBG) log("getLastVoiceTagNumber()"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getLastVoiceTagNumber(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getLastVoiceTagNumber(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -1097,17 +1182,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getAudioState(BluetoothDevice device) { if (VDBG) log("getAudioState"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothHeadsetClient service = getService(); + final int defaultValue = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getAudioState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getAudioState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + return defaultValue; } return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; } @@ -1123,17 +1212,18 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { if (VDBG) log("setAudioRouteAllowed"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothHeadsetClient service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.setAudioRouteAllowed(device, allowed, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setAudioRouteAllowed(device, allowed, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } } @@ -1148,19 +1238,21 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean getAudioRouteAllowed(BluetoothDevice device) { if (VDBG) log("getAudioRouteAllowed"); - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getAudioRouteAllowed(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getAudioRouteAllowed(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1175,19 +1267,22 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connectAudio(BluetoothDevice device) { - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + if (VDBG) log("connectAudio"); + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.connectAudio(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connectAudio(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1202,19 +1297,22 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnectAudio(BluetoothDevice device) { - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + if (VDBG) log("disconnectAudio"); + final IBluetoothHeadsetClient service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.disconnectAudio(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnectAudio(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return false; + return defaultValue; } /** @@ -1226,19 +1324,22 @@ public final class BluetoothHeadsetClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Bundle getCurrentAgFeatures(BluetoothDevice device) { - final IBluetoothHeadsetClient service = - getService(); - if (service != null && isEnabled()) { + if (VDBG) log("getCurrentAgFeatures"); + final IBluetoothHeadsetClient service = getService(); + final Bundle defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getCurrentAgFeatures(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Bundle> recv = new SynchronousResultReceiver(); + service.getCurrentAgFeatures(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); } - return null; + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java index a00b20d99f96..339a75fe0fbe 100644 --- a/core/java/android/bluetooth/BluetoothHearingAid.java +++ b/core/java/android/bluetooth/BluetoothHearingAid.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -28,14 +30,16 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Hearing Aid profile. @@ -136,7 +140,7 @@ public final class BluetoothHearingAid implements BluetoothProfile { "BluetoothHearingAid", IBluetoothHearingAid.class.getName()) { @Override public IBluetoothHearingAid getServiceInterface(IBinder service) { - return IBluetoothHearingAid.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothHearingAid.Stub.asInterface(service); } }; @@ -181,16 +185,20 @@ public final class BluetoothHearingAid implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() && isValidDevice(device)) { - return service.connect(device, mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -223,16 +231,20 @@ public final class BluetoothHearingAid implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() && isValidDevice(device)) { - return service.disconnect(device, mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -244,17 +256,23 @@ public final class BluetoothHearingAid implements BluetoothProfile { public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -267,18 +285,23 @@ public final class BluetoothHearingAid implements BluetoothProfile { @NonNull int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -291,17 +314,20 @@ public final class BluetoothHearingAid implements BluetoothProfile { @NonNull BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getConnectionState(device, mAttributionSource); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; } + return defaultValue; } /** @@ -330,18 +356,20 @@ public final class BluetoothHearingAid implements BluetoothProfile { public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && ((device == null) || isValidDevice(device))) { - service.setActiveDevice(device, mAttributionSource); - return true; + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && ((device == null) || isValidDevice(device))) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setActiveDevice(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -359,17 +387,23 @@ public final class BluetoothHearingAid implements BluetoothProfile { public @NonNull List<BluetoothDevice> getActiveDevices() { if (VDBG) log("getActiveDevices()"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getActiveDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getActiveDevices(mAttributionSource), mAttributionSource); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<>(); } + return defaultValue; } /** @@ -416,21 +450,22 @@ public final class BluetoothHearingAid implements BluetoothProfile { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); verifyDeviceNotNull(device, "setConnectionPolicy"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -474,17 +509,20 @@ public final class BluetoothHearingAid implements BluetoothProfile { if (VDBG) log("getConnectionPolicy(" + device + ")"); verifyDeviceNotNull(device, "getConnectionPolicy"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getConnectionPolicy(device, mAttributionSource); + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } + return defaultValue; } /** @@ -519,19 +557,18 @@ public final class BluetoothHearingAid implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setVolume(int volume) { if (DBG) Log.d(TAG, "setVolume(" + volume + ")"); - final IBluetoothHearingAid service = getService(); - try { - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - return; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setVolume(volume, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - - if (!isEnabled()) return; - - service.setVolume(volume, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); } } @@ -552,24 +589,23 @@ public final class BluetoothHearingAid implements BluetoothProfile { android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) public long getHiSyncId(@NonNull BluetoothDevice device) { - if (VDBG) { - log("getHiSyncId(" + device + ")"); - } + if (VDBG) log("getHiSyncId(" + device + ")"); verifyDeviceNotNull(device, "getConnectionPolicy"); final IBluetoothHearingAid service = getService(); - try { - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - return HI_SYNC_ID_INVALID; + final long defaultValue = HI_SYNC_ID_INVALID; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Long> recv = new SynchronousResultReceiver(); + service.getHiSyncId(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - - if (!isEnabled() || !isValidDevice(device)) return HI_SYNC_ID_INVALID; - - return service.getHiSyncId(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return HI_SYNC_ID_INVALID; } + return defaultValue; } /** @@ -583,21 +619,22 @@ public final class BluetoothHearingAid implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getDeviceSide(BluetoothDevice device) { - if (VDBG) { - log("getDeviceSide(" + device + ")"); - } + if (VDBG) log("getDeviceSide(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getDeviceSide(device, mAttributionSource); + final int defaultValue = SIDE_LEFT; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getDeviceSide(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return SIDE_LEFT; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return SIDE_LEFT; } + return defaultValue; } /** @@ -611,21 +648,22 @@ public final class BluetoothHearingAid implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getDeviceMode(BluetoothDevice device) { - if (VDBG) { - log("getDeviceMode(" + device + ")"); - } + if (VDBG) log("getDeviceMode(" + device + ")"); final IBluetoothHearingAid service = getService(); - try { - if (service != null && isEnabled() - && isValidDevice(device)) { - return service.getDeviceMode(device, mAttributionSource); + final int defaultValue = MODE_MONAURAL; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getDeviceMode(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return MODE_MONAURAL; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return MODE_MONAURAL; } + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index f5b444fd17cb..44a355b5f75c 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -26,14 +28,16 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.TimeoutException; /** * Provides the public APIs to control the Bluetooth HID Device profile. @@ -431,7 +435,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { "BluetoothHidDevice", IBluetoothHidDevice.class.getName()) { @Override public IBluetoothHidDevice getServiceInterface(IBinder service) { - return IBluetoothHidDevice.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothHidDevice.Stub.asInterface(service); } }; @@ -455,18 +459,23 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getConnectedDevices() { final IBluetoothHidDevice service = getService(); - if (service != null) { + final List<BluetoothDevice> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return new ArrayList<>(); + return defaultValue; } /** {@inheritDoc} */ @@ -475,19 +484,23 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { final IBluetoothHidDevice service = getService(); - if (service != null) { + final List<BluetoothDevice> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return new ArrayList<>(); + return defaultValue; } /** {@inheritDoc} */ @@ -496,17 +509,20 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(BluetoothDevice device) { final IBluetoothHidDevice service = getService(); - if (service != null) { + final int defaultValue = STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return STATE_DISCONNECTED; + return defaultValue; } /** @@ -555,18 +571,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { } final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = result; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); CallbackWrapper cbw = new CallbackWrapper(executor, callback, mAttributionSource); - result = service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource, recv); + result = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -582,20 +601,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterApp() { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - result = service.unregisterApp(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.unregisterApp(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -609,20 +629,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendReport(BluetoothDevice device, int id, byte[] data) { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - result = service.sendReport(device, id, data, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendReport(device, id, data, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -637,20 +658,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - result = service.replyReport(device, type, id, data, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.replyReport(device, type, id, data, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -663,20 +685,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean reportError(BluetoothDevice device, byte error) { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - result = service.reportError(device, error, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.reportError(device, error, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -689,18 +712,20 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getUserAppName() { final IBluetoothHidDevice service = getService(); - - if (service != null) { + final String defaultValue = ""; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.getUserAppName(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<String> recv = new SynchronousResultReceiver(); + service.getUserAppName(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return ""; + return defaultValue; } /** @@ -714,20 +739,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(BluetoothDevice device) { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - result = service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -740,20 +766,21 @@ public final class BluetoothHidDevice implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(BluetoothDevice device) { - boolean result = false; - final IBluetoothHidDevice service = getService(); - if (service != null) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - result = service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); } - - return result; + return defaultValue; } /** @@ -781,23 +808,24 @@ public final class BluetoothHidDevice implements BluetoothProfile { }) public boolean setConnectionPolicy(@NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { - log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - try { - final IBluetoothHidDevice service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); + final IBluetoothHidDevice service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java index 121aa1611522..ecbeddf2b853 100644 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ b/core/java/android/bluetooth/BluetoothHidHost.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -28,13 +30,15 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** @@ -244,7 +248,7 @@ public final class BluetoothHidHost implements BluetoothProfile { "BluetoothHidHost", IBluetoothHidHost.class.getName()) { @Override public IBluetoothHidHost getServiceInterface(IBinder service) { - return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothHidHost.Stub.asInterface(service); } }; @@ -292,16 +296,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -334,16 +342,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -358,17 +370,23 @@ public final class BluetoothHidHost implements BluetoothProfile { public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -382,18 +400,23 @@ public final class BluetoothHidHost implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -411,16 +434,20 @@ public final class BluetoothHidHost implements BluetoothProfile { throw new IllegalArgumentException("device must not be null"); } final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -469,20 +496,22 @@ public final class BluetoothHidHost implements BluetoothProfile { throw new IllegalArgumentException("device must not be null"); } final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -528,16 +557,20 @@ public final class BluetoothHidHost implements BluetoothProfile { throw new IllegalArgumentException("device must not be null"); } final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } private boolean isEnabled() { @@ -561,18 +594,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean virtualUnplug(BluetoothDevice device) { if (DBG) log("virtualUnplug(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.virtualUnplug(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.virtualUnplug(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - + return defaultValue; } /** @@ -588,16 +623,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean getProtocolMode(BluetoothDevice device) { if (VDBG) log("getProtocolMode(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getProtocolMode(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getProtocolMode(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -613,16 +652,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { if (DBG) log("setProtocolMode(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.setProtocolMode(device, protocolMode, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setProtocolMode(device, protocolMode, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -645,17 +688,21 @@ public final class BluetoothHidHost implements BluetoothProfile { + "bufferSize=" + bufferSize); } final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getReport(device, reportType, reportId, bufferSize, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getReport(device, reportType, reportId, bufferSize, mAttributionSource, + recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -673,16 +720,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean setReport(BluetoothDevice device, byte reportType, String report) { if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.setReport(device, reportType, report, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setReport(device, reportType, report, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -699,16 +750,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean sendData(BluetoothDevice device, String report) { if (DBG) log("sendData(" + device + "), report=" + report); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.sendData(device, report, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendData(device, report, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -724,16 +779,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean getIdleTime(BluetoothDevice device) { if (DBG) log("getIdletime(" + device + ")"); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getIdleTime(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getIdleTime(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -750,16 +809,20 @@ public final class BluetoothHidHost implements BluetoothProfile { public boolean setIdleTime(BluetoothDevice device, byte idleTime) { if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime); final IBluetoothHidHost service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.setIdleTime(device, idleTime, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setIdleTime(device, idleTime, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } private static void log(String msg) { diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java index 34398eba5d28..15db686b3be4 100644 --- a/core/java/android/bluetooth/BluetoothLeAudio.java +++ b/core/java/android/bluetooth/BluetoothLeAudio.java @@ -17,6 +17,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -27,14 +29,16 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.CloseGuard; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the LeAudio profile. @@ -331,7 +335,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { IBluetoothLeAudio.class.getName()) { @Override public IBluetoothLeAudio getServiceInterface(IBinder service) { - return IBluetoothLeAudio.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothLeAudio.Stub.asInterface(service); } }; @@ -385,17 +389,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(@Nullable BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() && isValidDevice(device)) { - return service.connect(device, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -425,17 +433,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(@Nullable BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() && isValidDevice(device)) { - return service.disconnect(device, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -446,18 +458,24 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled()) { + final IBluetoothLeAudio service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -469,19 +487,24 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates( @NonNull int[] states) { if (VDBG) log("getDevicesMatchingStates()"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled()) { + final IBluetoothLeAudio service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); } + return defaultValue; } /** @@ -493,18 +516,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() - && isValidDevice(device)) { - return service.getConnectionState(device, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; } + return defaultValue; } /** @@ -531,19 +557,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setActiveDevice(@Nullable BluetoothDevice device) { if (DBG) log("setActiveDevice(" + device + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() - && ((device == null) || isValidDevice(device))) { - service.setActiveDevice(device, mAttributionSource); - return true; + final IBluetoothLeAudio service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && ((device == null) || isValidDevice(device))) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setActiveDevice(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -557,19 +585,25 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getActiveDevices() { - if (VDBG) log("getActiveDevices()"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled()) { + if (VDBG) log("getActiveDevice()"); + final IBluetoothLeAudio service = getService(); + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getActiveDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getActiveDevices(mAttributionSource), mAttributionSource); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<>(); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<>(); } + return defaultValue; } /** @@ -583,17 +617,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getGroupId(@NonNull BluetoothDevice device) { if (VDBG) log("getGroupId()"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled()) { - return service.getGroupId(device, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final int defaultValue = GROUP_ID_INVALID; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getGroupId(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return GROUP_ID_INVALID; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return GROUP_ID_INVALID; } + return defaultValue; } /** @@ -606,17 +644,18 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setVolume(int volume) { if (VDBG) log("setVolume(vol: " + volume + " )"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled()) { - service.setVolume(volume, mAttributionSource); - return; + final IBluetoothLeAudio service = getService(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setVolume(volume, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return; } } @@ -635,16 +674,20 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { public boolean groupAddNode(int group_id, @NonNull BluetoothDevice device) { if (VDBG) log("groupAddNode()"); final IBluetoothLeAudio service = getService(); - try { - if (service != null && mAdapter.isEnabled()) { - return service.groupAddNode(group_id, device, mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.groupAddNode(group_id, device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -663,16 +706,20 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { public boolean groupRemoveNode(int group_id, @NonNull BluetoothDevice device) { if (VDBG) log("groupRemoveNode()"); final IBluetoothLeAudio service = getService(); - try { - if (service != null && mAdapter.isEnabled()) { - return service.groupRemoveNode(group_id, device, mAttributionSource); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.groupRemoveNode(group_id, device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -695,22 +742,23 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { public boolean setConnectionPolicy(@NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -728,18 +776,21 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); - try { - final IBluetoothLeAudio service = getService(); - if (service != null && mAdapter.isEnabled() - && isValidDevice(device)) { - return service.getConnectionPolicy(device, mAttributionSource); + final IBluetoothLeAudio service = getService(); + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (mAdapter.isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; } + return defaultValue; } diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index c93de41b5b36..fef6f225dd3b 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -16,14 +16,10 @@ package android.bluetooth; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SystemService; -import android.app.ActivityThread; -import android.app.AppGlobals; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.content.AttributionSource; @@ -68,37 +64,11 @@ public final class BluetoothManager { * @hide */ public BluetoothManager(Context context) { - mAttributionSource = resolveAttributionSource(context); + mAttributionSource = (context != null) ? context.getAttributionSource() : + AttributionSource.myAttributionSource(); mAdapter = BluetoothAdapter.createAdapter(mAttributionSource); } - /** {@hide} */ - public static @NonNull AttributionSource resolveAttributionSource(@Nullable Context context) { - AttributionSource res = null; - if (context != null) { - res = context.getAttributionSource(); - } - if (res == null) { - res = ActivityThread.currentAttributionSource(); - } - if (res == null) { - int uid = android.os.Process.myUid(); - if (uid == android.os.Process.ROOT_UID) { - uid = android.os.Process.SYSTEM_UID; - } - try { - res = new AttributionSource.Builder(uid) - .setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0]) - .build(); - } catch (RemoteException ignored) { - } - } - if (res == null) { - throw new IllegalStateException("Failed to resolve AttributionSource"); - } - return res; - } - /** * Get the BLUETOOTH Adapter for this device. * diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java index 474e41f4aa19..56e497262421 100644 --- a/core/java/android/bluetooth/BluetoothMap.java +++ b/core/java/android/bluetooth/BluetoothMap.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresNoPermission; @@ -28,15 +30,17 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.CloseGuard; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the APIs to control the Bluetooth MAP @@ -87,7 +91,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { "BluetoothMap", IBluetoothMap.class.getName()) { @Override public IBluetoothMap getServiceInterface(IBinder service) { - return IBluetoothMap.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothMap.Stub.asInterface(service); } }; @@ -142,17 +146,20 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public int getState() { if (VDBG) log("getState()"); final IBluetoothMap service = getService(); - if (service != null) { - try { - return service.getState(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final int defaultValue = BluetoothMap.STATE_ERROR; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getState(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return BluetoothMap.STATE_ERROR; + return defaultValue; } /** @@ -168,18 +175,23 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public BluetoothDevice getClient() { if (VDBG) log("getClient()"); final IBluetoothMap service = getService(); - if (service != null) { + final BluetoothDevice defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<BluetoothDevice> recv = + new SynchronousResultReceiver(); + service.getClient(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getClient(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); } - return null; + return defaultValue; } /** @@ -194,17 +206,20 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public boolean isConnected(BluetoothDevice device) { if (VDBG) log("isConnected(" + device + ")"); final IBluetoothMap service = getService(); - if (service != null) { - try { - return service.isConnected(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final boolean defaultValue = false; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isConnected(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -233,16 +248,20 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothMap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -284,17 +303,23 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public @NonNull List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothMap service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -309,18 +334,23 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); final IBluetoothMap service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -335,16 +365,21 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public int getConnectionState(BluetoothDevice device) { if (DBG) log("getConnectionState(" + device + ")"); final IBluetoothMap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = + new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -390,20 +425,22 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -446,16 +483,20 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable { public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothMap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } private static void log(String msg) { diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java index 8a3f80164aeb..03536f9aad39 100644 --- a/core/java/android/bluetooth/BluetoothMapClient.java +++ b/core/java/android/bluetooth/BluetoothMapClient.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -29,15 +31,17 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; import android.net.Uri; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the APIs to control the Bluetooth MAP MCE Profile. @@ -180,7 +184,7 @@ public final class BluetoothMapClient implements BluetoothProfile { "BluetoothMapClient", IBluetoothMapClient.class.getName()) { @Override public IBluetoothMapClient getServiceInterface(IBinder service) { - return IBluetoothMapClient.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothMapClient.Stub.asInterface(service); } }; @@ -221,17 +225,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean isConnected(BluetoothDevice device) { if (VDBG) Log.d(TAG, "isConnected(" + device + ")"); final IBluetoothMapClient service = getService(); - if (service != null) { - try { - return service.isConnected(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final boolean defaultValue = false; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isConnected(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -248,17 +255,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE"); final IBluetoothMapClient service = getService(); - if (service != null) { - try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final boolean defaultValue = false; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -277,15 +287,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) Log.d(TAG, "disconnect(" + device + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -300,17 +315,23 @@ public final class BluetoothMapClient implements BluetoothProfile { public List<BluetoothDevice> getConnectedDevices() { if (DBG) Log.d(TAG, "getConnectedDevices()"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<>(); + return defaultValue; } /** @@ -325,18 +346,23 @@ public final class BluetoothMapClient implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) Log.d(TAG, "getDevicesMatchingStates()"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<>(); + return defaultValue; } /** @@ -351,16 +377,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public int getConnectionState(BluetoothDevice device) { if (DBG) Log.d(TAG, "getConnectionState(" + device + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver<>(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -405,20 +435,22 @@ public final class BluetoothMapClient implements BluetoothProfile { @ConnectionPolicy int connectionPolicy) { if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -460,16 +492,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } /** @@ -494,18 +530,8 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts, @NonNull String message, @Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveredIntent) { - if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message); - final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.sendMessage(device, contacts.toArray(new Uri[contacts.size()]), - message, sentIntent, deliveredIntent, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; - } - } - return false; + return sendMessage(device, contacts.toArray(new Uri[contacts.size()]), message, sentIntent, + deliveredIntent); } /** @@ -531,16 +557,21 @@ public final class BluetoothMapClient implements BluetoothProfile { PendingIntent sentIntent, PendingIntent deliveredIntent) { if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.sendMessage(device, contacts, message, sentIntent, deliveredIntent, - mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.sendMessage(device, contacts, message, sentIntent, deliveredIntent, + mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return false; + return defaultValue; } /** @@ -558,15 +589,20 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean getUnreadMessages(BluetoothDevice device) { if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getUnreadMessages(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.getUnreadMessages(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return false; + return defaultValue; } /** @@ -580,13 +616,21 @@ public final class BluetoothMapClient implements BluetoothProfile { @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isUploadingSupported(BluetoothDevice device) { + if (DBG) Log.d(TAG, "isUploadingSupported(" + device + ")"); final IBluetoothMapClient service = getService(); - try { - return (service != null && isEnabled() && isValidDevice(device)) - && ((service.getSupportedFeatures(device, mAttributionSource) - & UPLOADING_FEATURE_BITMASK) > 0); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); + final int defaultValue = 0; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getSupportedFeatures(device, mAttributionSource, recv); + return (recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue) + & UPLOADING_FEATURE_BITMASK) > 0; + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } return false; } @@ -615,16 +659,21 @@ public final class BluetoothMapClient implements BluetoothProfile { public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")"); final IBluetoothMapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device) && handle != null && - (status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) && handle != null && (status == READ + || status == UNREAD || status == UNDELETED || status == DELETED)) { try { - return service.setMessageStatus(device, handle, status, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setMessageStatus(device, handle, status, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return false; + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index ac7a52d8f636..d4ad4ef47acd 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -28,16 +30,18 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the APIs to control the Bluetooth Pan @@ -188,7 +192,7 @@ public final class BluetoothPan implements BluetoothProfile { "BluetoothPan", IBluetoothPan.class.getName()) { @Override public IBluetoothPan getServiceInterface(IBinder service) { - return IBluetoothPan.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothPan.Stub.asInterface(service); } }; @@ -249,16 +253,20 @@ public final class BluetoothPan implements BluetoothProfile { public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); final IBluetoothPan service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -289,16 +297,20 @@ public final class BluetoothPan implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothPan service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -322,22 +334,23 @@ public final class BluetoothPan implements BluetoothProfile { public boolean setConnectionPolicy(@NonNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); - try { - final IBluetoothPan service = getService(); - if (service != null && isEnabled() - && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); + final IBluetoothPan service = getService(); + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return false; } + return defaultValue; } /** @@ -354,17 +367,23 @@ public final class BluetoothPan implements BluetoothProfile { public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothPan service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -381,18 +400,23 @@ public final class BluetoothPan implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (VDBG) log("getDevicesMatchingStates()"); final IBluetoothPan service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -409,16 +433,20 @@ public final class BluetoothPan implements BluetoothProfile { public int getConnectionState(@NonNull BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothPan service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -438,11 +466,16 @@ public final class BluetoothPan implements BluetoothProfile { String pkgName = mContext.getOpPackageName(); if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); final IBluetoothPan service = getService(); - if (service != null && isEnabled()) { + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - service.setBluetoothTethering(value, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setBluetoothTethering(value, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } } @@ -459,14 +492,20 @@ public final class BluetoothPan implements BluetoothProfile { public boolean isTetheringOn() { if (VDBG) log("isTetheringOn()"); final IBluetoothPan service = getService(); - if (service != null && isEnabled()) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { - return service.isTetheringOn(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isTetheringOn(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - return false; + return defaultValue; } @UnsupportedAppUsage diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index e13792918103..de2db9c2ca86 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -25,15 +25,10 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; import java.util.ArrayList; @@ -96,10 +91,6 @@ public class BluetoothPbap implements BluetoothProfile { public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED"; - private volatile IBluetoothPbap mService; - private final Context mContext; - private ServiceListener mServiceListener; - private final BluetoothAdapter mAdapter; private final AttributionSource mAttributionSource; /** @hide */ @@ -113,87 +104,25 @@ public class BluetoothPbap implements BluetoothProfile { */ public static final int RESULT_CANCELED = 2; - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = - new IBluetoothStateChangeCallback.Stub() { - public void onBluetoothStateChange(boolean up) { - log("onBluetoothStateChange: up=" + up); - if (!up) { - doUnbind(); - } else { - doBind(); - } + private BluetoothAdapter mAdapter; + private final BluetoothProfileConnector<IBluetoothPbap> mProfileConnector = + new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap", + IBluetoothPbap.class.getName()) { + @Override + public IBluetoothPbap getServiceInterface(IBinder service) { + return IBluetoothPbap.Stub.asInterface(service); } - }; + }; /** * Create a BluetoothPbap proxy object. * * @hide */ - public BluetoothPbap(Context context, ServiceListener l, BluetoothAdapter adapter) { - mContext = context; - mServiceListener = l; + public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) { mAdapter = adapter; mAttributionSource = adapter.getAttributionSource(); - - // Preserve legacy compatibility where apps were depending on - // registerStateChangeCallback() performing a permissions check which - // has been relaxed in modern platform versions - if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R - && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Need BLUETOOTH permission"); - } - - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - Log.e(TAG, "", re); - } - } - doBind(); - } - - @SuppressLint("AndroidFrameworkRequiresPermission") - boolean doBind() { - synchronized (mConnection) { - try { - if (mService == null) { - log("Binding service..."); - Intent intent = new Intent(IBluetoothPbap.class.getName()); - ComponentName comp = intent.resolveSystemService( - mContext.getPackageManager(), 0); - intent.setComponent(comp); - if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, - UserHandle.CURRENT)) { - Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent); - return false; - } - } - } catch (SecurityException se) { - Log.e(TAG, "", se); - return false; - } - } - return true; - } - - private void doUnbind() { - synchronized (mConnection) { - if (mService != null) { - log("Unbinding service..."); - try { - mContext.unbindService(mConnection); - } catch (IllegalArgumentException ie) { - Log.e(TAG, "", ie); - } finally { - mService = null; - } - } - } + mProfileConnector.connect(context, listener); } /** @hide */ @@ -214,16 +143,11 @@ public class BluetoothPbap implements BluetoothProfile { * @hide */ public synchronized void close() { - IBluetoothManager mgr = mAdapter.getBluetoothManager(); - if (mgr != null) { - try { - mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); - } catch (RemoteException re) { - Log.e(TAG, "", re); - } - } - doUnbind(); - mServiceListener = null; + mProfileConnector.disconnect(); + } + + private IBluetoothPbap getService() { + return (IBluetoothPbap) mProfileConnector.getService(); } /** @@ -236,7 +160,7 @@ public class BluetoothPbap implements BluetoothProfile { @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getConnectedDevices() { log("getConnectedDevices()"); - final IBluetoothPbap service = mService; + final IBluetoothPbap service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); return new ArrayList<BluetoothDevice>(); @@ -265,7 +189,7 @@ public class BluetoothPbap implements BluetoothProfile { public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) { log("getConnectionState: device=" + device); try { - final IBluetoothPbap service = mService; + final IBluetoothPbap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { return service.getConnectionState(device, mAttributionSource); } @@ -289,7 +213,7 @@ public class BluetoothPbap implements BluetoothProfile { @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states)); - final IBluetoothPbap service = mService; + final IBluetoothPbap service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); return new ArrayList<BluetoothDevice>(); @@ -330,7 +254,7 @@ public class BluetoothPbap implements BluetoothProfile { @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); try { - final IBluetoothPbap service = mService; + final IBluetoothPbap service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN @@ -359,7 +283,7 @@ public class BluetoothPbap implements BluetoothProfile { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(BluetoothDevice device) { log("disconnect()"); - final IBluetoothPbap service = mService; + final IBluetoothPbap service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); return false; @@ -373,25 +297,6 @@ public class BluetoothPbap implements BluetoothProfile { return false; } - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - log("Proxy object connected"); - mService = IBluetoothPbap.Stub.asInterface(service); - if (mServiceListener != null) { - mServiceListener.onServiceConnected(BluetoothProfile.PBAP, BluetoothPbap.this); - } - } - - public void onServiceDisconnected(ComponentName className) { - log("Proxy object disconnected"); - doUnbind(); - if (mServiceListener != null) { - mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP); - } - } - }; - private boolean isEnabled() { if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; return false; diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java index cc91ad258d03..e096de8cb829 100644 --- a/core/java/android/bluetooth/BluetoothPbapClient.java +++ b/core/java/android/bluetooth/BluetoothPbapClient.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -24,13 +26,15 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the APIs to control the Bluetooth PBAP Client Profile. @@ -64,7 +68,7 @@ public final class BluetoothPbapClient implements BluetoothProfile { "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) { @Override public IBluetoothPbapClient getServiceInterface(IBinder service) { - return IBluetoothPbapClient.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothPbapClient.Stub.asInterface(service); } }; @@ -123,18 +127,20 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("connect(" + device + ") for PBAP Client."); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.connect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; - } - } + final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.connect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -155,19 +161,21 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("disconnect(" + device + ")" + new Exception()); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = true; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - service.disconnect(device, mAttributionSource); + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); return true; - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return false; + return defaultValue; } /** @@ -184,19 +192,23 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("getConnectedDevices()"); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -212,20 +224,23 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("getDevicesMatchingStates()"); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) { - Log.w(TAG, "Proxy not attached to service"); - } - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -241,18 +256,20 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("getConnectionState(" + device + ")"); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; - } - } + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } private static void log(String msg) { @@ -311,22 +328,22 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } - try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; - } - } + final boolean defaultValue = false; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -370,17 +387,19 @@ public final class BluetoothPbapClient implements BluetoothProfile { log("getConnectionPolicy(" + device + ")"); } final IBluetoothPbapClient service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; - } - } + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; if (service == null) { Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } } diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java index ecd5e4077de9..79373f1a32ec 100644 --- a/core/java/android/bluetooth/BluetoothProfileConnector.java +++ b/core/java/android/bluetooth/BluetoothProfileConnector.java @@ -16,12 +16,16 @@ package android.bluetooth; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; @@ -29,6 +33,7 @@ import android.os.UserHandle; import android.util.CloseGuard; import android.util.Log; +import java.util.List; /** * Connector for Bluetooth profile proxies to bind manager service and * profile services @@ -57,6 +62,29 @@ public abstract class BluetoothProfileConnector<T> { } }; + private @Nullable ComponentName resolveSystemService(@NonNull Intent intent, + @NonNull PackageManager pm, @PackageManager.ComponentInfoFlags int flags) { + List<ResolveInfo> results = pm.queryIntentServices(intent, flags); + if (results == null) { + return null; + } + ComponentName comp = null; + for (int i = 0; i < results.size(); i++) { + ResolveInfo ri = results.get(i); + if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + continue; + } + ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName, + ri.serviceInfo.name); + if (comp != null) { + throw new IllegalStateException("Multiple system services handle " + intent + + ": " + comp + ", " + foundComp); + } + comp = foundComp; + } + return comp; + } + private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { logDebug("Proxy object connected"); @@ -99,8 +127,8 @@ public abstract class BluetoothProfileConnector<T> { mCloseGuard.open("doUnbind"); try { Intent intent = new Intent(mServiceName); - ComponentName comp = intent.resolveSystemService( - mContext.getPackageManager(), 0); + ComponentName comp = resolveSystemService(intent, mContext.getPackageManager(), + 0); intent.setComponent(comp); if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, UserHandle.CURRENT)) { diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java index ab2b8eaaa36e..808fa3913316 100644 --- a/core/java/android/bluetooth/BluetoothSap.java +++ b/core/java/android/bluetooth/BluetoothSap.java @@ -16,6 +16,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; @@ -26,14 +28,16 @@ import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the APIs to control the Bluetooth SIM @@ -104,7 +108,7 @@ public final class BluetoothSap implements BluetoothProfile { "BluetoothSap", IBluetoothSap.class.getName()) { @Override public IBluetoothSap getServiceInterface(IBinder service) { - return IBluetoothSap.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothSap.Stub.asInterface(service); } }; @@ -155,17 +159,20 @@ public final class BluetoothSap implements BluetoothProfile { public int getState() { if (VDBG) log("getState()"); final IBluetoothSap service = getService(); - if (service != null) { - try { - return service.getState(mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final int defaultValue = BluetoothSap.STATE_ERROR; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getState(mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return BluetoothSap.STATE_ERROR; + return defaultValue; } /** @@ -180,18 +187,23 @@ public final class BluetoothSap implements BluetoothProfile { public BluetoothDevice getClient() { if (VDBG) log("getClient()"); final IBluetoothSap service = getService(); - if (service != null) { + final BluetoothDevice defaultValue = null; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<BluetoothDevice> recv = + new SynchronousResultReceiver(); + service.getClient(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getClient(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - } else { - Log.w(TAG, "Proxy not attached to service"); - if (DBG) log(Log.getStackTraceString(new Throwable())); } - return null; + return defaultValue; } /** @@ -206,17 +218,20 @@ public final class BluetoothSap implements BluetoothProfile { public boolean isConnected(BluetoothDevice device) { if (VDBG) log("isConnected(" + device + ")"); final IBluetoothSap service = getService(); - if (service != null) { - try { - return service.isConnected(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - } else { + final boolean defaultValue = false; + if (service == null) { Log.w(TAG, "Proxy not attached to service"); if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.isConnected(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); + } } - return false; + return defaultValue; } /** @@ -244,16 +259,20 @@ public final class BluetoothSap implements BluetoothProfile { public boolean disconnect(BluetoothDevice device) { if (DBG) log("disconnect(" + device + ")"); final IBluetoothSap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.disconnect(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.disconnect(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -267,17 +286,23 @@ public final class BluetoothSap implements BluetoothProfile { public List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothSap service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -291,18 +316,23 @@ public final class BluetoothSap implements BluetoothProfile { public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); final IBluetoothSap service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -316,16 +346,20 @@ public final class BluetoothSap implements BluetoothProfile { public int getConnectionState(BluetoothDevice device) { if (DBG) log("getConnectionState(" + device + ")"); final IBluetoothSap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -370,20 +404,22 @@ public final class BluetoothSap implements BluetoothProfile { @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothSap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -425,16 +461,20 @@ public final class BluetoothSap implements BluetoothProfile { public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothSap service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } private static void log(String msg) { diff --git a/core/java/android/bluetooth/BluetoothUtils.java b/core/java/android/bluetooth/BluetoothUtils.java new file mode 100644 index 000000000000..867469241f84 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothUtils.java @@ -0,0 +1,41 @@ +/* + * 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.bluetooth; + +import java.time.Duration; + +/** + * {@hide} + */ +public final class BluetoothUtils { + /** + * This utility class cannot be instantiated + */ + private BluetoothUtils() {} + + /** + * Timeout value for synchronous binder call + */ + private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(5); + + /** + * @return timeout value for synchronous binder call + */ + static Duration getSyncTimeout() { + return SYNC_CALLS_TIMEOUT; + } +} diff --git a/core/java/android/bluetooth/BluetoothVolumeControl.java b/core/java/android/bluetooth/BluetoothVolumeControl.java index ba83eca423f4..27532aabc3fc 100644 --- a/core/java/android/bluetooth/BluetoothVolumeControl.java +++ b/core/java/android/bluetooth/BluetoothVolumeControl.java @@ -17,6 +17,8 @@ package android.bluetooth; +import static android.bluetooth.BluetoothUtils.getSyncTimeout; + import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; @@ -29,14 +31,16 @@ import android.annotation.SystemApi; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.content.AttributionSource; import android.content.Context; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.CloseGuard; import android.util.Log; +import com.android.modules.utils.SynchronousResultReceiver; + import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeoutException; /** * This class provides the public APIs to control the Bluetooth Volume Control service. @@ -86,7 +90,7 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose IBluetoothVolumeControl.class.getName()) { @Override public IBluetoothVolumeControl getServiceInterface(IBinder service) { - return IBluetoothVolumeControl.Stub.asInterface(Binder.allowBlocking(service)); + return IBluetoothVolumeControl.Stub.asInterface(service); } }; @@ -134,17 +138,23 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose public @NonNull List<BluetoothDevice> getConnectedDevices() { if (DBG) log("getConnectedDevices()"); final IBluetoothVolumeControl service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getConnectedDevices(mAttributionSource, recv); return Attributable.setAttributionSource( - service.getConnectedDevices(mAttributionSource), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), + mAttributionSource); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -159,18 +169,23 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { if (DBG) log("getDevicesMatchingStates()"); final IBluetoothVolumeControl service = getService(); - if (service != null && isEnabled()) { + final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>(); + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { try { + final SynchronousResultReceiver<List<BluetoothDevice>> recv = + new SynchronousResultReceiver(); + service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv); return Attributable.setAttributionSource( - service.getDevicesMatchingConnectionStates(states, mAttributionSource), + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue), mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return new ArrayList<BluetoothDevice>(); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return new ArrayList<BluetoothDevice>(); + return defaultValue; } /** @@ -185,16 +200,20 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose public int getConnectionState(BluetoothDevice device) { if (DBG) log("getConnectionState(" + device + ")"); final IBluetoothVolumeControl service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.STATE_DISCONNECTED; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionState(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.STATE_DISCONNECTED; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionState(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.STATE_DISCONNECTED; + return defaultValue; } /** @@ -212,18 +231,19 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose }) public void setVolume(@Nullable BluetoothDevice device, @IntRange(from = 0, to = 255) int volume) { - if (DBG) - log("setVolume(" + volume + ")"); + if (DBG) log("setVolume(" + volume + ")"); final IBluetoothVolumeControl service = getService(); - try { - if (service != null && isEnabled()) { - service.setVolume(device, volume, mAttributionSource); - return; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled()) { + try { + final SynchronousResultReceiver recv = new SynchronousResultReceiver(); + service.setVolume(device, volume, mAttributionSource, recv); + recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } - if (service == null) - Log.w(TAG, "Proxy not attached to service"); - } catch (RemoteException e) { - Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); } } @@ -249,20 +269,22 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose @ConnectionPolicy int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothVolumeControl service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { - if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN - && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { - return false; - } + final boolean defaultValue = false; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device) + && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN + || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { try { - return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return false; + final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver(); + service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return false; + return defaultValue; } /** @@ -285,16 +307,20 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothVolumeControl service = getService(); - if (service != null && isEnabled() && isValidDevice(device)) { + final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + if (service == null) { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) log(Log.getStackTraceString(new Throwable())); + } else if (isEnabled() && isValidDevice(device)) { try { - return service.getConnectionPolicy(device, mAttributionSource); - } catch (RemoteException e) { - Log.e(TAG, Log.getStackTraceString(new Throwable())); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver(); + service.getConnectionPolicy(device, mAttributionSource, recv); + return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue); + } catch (RemoteException | TimeoutException e) { + Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); } } - if (service == null) Log.w(TAG, "Proxy not attached to service"); - return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + return defaultValue; } private boolean isEnabled() { diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index f913349e7955..540e5a778c27 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -514,16 +514,27 @@ public final class BluetoothLeScanner { @Override public void onScanResult(final ScanResult scanResult) { Attributable.setAttributionSource(scanResult, mAttributionSource); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "onScanResult() - mScannerId=" + mScannerId); + } if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); // Check null in case the scan has been stopped synchronized (this) { - if (mScannerId <= 0) return; + if (mScannerId <= 0) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Ignoring result as scan stopped."); + } + return; + }; } Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "onScanResult() - handler run"); + } mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult); } }); diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 6ae2bb5b642a..157e709a67f0 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -22,6 +22,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; +import android.app.AppGlobals; import android.os.Binder; import android.os.Build; import android.os.IBinder; @@ -191,10 +192,42 @@ public final class AttributionSource implements Parcelable { return new ScopedParcelState(this); } - /** @hide */ - public static AttributionSource myAttributionSource() { - return new AttributionSource(Process.myUid(), ActivityThread.currentOpPackageName(), - /*attributionTag*/ null, (String[]) /*renouncedPermissions*/ null, /*next*/ null); + /** + * Returns a generic {@link AttributionSource} that represents the entire + * calling process. + * + * <p>Callers are <em>strongly</em> encouraged to use a more specific + * attribution source whenever possible, such as from + * {@link Context#getAttributionSource()}, since that enables developers to + * have more detailed and scoped control over attribution within + * sub-components of their app. + * + * @see Context#createAttributionContext(String) + * @see Context#getAttributionTag() + * @return a generic {@link AttributionSource} representing the entire + * calling process + * @throws IllegalStateException when no accurate {@link AttributionSource} + * can be determined + */ + public static @NonNull AttributionSource myAttributionSource() { + + final AttributionSource globalSource = ActivityThread.currentAttributionSource(); + if (globalSource != null) { + return globalSource; + } + + int uid = Process.myUid(); + if (uid == Process.ROOT_UID) { + uid = Process.SYSTEM_UID; + } + try { + return new AttributionSource.Builder(uid) + .setPackageName(AppGlobals.getPackageManager().getPackagesForUid(uid)[0]) + .build(); + } catch (Exception ignored) { + } + + throw new IllegalStateException("Failed to resolve AttributionSource"); } /** @@ -247,7 +280,7 @@ public final class AttributionSource implements Parcelable { * whether the attribution source is one for the calling app to prevent the caller * to pass you a source from another app without including themselves in the * attribution chain. - *f + * * @return if the attribution source cannot be trusted to be from the caller. */ public boolean checkCallingUid() { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1552dbd00c92..9659df6bf04a 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -5408,7 +5408,9 @@ public class Intent implements Parcelable, Cloneable { * * <p>Targets provided in this way will be presented inline with all other targets provided * by services from other apps. They will be prioritized before other service targets, but - * after those targets provided by sources that the user has manually pinned to the front.</p> + * after those targets provided by sources that the user has manually pinned to the front. + * You can provide up to two targets on this extra (the limit of two targets + * starts in Android 10).</p> * * @see #ACTION_CHOOSER */ @@ -5519,9 +5521,11 @@ public class Intent implements Parcelable, Cloneable { /** * A Parcelable[] of {@link Intent} or * {@link android.content.pm.LabeledIntent} objects as set with - * {@link #putExtra(String, Parcelable[])} of additional activities to place - * a the front of the list of choices, when shown to the user with a - * {@link #ACTION_CHOOSER}. + * {@link #putExtra(String, Parcelable[])} to place + * at the front of the list of choices, when shown to the user with an + * {@link #ACTION_CHOOSER}. You can choose up to two additional activities + * to show before the app suggestions (the limit of two additional activities starts in + * Android 10). */ public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS"; diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 70fe5d677b4f..123c55c27d1c 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -18,8 +18,11 @@ package android.net; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.METERED_YES; +import static android.net.NetworkTemplate.MATCH_BLUETOOTH; import static android.net.NetworkTemplate.MATCH_CARRIER; +import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE; +import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT; import android.annotation.NonNull; @@ -324,7 +327,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { @NonNull private byte[] getNetworkTemplateBytesForBackup() throws IOException { - if (!template.isPersistable()) { + if (!isTemplatePersistable(this.template)) { Log.wtf(TAG, "Trying to backup non-persistable template: " + this); } @@ -378,4 +381,28 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { "Restored network template contains unknown match rule " + matchRule, e); } } + + /** + * Check if the template can be persisted into disk. + */ + public static boolean isTemplatePersistable(@NonNull NetworkTemplate template) { + switch (template.getMatchRule()) { + case MATCH_BLUETOOTH: + case MATCH_ETHERNET: + return true; + case MATCH_CARRIER: + case MATCH_MOBILE: + return !template.getSubscriberIds().isEmpty(); + case MATCH_WIFI: + if (Objects.equals(template.getWifiNetworkKey(), null) + && template.getSubscriberIds().isEmpty()) { + return false; + } + return true; + default: + // Don't allow persistable for unknown types or legacy types such as + // MATCH_MOBILE_WILDCARD, MATCH_PROXY, etc. + return false; + } + } } diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index b069fb336d55..59db8f495dd9 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1235,10 +1235,11 @@ public class Binder implements IBinder { data.readCallingWorkSourceUid()); observer.callEnded(callSession, data.dataSize(), reply.dataSize(), workSourceUid); } + + checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); + reply.recycle(); + data.recycle(); } - checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); - reply.recycle(); - data.recycle(); // Just in case -- we are done with the IPC, so there should be no more strict // mode violations that have gathered for this thread. Either they have been diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index 0c3debb1b54e..26de7112a8b5 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -389,7 +389,7 @@ public class SystemVibrator extends Vibrator { mExecutor.execute(() -> { boolean anyVibrating; synchronized (mLock) { - int allInitializedMask = 1 << mVibratorListeners.size() - 1; + int allInitializedMask = (1 << mVibratorListeners.size()) - 1; int vibratorMask = 1 << vibratorIdx; if ((mInitializedMask & vibratorMask) == 0) { // First state report for this vibrator, set vibrating initial value. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2d70bad39c85..d0ef546a8122 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5756,7 +5756,6 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.CONNECTIVITY_CHANGE_DELAY); MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_SERVER); - MOVED_TO_GLOBAL.add(Settings.Global.NSD_ON); MOVED_TO_GLOBAL.add(Settings.Global.SET_INSTALL_LOCATION); MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_INSTALL_LOCATION); MOVED_TO_GLOBAL.add(Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY); @@ -12631,13 +12630,6 @@ public final class Settings { @Readable public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = "min_duration_between_recovery_steps"; - /** - * Whether network service discovery is enabled. - * - * @hide - */ - @Readable - public static final String NSD_ON = "nsd_on"; /** * Let user pick default install location. diff --git a/core/java/android/service/cloudsearch/OWNERS b/core/java/android/service/cloudsearch/OWNERS new file mode 100644 index 000000000000..aa4da3b4bee0 --- /dev/null +++ b/core/java/android/service/cloudsearch/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 758286 + +huiwu@google.com +srazdan@google.com diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index e7f89204c1ec..9eaaa91532d0 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -36,18 +36,24 @@ import android.telephony.Annotation.PreciseDisconnectCauses; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; +import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; import android.util.Log; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.listeners.ListenerExecutor; +import com.android.internal.telephony.ICarrierPrivilegesListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.ITelephonyRegistry; +import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.Executor; /** @@ -1214,4 +1220,117 @@ public class TelephonyRegistryManager { listenFromCallback(false, false, subId, pkgName, attributionTag, callback, new int[0], notifyNow); } + + private static class CarrierPrivilegesListenerWrapper extends ICarrierPrivilegesListener.Stub + implements ListenerExecutor { + private final WeakReference<CarrierPrivilegesListener> mListener; + private final Executor mExecutor; + + CarrierPrivilegesListenerWrapper(CarrierPrivilegesListener listener, Executor executor) { + mListener = new WeakReference<>(listener); + mExecutor = executor; + } + + @Override + public void onCarrierPrivilegesChanged( + List<String> privilegedPackageNames, int[] privilegedUids) { + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mListener::get, + cpl -> + cpl.onCarrierPrivilegesChanged( + privilegedPackageNames, privilegedUids))); + } + } + + @GuardedBy("sCarrierPrivilegeListeners") + private static final WeakHashMap< + CarrierPrivilegesListener, WeakReference<CarrierPrivilegesListenerWrapper>> + sCarrierPrivilegeListeners = new WeakHashMap<>(); + + /** + * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to + * receive callbacks when the set of packages with carrier privileges changes. The callback will + * immediately be called with the latest state. + * + * @param logicalSlotIndex The SIM slot to listen on + * @param executor The executor where {@code listener} will be invoked + * @param listener The callback to register + */ + public void addCarrierPrivilegesListener( + int logicalSlotIndex, + @NonNull @CallbackExecutor Executor executor, + @NonNull CarrierPrivilegesListener listener) { + if (listener == null || executor == null) { + throw new IllegalArgumentException("listener and executor must be non-null"); + } + synchronized (sCarrierPrivilegeListeners) { + WeakReference<CarrierPrivilegesListenerWrapper> existing = + sCarrierPrivilegeListeners.get(listener); + if (existing != null && existing.get() != null) { + Log.d(TAG, "addCarrierPrivilegesListener: listener already registered"); + return; + } + CarrierPrivilegesListenerWrapper wrapper = + new CarrierPrivilegesListenerWrapper(listener, executor); + sCarrierPrivilegeListeners.put(listener, new WeakReference<>(wrapper)); + try { + sRegistry.addCarrierPrivilegesListener( + logicalSlotIndex, + wrapper, + mContext.getOpPackageName(), + mContext.getAttributionTag()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Unregisters a {@link CarrierPrivilegesListener}. + * + * @param listener The callback to unregister + */ + public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must be non-null"); + } + synchronized (sCarrierPrivilegeListeners) { + WeakReference<CarrierPrivilegesListenerWrapper> ref = + sCarrierPrivilegeListeners.remove(listener); + if (ref == null) return; + CarrierPrivilegesListenerWrapper wrapper = ref.get(); + if (wrapper == null) return; + try { + sRegistry.removeCarrierPrivilegesListener(wrapper, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Notify listeners that the set of packages with carrier privileges has changed. + * + * @param logicalSlotIndex The SIM slot the change occurred on + * @param privilegedPackageNames The updated set of packages names with carrier privileges + * @param privilegedUids The updated set of UIDs with carrier privileges + */ + public void notifyCarrierPrivilegesChanged( + int logicalSlotIndex, + @NonNull List<String> privilegedPackageNames, + @NonNull int[] privilegedUids) { + if (privilegedPackageNames == null || privilegedUids == null) { + throw new IllegalArgumentException( + "privilegedPackageNames and privilegedUids must be non-null"); + } + try { + sRegistry.notifyCarrierPrivilegesChanged( + logicalSlotIndex, privilegedPackageNames, privilegedUids); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java index 052959abff69..1b6cb29d048d 100644 --- a/core/java/com/android/internal/net/NetworkUtilsInternal.java +++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java @@ -74,35 +74,4 @@ public class NetworkUtilsInternal { return true; } - - /** - * Safely multiple a value by a rational. - * <p> - * Internally it uses integer-based math whenever possible, but switches - * over to double-based math if values would overflow. - * @hide - */ - public static long multiplySafeByRational(long value, long num, long den) { - if (den == 0) { - throw new ArithmeticException("Invalid Denominator"); - } - long x = value; - long y = num; - - // Logic shamelessly borrowed from Math.multiplyExact() - long r = x * y; - long ax = Math.abs(x); - long ay = Math.abs(y); - if (((ax | ay) >>> 31 != 0)) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((y != 0) && (r / y != x)) - || (x == Long.MIN_VALUE && y == -1)) { - // Use double math to avoid overflowing - return (long) (((double) num / den) * value); - } - } - return r / den; - } } diff --git a/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl b/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl new file mode 100644 index 000000000000..6ca8cecba3c8 --- /dev/null +++ b/core/java/com/android/internal/telephony/ICarrierPrivilegesListener.aidl @@ -0,0 +1,22 @@ +/* + * 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 com.android.internal.telephony; + +oneway interface ICarrierPrivilegesListener { + void onCarrierPrivilegesChanged( + in List<String> privilegedPackageNames, in int[] privilegedUids); +} diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 15d4246e302a..9712d7e38a4b 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -32,6 +32,7 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; +import com.android.internal.telephony.ICarrierPrivilegesListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -100,4 +101,10 @@ interface ITelephonyRegistry { void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType); void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId, in List<LinkCapacityEstimate> linkCapacityEstimateList); + + void addCarrierPrivilegesListener( + int phoneId, ICarrierPrivilegesListener callback, String pkg, String featureId); + void removeCarrierPrivilegesListener(ICarrierPrivilegesListener callback, String pkg); + void notifyCarrierPrivilegesChanged( + int phoneId, in List<String> privilegedPackageNames, in int[] privilegedUids); } diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 790c39e73bff..832c49801bdc 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -55,13 +55,17 @@ per-file android_media_* = file:/media/java/android/media/OWNERS per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS -per-file android_se_* = file:/core/java/android/se/OWNERS +per-file android_se_* = file:/omapi/java/android/se/OWNERS per-file android_security_* = file:/core/java/android/security/OWNERS per-file android_view_* = file:/core/java/android/view/OWNERS per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS ### Graphics ### per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS + +### Text ### +per-file android_text_* = file:/core/java/android/text/OWNERS + # These are highly common-use files per-file Android.bp = file:/graphics/java/android/graphics/OWNERS per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index ca9124a78204..e035ab151190 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -716,8 +716,6 @@ message GlobalSettingsProto { optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; - message Ntp { option (android.msg_privacy).dest = DEST_EXPLICIT; diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt index d936cad15689..121caef87f6f 100644 --- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt +++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt @@ -16,6 +16,10 @@ package android.net +import android.net.NetworkTemplate.MATCH_BLUETOOTH +import android.net.NetworkTemplate.MATCH_ETHERNET +import android.net.NetworkTemplate.MATCH_MOBILE +import android.net.NetworkTemplate.MATCH_WIFI import android.text.format.Time.TIMEZONE_UTC import androidx.test.runner.AndroidJUnit4 import org.junit.Test @@ -24,6 +28,8 @@ import java.io.ByteArrayInputStream import java.io.DataInputStream import java.time.ZoneId import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue private const val TEST_IMSI1 = "TESTIMSI1" private const val TEST_SSID1 = "TESTISSID1" @@ -53,4 +59,26 @@ class NetworkPolicyTest { val restored = NetworkPolicy.getNetworkPolicyFromBackup(stream) assertEquals(policy, restored) } + + @Test + fun testIsTemplatePersistable() { + listOf(MATCH_MOBILE, MATCH_WIFI).forEach { + // Verify wildcard templates cannot be persistable. + assertFalse(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build())) + + // Verify mobile/wifi templates can be persistable if the Subscriber Id is supplied. + assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it) + .setSubscriberIds(setOf(TEST_IMSI1)).build())) + } + + // Verify bluetooth and ethernet templates can be persistable without any other + // field is supplied. + listOf(MATCH_BLUETOOTH, MATCH_ETHERNET).forEach { + assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build())) + } + + // Verify wifi template can be persistable if the Wifi Network Key is supplied. + assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI) + .setWifiNetworkKey(TEST_SSID1).build())) + } }
\ No newline at end of file diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 60f4a5a226db..982cf07da358 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -6791,56 +6791,63 @@ public class AudioManager { /** * Returns a list of audio formats that corresponds to encoding formats - * supported on offload path for A2DP and LE audio playback. + * supported on offload path for A2DP playback. * - * @param deviceType Indicates the target device type {@link AudioSystem.DeviceType} * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats - * supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig} - * objects containing encoding formats supported for offload LE Audio playback + * supported for offload A2DP playback * @hide */ - public List<?> getHwOffloadFormatsSupportedForBluetoothMedia( - @AudioSystem.DeviceType int deviceType) { - ArrayList<Integer> formatsList = new ArrayList<Integer>(); - ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>(); - ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = - new ArrayList<BluetoothLeAudioCodecConfig>(); + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() { + ArrayList<Integer> formatsList = new ArrayList<>(); + ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>(); - if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP - && deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) { - throw new IllegalArgumentException( - "Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia"); + int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList); + if (status != AudioManager.SUCCESS) { + Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status); + return codecConfigList; + } + + for (Integer format : formatsList) { + int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); + if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { + codecConfigList.add(new BluetoothCodecConfig(btSourceCodec)); + } } + return codecConfigList; + } + + /** + * Returns a list of audio formats that corresponds to encoding formats + * supported on offload path for Le audio playback. + * + * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats + * supported for offload Le Audio playback + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull + public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() { + ArrayList<Integer> formatsList = new ArrayList<>(); + ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>(); - int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType, - formatsList); + int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( + AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList); if (status != AudioManager.SUCCESS) { - Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType " - + deviceType + " failed:" + status); - return a2dpCodecConfigList; + Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status); + return leAudioCodecConfigList; } - if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { - for (Integer format : formatsList) { - int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); - if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { - a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec)); - } + for (Integer format : formatsList) { + int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format); + if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) { + leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder() + .setCodecType(btLeAudioCodec) + .build()); } - return a2dpCodecConfigList; - } else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) { - for (Integer format : formatsList) { - int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format); - if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) { - leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder() - .setCodecType(btLeAudioCodec) - .build()); - } - } - return leAudioCodecConfigList; } - Log.e(TAG, "Input deviceType " + deviceType + " doesn't support."); - return a2dpCodecConfigList; + return leAudioCodecConfigList; } // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java index dcd4dce5f3eb..ec56d614f2b5 100644 --- a/media/java/android/media/MediaActionSound.java +++ b/media/java/android/media/MediaActionSound.java @@ -16,8 +16,11 @@ package android.media; -import android.media.AudioManager; +import android.content.Context; import android.media.SoundPool; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; /** @@ -104,6 +107,26 @@ public class MediaActionSound { private static final int STATE_LOADING_PLAY_REQUESTED = 2; private static final int STATE_LOADED = 3; + /** + * <p>Returns true if the application must play the shutter sound in accordance + * to certain regional restrictions. </p> + * + * <p>If this method returns true, applications are strongly recommended to use + * MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures + * images or video to storage or sends them over the network.</p> + */ + public static boolean mustPlayShutterSound() { + boolean result = false; + IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); + IAudioService audioService = IAudioService.Stub.asInterface(b); + try { + result = audioService.isCameraSoundForced(); + } catch (RemoteException e) { + Log.e(TAG, "audio service is unavailable for queries, defaulting to false"); + } + return result; + } + private class SoundState { public final int name; public int id; diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index a0f6fb9577c3..9147c123c6f3 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -2720,6 +2720,42 @@ public final class TvContract { */ public static final String COLUMN_GLOBAL_CONTENT_ID = "global_content_id"; + /** + * The flag indicating whether this TV program is scrambled or not. + * + * <p>Use the same coding for scrambled in the underlying broadcast standard + * if {@code free_ca_mode} in EIT is defined there (e.g. ETSI EN 300 468). + * + * <p>Type: INTEGER (boolean) + */ + public static final String COLUMN_SCRAMBLED = "scrambled"; + + /** + * The comma-separated series IDs of this TV program for episodic TV shows. + * + * <p>This is used to indicate the series IDs. + * Programs in the same series share a series ID. + * Use this instead of {@link #COLUMN_SERIES_ID} if more than one series IDs + * are assigned to the TV program. + * + * <p>Can be empty. + * + * <p>Type: TEXT + */ + public static final String COLUMN_MULTI_SERIES_ID = "multi_series_id"; + + /** + * The internal ID used by individual TV input services. + * + * <p>This is internal to the provider that inserted it, and should not be decoded by other + * apps. + * + * <p>Can be empty. + * + * <p>Type: TEXT + */ + public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; + private Programs() {} /** Canonical genres for TV programs. */ @@ -3052,6 +3088,32 @@ public final class TvContract { public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS = "recording_expire_time_utc_millis"; + /** + * The comma-separated series IDs of this TV program for episodic TV shows. + * + * <p>This is used to indicate the series IDs. + * Programs in the same series share a series ID. + * Use this instead of {@link #COLUMN_SERIES_ID} if more than one series IDs + * are assigned to the TV program. + * + * <p>Can be empty. + * + * <p>Type: TEXT + */ + public static final String COLUMN_MULTI_SERIES_ID = "multi_series_id"; + + /** + * The internal ID used by individual TV input services. + * + * <p>This is internal to the provider that inserted it, and should not be decoded by other + * apps. + * + * <p>Can be empty. + * + * <p>Type: TEXT + */ + public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id"; + private RecordedPrograms() {} } diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp index 931a55b27ddb..0bda923f2389 100644 --- a/packages/ConnectivityT/framework-t/Android.bp +++ b/packages/ConnectivityT/framework-t/Android.bp @@ -114,6 +114,23 @@ filegroup { ], } +// Ethernet related libraries. + +filegroup { + name: "framework-connectivity-ethernet-sources", + srcs: [ + "src/android/net/EthernetManager.java", + "src/android/net/EthernetNetworkSpecifier.java", + "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/ITetheredInterfaceCallback.aidl", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + // Connectivity-T common libraries. filegroup { @@ -130,6 +147,7 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ + ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java index 8a6c85d54896..ca8330921620 100644 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -45,8 +45,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DataUnit; @@ -135,15 +133,6 @@ public class NetworkStatsManager { private int mFlags; - /** - * {@hide} - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStatsManager(Context context) throws ServiceNotFoundException { - this(context, INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); - } - /** @hide */ @VisibleForTesting public NetworkStatsManager(Context context, INetworkStatsService service) { diff --git a/core/java/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java index 7cd63ef9cc5a..7cd63ef9cc5a 100644 --- a/core/java/android/net/EthernetManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java index 62c576144221..62c576144221 100644 --- a/core/java/android/net/EthernetNetworkSpecifier.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java diff --git a/core/java/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl index e058e5a70c71..e058e5a70c71 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl diff --git a/core/java/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl index 782fa19d9df7..782fa19d9df7 100644 --- a/core/java/android/net/IEthernetServiceListener.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl index 14aa0237f24a..14aa0237f24a 100644 --- a/core/java/android/net/ITetheredInterfaceCallback.aidl +++ b/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java index 840af28b77e7..a84e7a9c6344 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java +++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java @@ -23,7 +23,6 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -469,20 +468,12 @@ public final class IpSecAlgorithm implements Parcelable { } } - // Because encryption keys are sensitive and userdebug builds are used by large user pools - // such as beta testers, we only allow sensitive info such as keys on eng builds. - private static boolean isUnsafeBuild() { - return Build.IS_DEBUGGABLE && Build.IS_ENG; - } - @Override @NonNull public String toString() { return new StringBuilder() .append("{mName=") .append(mName) - .append(", mKey=") - .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "<hidden>") .append(", mTruncLenBits=") .append(mTruncLenBits) .append("}") diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java index 837629911ccd..0d15dffae92d 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java +++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java @@ -17,8 +17,6 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.NonNull; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; @@ -46,6 +44,7 @@ import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; +import java.util.Objects; /** * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply @@ -86,6 +85,7 @@ public final class IpSecManager { * * @hide */ + @SystemApi(client = MODULE_LIBRARIES) public static final int DIRECTION_FWD = 2; /** @@ -988,7 +988,7 @@ public final class IpSecManager { */ public IpSecManager(Context ctx, IIpSecService service) { mContext = ctx; - mService = checkNotNull(service, "missing service"); + mService = Objects.requireNonNull(service, "missing service"); } private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java index b48c1fdaf1b2..36199a046cfc 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java +++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java @@ -33,7 +33,6 @@ import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; @@ -41,6 +40,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; +import java.util.Objects; /** * This class represents a transform, which roughly corresponds to an IPsec Security Association. @@ -255,7 +255,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setEncryption(algo); return this; } @@ -270,7 +270,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setAuthentication(algo); return this; } @@ -290,7 +290,7 @@ public final class IpSecTransform implements AutoCloseable { */ @NonNull public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setAuthenticatedEncryption(algo); return this; } @@ -311,7 +311,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setIpv4Encapsulation( @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { - Preconditions.checkNotNull(localSocket); + Objects.requireNonNull(localSocket); mConfig.setEncapType(ENCAP_ESPINUDP); if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); @@ -348,8 +348,8 @@ public final class IpSecTransform implements AutoCloseable { @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - Preconditions.checkNotNull(sourceAddress); - Preconditions.checkNotNull(spi); + Objects.requireNonNull(sourceAddress); + Objects.requireNonNull(spi); if (spi.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } @@ -387,8 +387,8 @@ public final class IpSecTransform implements AutoCloseable { @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - Preconditions.checkNotNull(sourceAddress); - Preconditions.checkNotNull(spi); + Objects.requireNonNull(sourceAddress); + Objects.requireNonNull(spi); if (spi.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } @@ -404,7 +404,7 @@ public final class IpSecTransform implements AutoCloseable { * @param context current context */ public Builder(@NonNull Context context) { - Preconditions.checkNotNull(context); + Objects.requireNonNull(context); mContext = context; mConfig = new IpSecConfig(); } diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java index c7ffc1933829..1986b83b12d8 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java @@ -16,7 +16,7 @@ package android.net; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.annotation.IntDef; import android.annotation.NonNull; diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java index 3885a9e6d5cb..591605d952e9 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java @@ -24,7 +24,7 @@ import static android.net.TrafficStats.UID_TETHERING; import android.Manifest; import android.annotation.IntDef; import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -32,8 +32,6 @@ import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; -import com.android.server.LocalServices; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -109,8 +107,7 @@ public final class NetworkStatsAccess { /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ public static @NetworkStatsAccess.Level int checkAccessLevel( Context context, int callingUid, String callingPackage) { - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); + final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); boolean hasCarrierPrivileges; @@ -123,8 +120,9 @@ public final class NetworkStatsAccess { Binder.restoreCallingIdentity(token); } - final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); + final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); final int appId = UserHandle.getAppId(callingUid); + if (hasCarrierPrivileges || isDeviceOwner || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { // Carrier-privileged apps and device owners, and the system (including the @@ -139,8 +137,8 @@ public final class NetworkStatsAccess { } //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. - boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid) - || dpmi.isActiveDeviceOwner(callingUid)); + boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage) + || mDpm.isDeviceOwnerApp(callingPackage)); if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile. diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java index 0d3b9ed4e3d4..8d1347e25bb6 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java @@ -30,7 +30,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.text.format.DateUtils.WEEK_IN_MILLIS; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java index a875e1ad45a3..3eef4ee6f829 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java @@ -28,8 +28,8 @@ import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; import static com.android.internal.util.ArrayUtils.total; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java index 8b9c14df7dc8..d85291318fa4 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java +++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java @@ -24,6 +24,8 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.OEM_NONE; +import static android.net.NetworkIdentity.OEM_PAID; +import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -35,6 +37,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -44,15 +47,21 @@ import android.os.Parcelable; import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; /** * Predicate used to match {@link NetworkIdentity}, usually when collecting @@ -60,40 +69,88 @@ import java.util.Objects; * * @hide */ -public class NetworkTemplate implements Parcelable { - private static final String TAG = "NetworkTemplate"; - +// @SystemApi(client = MODULE_LIBRARIES) +public final class NetworkTemplate implements Parcelable { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "MATCH_" }, value = { + MATCH_MOBILE, + MATCH_WIFI, + MATCH_ETHERNET, + MATCH_BLUETOOTH, + MATCH_CARRIER + }) + public @interface TemplateMatchRule{} + + /** Match rule to match cellular networks with given Subscriber Ids. */ public static final int MATCH_MOBILE = 1; + /** Match rule to match wifi networks. */ public static final int MATCH_WIFI = 4; + /** Match rule to match ethernet networks. */ public static final int MATCH_ETHERNET = 5; + /** + * Match rule to match all cellular networks. + * + * @hide + */ public static final int MATCH_MOBILE_WILDCARD = 6; + /** + * Match rule to match all wifi networks. + * + * @hide + */ public static final int MATCH_WIFI_WILDCARD = 7; + /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; + /** + * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. + * + * @hide + */ public static final int MATCH_PROXY = 9; + /** + * Match rule to match all networks with subscriberId inside the template. Some carriers + * may offer non-cellular networks like WiFi, which will be matched by this rule. + */ public static final int MATCH_CARRIER = 10; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = { + SUBSCRIBER_ID_MATCH_RULE_EXACT, + SUBSCRIBER_ID_MATCH_RULE_ALL + }) + public @interface SubscriberIdMatchRule{} /** * Value of the match rule of the subscriberId to match networks with specific subscriberId. + * + * @hide */ public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; /** * Value of the match rule of the subscriberId to match networks with any subscriberId which * includes null and non-null. + * + * @hide */ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. + /** @hide */ + public static final String WIFI_NETWORKID_ALL = null; + /** - * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that + * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that * should be fixed), so it's not possible to want to match null vs - * non-null. Therefore it's fine to use null as a sentinel for Network ID. + * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key. + * + * @hide */ - public static final String WIFI_NETWORKID_ALL = null; + public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL; /** * Include all network types when filtering. This is meant to merge in with the * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. - * - * @hide */ public static final int NETWORK_TYPE_ALL = -1; /** @@ -106,21 +163,37 @@ public class NetworkTemplate implements Parcelable { */ public static final int NETWORK_TYPE_5G_NSA = -2; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "OEM_MANAGED_" }, value = { + OEM_MANAGED_ALL, + OEM_MANAGED_NO, + OEM_MANAGED_YES, + OEM_MANAGED_PAID, + OEM_MANAGED_PRIVATE + }) + public @interface OemManaged{} + /** * Value to match both OEM managed and unmanaged networks (all networks). - * @hide */ public static final int OEM_MANAGED_ALL = -1; /** * Value to match networks which are not OEM managed. - * @hide */ public static final int OEM_MANAGED_NO = OEM_NONE; /** * Value to match any OEM managed network. - * @hide */ public static final int OEM_MANAGED_YES = -2; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. + */ + public static final int OEM_MANAGED_PAID = OEM_PAID; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. + */ + public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -142,6 +215,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { @@ -152,6 +227,8 @@ public class NetworkTemplate implements Parcelable { * Template to match cellular networks with the given IMSI, {@code ratType} and * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. + * + * @hide */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, @NetworkType int ratType, int metered) { @@ -168,6 +245,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. + * + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { @@ -177,6 +256,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { @@ -185,6 +266,7 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } + /** @hide */ @Deprecated @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifi() { @@ -194,6 +276,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. + * + * @hide */ public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { Objects.requireNonNull(networkId); @@ -208,7 +292,10 @@ public class NetworkTemplate implements Parcelable { * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, * and IMSI. * - * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless + * of SSID. + * + * @hide */ public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, @Nullable String subscriberId) { @@ -221,6 +308,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style * networks together. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateEthernet() { @@ -230,6 +319,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style * networks together. + * + * @hide */ public static NetworkTemplate buildTemplateBluetooth() { return new NetworkTemplate(MATCH_BLUETOOTH, null, null); @@ -238,6 +329,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style * networks together. + * + * @hide */ public static NetworkTemplate buildTemplateProxy() { return new NetworkTemplate(MATCH_PROXY, null, null); @@ -245,6 +338,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match all metered carrier networks with the given IMSI. + * + * @hide */ public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { Objects.requireNonNull(subscriberId); @@ -267,6 +362,7 @@ public class NetworkTemplate implements Parcelable { */ private final String[] mMatchSubscriberIds; + // TODO: Change variable name to match the Api surface. private final String mNetworkId; // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. @@ -283,14 +379,14 @@ public class NetworkTemplate implements Parcelable { // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; - private void checkValidSubscriberIdMatchRule() { - switch (mMatchRule) { + private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) { + switch (matchRule) { case MATCH_MOBILE: case MATCH_CARRIER: // MOBILE and CARRIER templates must always specify a subscriber ID. - if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { - throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" - + "on match rule: " + getMatchRuleName(mMatchRule)); + if (subscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " + + "on match rule: " + getMatchRuleName(matchRule)); } return; default: @@ -298,12 +394,14 @@ public class NetworkTemplate implements Parcelable { } } + /** @hide */ // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } + /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates @@ -316,6 +414,7 @@ public class NetworkTemplate implements Parcelable { OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } + /** @hide */ // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, @@ -324,6 +423,7 @@ public class NetworkTemplate implements Parcelable { defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); } + /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) { @@ -339,7 +439,7 @@ public class NetworkTemplate implements Parcelable { mSubType = subType; mOemManaged = oemManaged; mSubscriberIdMatchRule = subscriberIdMatchRule; - checkValidSubscriberIdMatchRule(); + checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); if (!isKnownMatchRule(matchRule)) { throw new IllegalArgumentException("Unknown network template rule " + matchRule + " will not match any identity."); @@ -360,7 +460,7 @@ public class NetworkTemplate implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); @@ -437,7 +537,7 @@ public class NetworkTemplate implements Parcelable { return false; } - private String subscriberIdMatchRuleToString(int rule) { + private static String subscriberIdMatchRuleToString(int rule) { switch (rule) { case SUBSCRIBER_ID_MATCH_RULE_EXACT: return "EXACT_MATCH"; @@ -448,6 +548,7 @@ public class NetworkTemplate implements Parcelable { } } + /** @hide */ public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -458,48 +559,108 @@ public class NetworkTemplate implements Parcelable { } } - public boolean isPersistable() { + /** + * Get match rule of the template. See {@code MATCH_*}. + */ + @UnsupportedAppUsage + public int getMatchRule() { + // Wildcard rules are not exposed. For external callers, convert wildcard rules to + // exposed rules before returning. switch (mMatchRule) { case MATCH_MOBILE_WILDCARD: + return MATCH_MOBILE; case MATCH_WIFI_WILDCARD: - return false; - case MATCH_CARRIER: - return mSubscriberId != null; - case MATCH_WIFI: - if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) - && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { - return false; - } - return true; + return MATCH_WIFI; default: - return true; + return mMatchRule; } } - @UnsupportedAppUsage - public int getMatchRule() { - return mMatchRule; - } - + /** + * Get subscriber Id of the template. + */ + @Nullable @UnsupportedAppUsage public String getSubscriberId() { return mSubscriberId; } + /** + * Get set of subscriber Ids of the template. + */ + @NonNull + public Set<String> getSubscriberIds() { + return new ArraySet<>(Arrays.asList(mMatchSubscriberIds)); + } + + /** + * Get Wifi Network Key of the template. See {@link WifiInfo#getCurrentNetworkKey()}. + */ + @Nullable + public String getWifiNetworkKey() { + return mNetworkId; + } + + /** @hide */ + // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}. + @Nullable public String getNetworkId() { return mNetworkId; } + /** + * Get Subscriber Id Match Rule of the template. + * + * @hide + */ public int getSubscriberIdMatchRule() { return mSubscriberIdMatchRule; } + /** + * Get meteredness filter of the template. + */ + @NetworkStats.Meteredness public int getMeteredness() { return mMetered; } /** + * Get roaming filter of the template. + */ + @NetworkStats.Roaming + public int getRoaming() { + return mRoaming; + } + + /** + * Get the default network status filter of the template. + */ + @NetworkStats.DefaultNetwork + public int getDefaultNetworkStatus() { + return mDefaultNetwork; + } + + /** + * Get the Radio Access Technology(RAT) type filter of the template. + */ + public int getRatType() { + return mSubType; + } + + /** + * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or + * {@code android.net.NetworkIdentity#OEM_*}. + */ + @OemManaged + public int getOemManaged() { + return mOemManaged; + } + + /** * Test if given {@link NetworkIdentity} matches this template. + * + * @hide */ public boolean matches(NetworkIdentity ident) { if (!matchesMetered(ident)) return false; @@ -565,6 +726,8 @@ public class NetworkTemplate implements Parcelable { * Check if this template matches {@code subscriberId}. Returns true if this * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + * + * @hide */ public boolean matchesSubscriberId(@Nullable String subscriberId) { return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL @@ -573,10 +736,10 @@ public class NetworkTemplate implements Parcelable { /** * Check if network with matching SSID. Returns true when the SSID matches, or when - * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + * {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}. */ private boolean matchesWifiNetworkId(@Nullable String networkId) { - return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL) || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } @@ -599,10 +762,13 @@ public class NetworkTemplate implements Parcelable { * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. * * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + * + * @hide */ // TODO: 1. Consider move this to TelephonyManager if used by other modules. // 2. Consider make this configurable. // 3. Use TelephonyManager APIs when available. + // TODO: @SystemApi when ready. public static int getCollapsedRatType(int ratType) { switch (ratType) { case TelephonyManager.NETWORK_TYPE_GPRS: @@ -639,7 +805,10 @@ public class NetworkTemplate implements Parcelable { /** * Return all supported collapsed RAT types that could be returned by * {@link #getCollapsedRatType(int)}. + * + * @hide */ + // TODO: @SystemApi when ready. @NonNull public static final int[] getAllCollapsedRatTypes() { final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); @@ -779,6 +948,8 @@ public class NetworkTemplate implements Parcelable { * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { @@ -797,7 +968,10 @@ public class NetworkTemplate implements Parcelable { * For example, given an incoming template matching B, and the currently * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. + * + * @hide */ + // TODO: @SystemApi when ready. public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { // Now there are several types of network which uses SubscriberId to store network // information. For instances: @@ -830,4 +1004,184 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate[size]; } }; + + /** + * Builder class for NetworkTemplate. + */ + public static final class Builder { + private final int mMatchRule; + // Use a SortedSet to provide a deterministic order when fetching the first one. + @NonNull + private final SortedSet<String> mMatchSubscriberIds = new TreeSet<>(); + @Nullable + private String mWifiNetworkKey; + + // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. + private int mMetered; + private int mRoaming; + private int mDefaultNetwork; + private int mRatType; + + // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}. + private int mOemManaged; + + /** + * Creates a new Builder with given match rule to construct NetworkTemplate objects. + * + * @param matchRule the match rule of the template, see {@code MATCH_*}. + */ + public Builder(@TemplateMatchRule final int matchRule) { + assertRequestableMatchRule(matchRule); + // Initialize members with default values. + mMatchRule = matchRule; + mWifiNetworkKey = WIFI_NETWORK_KEY_ALL; + mMetered = METERED_ALL; + mRoaming = ROAMING_ALL; + mDefaultNetwork = DEFAULT_NETWORK_ALL; + mRatType = NETWORK_TYPE_ALL; + mOemManaged = OEM_MANAGED_ALL; + } + + /** + * Set the Subscriber Ids. Calling this function with an empty set represents + * the intention of matching any Subscriber Ids. + * + * @param subscriberIds the list of Subscriber Ids. + * @return this builder. + */ + @NonNull + public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) { + Objects.requireNonNull(subscriberIds); + mMatchSubscriberIds.clear(); + mMatchSubscriberIds.addAll(subscriberIds); + return this; + } + + /** + * Set the Wifi Network Key. + * + * @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}. + * Or null to match all networks. + * @return this builder. + */ + @NonNull + public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { + mWifiNetworkKey = wifiNetworkKey; + return this; + } + + /** + * Set the meteredness filter. + * + * @param metered the meteredness filter. + * @return this builder. + */ + @NonNull + public Builder setMeteredness(@NetworkStats.Meteredness int metered) { + mMetered = metered; + return this; + } + + /** + * Set the roaming filter. + * + * @param roaming the roaming filter. + * @return this builder. + */ + @NonNull + public Builder setRoaming(@NetworkStats.Roaming int roaming) { + mRoaming = roaming; + return this; + } + + /** + * Set the default network status filter. + * + * @param defaultNetwork the default network status filter. + * @return this builder. + */ + @NonNull + public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) { + mDefaultNetwork = defaultNetwork; + return this; + } + + /** + * Set the Radio Access Technology(RAT) type filter. + * + * @param ratType the Radio Access Technology(RAT) type filter. Use + * {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + * @return this builder. + */ + @NonNull + public Builder setRatType(@NetworkType int ratType) { + // Input will be validated with the match rule when building the template. + mRatType = ratType; + return this; + } + + /** + * Set the OEM managed filter. + * + * @param oemManaged the match rule to match different type of OEM managed network or + * unmanaged networks. See {@code OEM_MANAGED_*}. + * @return this builder. + */ + @NonNull + public Builder setOemManaged(@OemManaged int oemManaged) { + mOemManaged = oemManaged; + return this; + } + + /** + * Check whether the match rule is requestable. + * + * @param matchRule the target match rule to be checked. + */ + private static void assertRequestableMatchRule(final int matchRule) { + if (!isKnownMatchRule(matchRule) + || matchRule == MATCH_PROXY + || matchRule == MATCH_MOBILE_WILDCARD + || matchRule == MATCH_WIFI_WILDCARD) { + throw new IllegalArgumentException("Invalid match rule: " + + getMatchRuleName(matchRule)); + } + } + + private void assertRequestableParameters() { + // TODO: Check all the input are legitimate. + } + + /** + * For backward compatibility, deduce match rule to a wildcard match rule + * if the Subscriber Ids are empty. + */ + private int getWildcardDeducedMatchRule() { + if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { + return MATCH_MOBILE_WILDCARD; + } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() + && mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) { + return MATCH_WIFI_WILDCARD; + } + return mMatchRule; + } + + /** + * Builds the instance of the NetworkTemplate. + * + * @return the built instance of NetworkTemplate. + */ + @NonNull + public NetworkTemplate build() { + assertRequestableParameters(); + final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() + ? SUBSCRIBER_ID_MATCH_RULE_ALL : SUBSCRIBER_ID_MATCH_RULE_EXACT; + return new NetworkTemplate(getWildcardDeducedMatchRule(), + mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), + mMatchSubscriberIds.toArray(new String[0]), + mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, + subscriberIdMatchRule); + } + } } diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp index 7b8817692b74..97dfb64b33dd 100644 --- a/packages/ConnectivityT/service/Android.bp +++ b/packages/ConnectivityT/service/Android.bp @@ -61,11 +61,25 @@ filegroup { ], } +// Ethernet related libraries. + +filegroup { + name: "services.connectivity-ethernet-sources", + srcs: [ + "src/com/android/server/net/IpConfigStore.java", + ], + path: "src", + visibility: [ + "//frameworks/opt/net/ethernet", + ], +} + // Connectivity-T common libraries. filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ + ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java index f251b86b7a09..d1e432e80f51 100644 --- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java +++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java @@ -45,7 +45,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.TrafficStats; -import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -96,8 +95,6 @@ import java.util.Objects; public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - - private static final String NETD_SERVICE_NAME = "netd"; private static final int[] ADDRESS_FAMILIES = new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; @@ -106,6 +103,8 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; + private final INetd mNetd; + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); @@ -627,16 +626,14 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { int spi = mSpi.getSpi(); try { - mDeps - .getNetdInstance(mContext) - .ipSecDeleteSecurityAssociation( - mUid, - mConfig.getSourceAddress(), - mConfig.getDestinationAddress(), - spi, - mConfig.getMarkValue(), - mConfig.getMarkMask(), - mConfig.getXfrmInterfaceId()); + mNetd.ipSecDeleteSecurityAssociation( + mUid, + mConfig.getSourceAddress(), + mConfig.getDestinationAddress(), + spi, + mConfig.getMarkValue(), + mConfig.getMarkMask(), + mConfig.getXfrmInterfaceId()); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } @@ -680,14 +677,12 @@ public class IpSecService extends IIpSecService.Stub { private final String mSourceAddress; private final String mDestinationAddress; private int mSpi; - private final Context mContext; private boolean mOwnedByTransform = false; - SpiRecord(Context context, int resourceId, String sourceAddress, + SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) { super(resourceId); - mContext = context; mSourceAddress = sourceAddress; mDestinationAddress = destinationAddress; mSpi = spi; @@ -698,11 +693,9 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { try { if (!mOwnedByTransform) { - mDeps - .getNetdInstance(mContext) - .ipSecDeleteSecurityAssociation( - mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, - 0 /* mask */, 0 /* if_id */); + mNetd.ipSecDeleteSecurityAssociation( + mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, + 0 /* mask */, 0 /* if_id */); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -821,10 +814,8 @@ public class IpSecService extends IIpSecService.Stub { private final int mIfId; private Network mUnderlyingNetwork; - private final Context mContext; TunnelInterfaceRecord( - Context context, int resourceId, String interfaceName, Network underlyingNetwork, @@ -835,7 +826,6 @@ public class IpSecService extends IIpSecService.Stub { int intfId) { super(resourceId); - mContext = context; mInterfaceName = interfaceName; mUnderlyingNetwork = underlyingNetwork; mLocalAddress = localAddr; @@ -852,18 +842,17 @@ public class IpSecService extends IIpSecService.Stub { // Teardown VTI // Delete global policies try { - final INetd netd = mDeps.getNetdInstance(mContext); - netd.ipSecRemoveTunnelInterface(mInterfaceName); + mNetd.ipSecRemoveTunnelInterface(mInterfaceName); for (int selAddrFamily : ADDRESS_FAMILIES) { - netd.ipSecDeleteSecurityPolicy( + mNetd.ipSecDeleteSecurityPolicy( mUid, selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, 0xffffffff, mIfId); - netd.ipSecDeleteSecurityPolicy( + mNetd.ipSecDeleteSecurityPolicy( mUid, selAddrFamily, IpSecManager.DIRECTION_IN, @@ -1026,7 +1015,6 @@ public class IpSecService extends IIpSecService.Stub { static IpSecService create(Context context) throws InterruptedException { final IpSecService service = new IpSecService(context); - service.connectNativeNetdService(); return service; } @@ -1057,8 +1045,13 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) { mContext = context; - mDeps = deps; + mDeps = Objects.requireNonNull(deps, "Missing dependencies."); mUidFdTagger = uidFdTagger; + try { + mNetd = mDeps.getNetdInstance(mContext); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** Called by system server when system is ready. */ @@ -1070,25 +1063,12 @@ public class IpSecService extends IIpSecService.Stub { } } - private void connectNativeNetdService() { - // Avoid blocking the system server to do this - new Thread() { - @Override - public void run() { - synchronized (IpSecService.this) { - NetdService.get(NETD_FETCH_TIMEOUT_MS); - } - } - }.start(); - } - synchronized boolean isNetdAlive() { try { - final INetd netd = mDeps.getNetdInstance(mContext); - if (netd == null) { + if (mNetd == null) { return false; } - return netd.isAlive(); + return mNetd.isAlive(); } catch (RemoteException re) { return false; } @@ -1149,15 +1129,12 @@ public class IpSecService extends IIpSecService.Stub { IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } - spi = - mDeps - .getNetdInstance(mContext) - .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); + spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, new RefcountedResource<SpiRecord>( - new SpiRecord(mContext, resourceId, "", + new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { if (e.errorCode == OsConstants.ENOENT) { @@ -1275,8 +1252,7 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mDeps.getNetdInstance(mContext).ipSecSetEncapSocketOwner( - new ParcelFileDescriptor(sockFd), callingUid); + mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); Os.bind(sockFd, INADDR_ANY, port); @@ -1338,16 +1314,15 @@ public class IpSecService extends IIpSecService.Stub { // Create VTI // Add inbound/outbound global policies // (use reqid = 0) - final INetd netd = mDeps.getNetdInstance(mContext); - netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); + mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); BinderUtils.withCleanCallingIdentity(() -> { - NetdUtils.setInterfaceUp(netd, intfName); + NetdUtils.setInterfaceUp(mNetd, intfName); }); for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_OUT, @@ -1357,7 +1332,7 @@ public class IpSecService extends IIpSecService.Stub { okey, 0xffffffff, resourceId); - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_IN, @@ -1377,7 +1352,7 @@ public class IpSecService extends IIpSecService.Stub { // // This is necessary only on the tunnel interface, and not any the interface to // which traffic will be forwarded to. - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_FWD, @@ -1393,7 +1368,6 @@ public class IpSecService extends IIpSecService.Stub { resourceId, new RefcountedResource<TunnelInterfaceRecord>( new TunnelInterfaceRecord( - mContext, resourceId, intfName, underlyingNetwork, @@ -1435,12 +1409,10 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mDeps - .getNetdInstance(mContext) - .interfaceAddAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); + mNetd.interfaceAddAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1464,9 +1436,7 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mDeps - .getNetdInstance(mContext) - .interfaceDelAddress( + mNetd.interfaceDelAddress( tunnelInterfaceInfo.mInterfaceName, localAddr.getAddress().getHostAddress(), localAddr.getPrefixLength()); @@ -1679,30 +1649,28 @@ public class IpSecService extends IIpSecService.Stub { cryptName = crypt.getName(); } - mDeps - .getNetdInstance(mContext) - .ipSecAddSecurityAssociation( - Binder.getCallingUid(), - c.getMode(), - c.getSourceAddress(), - c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, - spiRecord.getSpi(), - c.getMarkValue(), - c.getMarkMask(), - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - cryptName, - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort, - c.getXfrmInterfaceId()); + mNetd.ipSecAddSecurityAssociation( + Binder.getCallingUid(), + c.getMode(), + c.getSourceAddress(), + c.getDestinationAddress(), + (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, + spiRecord.getSpi(), + c.getMarkValue(), + c.getMarkMask(), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : new byte[] {}, + (auth != null) ? auth.getTruncationLengthBits() : 0, + cryptName, + (crypt != null) ? crypt.getKey() : new byte[] {}, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort, + c.getXfrmInterfaceId()); } /** @@ -1791,15 +1759,13 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - mDeps - .getNetdInstance(mContext) - .ipSecApplyTransportModeTransform( - socket, - callingUid, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); + mNetd.ipSecApplyTransportModeTransform( + socket, + callingUid, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } /** @@ -1811,9 +1777,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - mDeps - .getNetdInstance(mContext) - .ipSecRemoveTransportModeTransform(socket); + mNetd.ipSecRemoveTransportModeTransform(socket); } /** @@ -1888,18 +1852,16 @@ public class IpSecService extends IIpSecService.Stub { // Always update the policy with the relevant XFRM_IF_ID for (int selAddrFamily : ADDRESS_FAMILIES) { - mDeps - .getNetdInstance(mContext) - .ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - transformInfo.getConfig().getSourceAddress(), - transformInfo.getConfig().getDestinationAddress(), - spi, // If outbound, also add SPI to the policy. - mark, // Must always set policy mark; ikey/okey for VTIs - 0xffffffff, - c.getXfrmInterfaceId()); + mNetd.ipSecUpdateSecurityPolicy( + callingUid, + selAddrFamily, + direction, + transformInfo.getConfig().getSourceAddress(), + transformInfo.getConfig().getDestinationAddress(), + spi, // If outbound, also add SPI to the policy. + mark, // Must always set policy mark; ikey/okey for VTIs + 0xffffffff, + c.getXfrmInterfaceId()); } // Update SA with tunnel mark (ikey or okey based on direction) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java index d17dbde496ce..3a9a54415537 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java @@ -44,6 +44,9 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; +/** + * This class provides an API to store and manage L3 network IP configuration. + */ public class IpConfigStore { private static final String TAG = "IpConfigStore"; private static final boolean DBG = false; @@ -78,6 +81,9 @@ public class IpConfigStore { return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); } + /** + * Write the IP configuration with the given parameters to {@link DataOutputStream}. + */ @VisibleForTesting public static boolean writeConfig(DataOutputStream out, String configKey, IpConfiguration config, int version) throws IOException { @@ -154,10 +160,10 @@ public class IpConfigStore { break; case UNASSIGNED: /* Ignore */ - break; - default: - loge("Ignore invalid proxy settings while writing"); - break; + break; + default: + loge("Ignore invalid proxy settings while writing"); + break; } if (written) { @@ -177,7 +183,7 @@ public class IpConfigStore { } /** - * @Deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. + * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. * New method uses string as network identifier which could be interface name or MAC address or * other token. */ @@ -186,22 +192,28 @@ public class IpConfigStore { final SparseArray<IpConfiguration> networks) { mWriter.write(filePath, out -> { out.writeInt(IPCONFIG_FILE_VERSION); - for(int i = 0; i < networks.size(); i++) { + for (int i = 0; i < networks.size(); i++) { writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); } }); } + /** + * Write the IP configuration associated to the target networks to the destination path. + */ public void writeIpConfigurations(String filePath, ArrayMap<String, IpConfiguration> networks) { mWriter.write(filePath, out -> { out.writeInt(IPCONFIG_FILE_VERSION); - for(int i = 0; i < networks.size(); i++) { + for (int i = 0; i < networks.size(); i++) { writeConfig(out, networks.keyAt(i), networks.valueAt(i)); } }); } + /** + * Read the IP configuration from the destination path to {@link BufferedInputStream}. + */ public static ArrayMap<String, IpConfiguration> readIpConfigurations(String filePath) { BufferedInputStream bufferedInputStream; try { @@ -215,7 +227,7 @@ public class IpConfigStore { return readIpConfigurations(bufferedInputStream); } - /** @Deprecated use {@link #readIpConfigurations(String)} */ + /** @deprecated use {@link #readIpConfigurations(String)} */ @Deprecated public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) { BufferedInputStream bufferedInputStream; @@ -230,7 +242,7 @@ public class IpConfigStore { return readIpAndProxyConfigurations(bufferedInputStream); } - /** @Deprecated use {@link #readIpConfigurations(InputStream)} */ + /** @deprecated use {@link #readIpConfigurations(InputStream)} */ @Deprecated public static SparseArray<IpConfiguration> readIpAndProxyConfigurations( InputStream inputStream) { @@ -420,7 +432,7 @@ public class IpConfigStore { if (in != null) { try { in.close(); - } catch (Exception e) {} + } catch (Exception e) { } } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 268603fa8b0d..200e902c6420 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -1348,7 +1348,6 @@ class DatabaseHelper extends SQLiteOpenHelper { Settings.Global.CONNECTIVITY_CHANGE_DELAY, Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, Settings.Global.CAPTIVE_PORTAL_SERVER, - Settings.Global.NSD_ON, Settings.Global.SET_INSTALL_LOCATION, Settings.Global.DEFAULT_INSTALL_LOCATION, Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index f145f508da2e..63c874a08621 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1115,10 +1115,6 @@ class SettingsProtoDumpUtil { p.end(notificationToken); dumpSetting(s, p, - Settings.Global.NSD_ON, - GlobalSettingsProto.NSD_ON); - - dumpSetting(s, p, Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE, GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 883c4a1cd936..10dafd93c18e 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -394,7 +394,6 @@ public class SettingsBackupTest { Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, Settings.Global.NOTIFICATION_FEEDBACK_ENABLED, Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE, - Settings.Global.NSD_ON, Settings.Global.NTP_SERVER, Settings.Global.NTP_TIMEOUT, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 918635d666fa..c88e95f07f12 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -323,6 +323,46 @@ </FrameLayout> </LinearLayout> + <LinearLayout + android:id="@+id/wifi_scan_notify_layout" + style="@style/InternetDialog.Network" + android:orientation="vertical" + android:layout_height="wrap_content" + android:paddingBottom="4dp" + android:clickable="false" + android:focusable="false"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="56dp" + android:gravity="start|top" + android:orientation="horizontal" + android:paddingEnd="12dp" + android:paddingTop="16dp" + android:paddingBottom="4dp"> + <ImageView + android:src="@drawable/ic_info_outline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:tint="?android:attr/textColorTertiary"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:id="@+id/wifi_scan_notify_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:paddingBottom="8dp" + android:textColor="?android:attr/textColorSecondary" + android:clickable="true"/> + </LinearLayout> + </LinearLayout> + <FrameLayout android:id="@+id/done_layout" android:layout_width="67dp" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7aacb702b75a..4ad4fa9d0854 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3033,4 +3033,6 @@ <string name="see_all_networks">See all</string> <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] --> <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string> + <!-- Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi scanning is on. [CHAR LIMIT=NONE] --> + <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java index d8e80fe99331..0d7551ff66e9 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java @@ -30,7 +30,7 @@ import java.util.Optional; /** * A span that turns the text wrapped by annotation tag into the clickable link text. */ -class AnnotationLinkSpan extends ClickableSpan { +public class AnnotationLinkSpan extends ClickableSpan { private final Optional<View.OnClickListener> mClickListener; private AnnotationLinkSpan(View.OnClickListener listener) { @@ -50,7 +50,7 @@ class AnnotationLinkSpan extends ClickableSpan { * @param linkInfos used to attach the click action into the corresponding span * @return the text attached with the span */ - static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { + public static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { final SpannableString msg = new SpannableString(text); final Annotation[] spans = msg.getSpans(/* queryStart= */ 0, msg.length(), Annotation.class); @@ -78,12 +78,12 @@ class AnnotationLinkSpan extends ClickableSpan { /** * Data class to store the annotation and the click action. */ - static class LinkInfo { - static final String DEFAULT_ANNOTATION = "link"; + public static class LinkInfo { + public static final String DEFAULT_ANNOTATION = "link"; private final Optional<String> mAnnotation; private final Optional<View.OnClickListener> mListener; - LinkInfo(@NonNull String annotation, View.OnClickListener listener) { + public LinkInfo(@NonNull String annotation, View.OnClickListener listener) { mAnnotation = Optional.of(annotation); mListener = Optional.ofNullable(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index dc54e1b52f2e..dae357e9e36b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -36,6 +36,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.text.Html; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -63,6 +64,7 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.SystemUIDialog; @@ -110,6 +112,8 @@ public class InternetDialog extends SystemUIDialog implements private LinearLayout mTurnWifiOnLayout; private LinearLayout mEthernetLayout; private TextView mWifiToggleTitleText; + private LinearLayout mWifiScanNotifyLayout; + private TextView mWifiScanNotifyText; private LinearLayout mSeeAllLayout; private RecyclerView mWifiRecyclerView; private ImageView mConnectedWifiIcon; @@ -220,6 +224,8 @@ public class InternetDialog extends SystemUIDialog implements mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout); mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout); mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title); + mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); + mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout); mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon); mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title); @@ -313,8 +319,10 @@ public class InternetDialog extends SystemUIDialog implements showProgressBar(); final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked(); final boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + final boolean isWifiScanEnabled = mWifiManager.isScanAlwaysAvailable(); updateWifiToggle(isWifiEnabled, isDeviceLocked); updateConnectedWifi(isWifiEnabled, isDeviceLocked); + updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked); final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0) ? View.GONE : View.VISIBLE; @@ -411,6 +419,24 @@ public class InternetDialog extends SystemUIDialog implements mContext.getColor(R.color.connected_network_primary_color)); } + @MainThread + private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled, + boolean isDeviceLocked) { + if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) { + mWifiScanNotifyLayout.setVisibility(View.GONE); + return; + } + if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) { + final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo( + AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION, + v -> mInternetDialogController.launchWifiScanningSetting()); + mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify( + getContext().getText(R.string.wifi_scan_notify_message), linkInfo)); + mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance()); + } + mWifiScanNotifyLayout.setVisibility(View.VISIBLE); + } + void onClickConnectedWifi() { if (mConnectedWifiEntry == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index aaba5efc92f6..276c0be53063 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -103,6 +103,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private static final String TAG = "InternetDialogController"; private static final String ACTION_NETWORK_PROVIDER_SETTINGS = "android.settings.NETWORK_PROVIDER_SETTINGS"; + private static final String ACTION_WIFI_SCANNING_SETTINGS = + "android.settings.WIFI_SCANNING_SETTINGS"; private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); public static final int NO_CELL_DATA_TYPE_ICON = 0; @@ -603,6 +605,13 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } } + void launchWifiScanningSetting() { + mCallback.dismissDialog(); + final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); + } + void connectCarrierNetwork() { final MergedCarrierEntry mergedCarrierEntry = mAccessPointController.getMergedCarrierEntry(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java index c42b64a09985..7cea430e146f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -19,6 +19,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.test.filters.SmallTest; @@ -73,6 +74,7 @@ public class InternetDialogTest extends SysuiTestCase { private LinearLayout mConnectedWifi; private RecyclerView mWifiList; private LinearLayout mSeeAll; + private LinearLayout mWifiScanNotify; @Before public void setUp() { @@ -104,6 +106,7 @@ public class InternetDialogTest extends SysuiTestCase { mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout); mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout); mSeeAll = mDialogView.requireViewById(R.id.see_all_layout); + mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); } @After @@ -264,6 +267,50 @@ public class InternetDialogTest extends SysuiTestCase { } @Test + public void updateDialog_wifiOn_hideWifiScanNotify() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + + mInternetDialog.updateDialog(); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + mInternetDialog.updateDialog(); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(false); + + mInternetDialog.updateDialog(); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE); + TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); + assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0); + assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull(); + } + + @Test public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() { mSeeAll.performClick(); diff --git a/services/OWNERS b/services/OWNERS index b3bf5dcd2292..9b5f0e701fdf 100644 --- a/services/OWNERS +++ b/services/OWNERS @@ -5,3 +5,5 @@ per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.co per-file java/com/android/server/* = patb@google.com per-file tests/servicestests/src/com/android/server/systemconfig/* = patb@google.com + +per-file proguard.flags = jdduke@google.com diff --git a/services/cloudsearch/OWNERS b/services/cloudsearch/OWNERS new file mode 100644 index 000000000000..aa4da3b4bee0 --- /dev/null +++ b/services/cloudsearch/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 758286 + +huiwu@google.com +srazdan@google.com diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index d7c1cfb7d1ed..811f2f5e5283 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -91,6 +91,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; +import com.android.internal.telephony.ICarrierPrivilegesListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; @@ -106,6 +107,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -149,6 +151,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { IPhoneStateListener callback; IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback; IOnSubscriptionsChangedListener onOpportunisticSubscriptionsChangedListenerCallback; + ICarrierPrivilegesListener carrierPrivilegesListener; int callerUid; int callerPid; @@ -173,6 +176,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return (onOpportunisticSubscriptionsChangedListenerCallback != null); } + boolean matchCarrierPrivilegesListener() { + return carrierPrivilegesListener != null; + } + boolean canReadCallLog() { try { return TelephonyPermissions.checkReadCallLog( @@ -189,8 +196,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + " onSubscriptionsChangedListenererCallback=" + onSubscriptionsChangedListenerCallback + " onOpportunisticSubscriptionsChangedListenererCallback=" - + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId - + " phoneId=" + phoneId + " events=" + eventList + "}"; + + onOpportunisticSubscriptionsChangedListenerCallback + + " carrierPrivilegesListener=" + carrierPrivilegesListener + + " subId=" + subId + " phoneId=" + phoneId + " events=" + eventList + "}"; } } @@ -402,6 +410,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { */ private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>> mPreciseDataConnectionStates; + + /** Per-phoneId snapshot of privileged packages (names + UIDs). */ + private List<Pair<List<String>, int[]>> mCarrierPrivilegeStates; + /** * Support backward compatibility for {@link android.telephony.TelephonyDisplayInfo}. */ @@ -689,6 +701,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { cutListToSize(mBarringInfo, mNumPhones); cutListToSize(mPhysicalChannelConfigs, mNumPhones); cutListToSize(mLinkCapacityEstimateLists, mNumPhones); + cutListToSize(mCarrierPrivilegeStates, mNumPhones); return; } @@ -729,6 +742,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); + mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } } @@ -794,6 +808,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; mLinkCapacityEstimateLists = new ArrayList<>(); + mCarrierPrivilegeStates = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; @@ -831,6 +846,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mAllowedNetworkTypeReason[i] = -1; mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, INVALID_LCE_LIST); + mCarrierPrivilegeStates.add(i, new Pair<>(Collections.emptyList(), new int[0])); } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -2766,6 +2782,104 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override + public void addCarrierPrivilegesListener( + int phoneId, + ICarrierPrivilegesListener callback, + String callingPackage, + String callingFeatureId) { + int callerUserId = UserHandle.getCallingUserId(); + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "addCarrierPrivilegesListener"); + if (VDBG) { + log( + "listen carrier privs: E pkg=" + pii(callingPackage) + " phoneId=" + phoneId + + " uid=" + Binder.getCallingUid() + + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId + + " callback=" + callback + + " callback.asBinder=" + callback.asBinder()); + } + if (!validatePhoneId(phoneId)) { + throw new IllegalArgumentException("Invalid slot index: " + phoneId); + } + + synchronized (mRecords) { + Record r = add( + callback.asBinder(), Binder.getCallingUid(), Binder.getCallingPid(), false); + + if (r == null) return; + + r.context = mContext; + r.carrierPrivilegesListener = callback; + r.callingPackage = callingPackage; + r.callingFeatureId = callingFeatureId; + r.callerUid = Binder.getCallingUid(); + r.callerPid = Binder.getCallingPid(); + r.phoneId = phoneId; + r.eventList = new ArraySet<>(); + if (DBG) { + log("listen carrier privs: Register r=" + r); + } + + Pair<List<String>, int[]> state = mCarrierPrivilegeStates.get(phoneId); + try { + r.carrierPrivilegesListener.onCarrierPrivilegesChanged( + Collections.unmodifiableList(state.first), + Arrays.copyOf(state.second, state.second.length)); + } catch (RemoteException ex) { + remove(r.binder); + } + } + } + + @Override + public void removeCarrierPrivilegesListener( + ICarrierPrivilegesListener callback, String callingPackage) { + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "removeCarrierPrivilegesListener"); + remove(callback.asBinder()); + } + + @Override + public void notifyCarrierPrivilegesChanged( + int phoneId, List<String> privilegedPackageNames, int[] privilegedUids) { + if (!checkNotifyPermission("notifyCarrierPrivilegesChanged")) { + return; + } + if (!validatePhoneId(phoneId)) return; + if (VDBG) { + log( + "notifyCarrierPrivilegesChanged: phoneId=" + phoneId + + ", <packages=" + pii(privilegedPackageNames) + + ", uids=" + Arrays.toString(privilegedUids) + ">"); + } + synchronized (mRecords) { + mCarrierPrivilegeStates.set( + phoneId, new Pair<>(privilegedPackageNames, privilegedUids)); + for (Record r : mRecords) { + // Listeners are per-slot, not per-subscription. This is to provide a stable + // view across SIM profile switches. + if (!r.matchCarrierPrivilegesListener() + || !idMatch(r, SubscriptionManager.INVALID_SUBSCRIPTION_ID, phoneId)) { + continue; + } + try { + // Make sure even in-process listeners can't modify the values. + r.carrierPrivilegesListener.onCarrierPrivilegesChanged( + Collections.unmodifiableList(privilegedPackageNames), + Arrays.copyOf(privilegedUids, privilegedUids.length)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + handleRemoveListLocked(); + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); @@ -2814,6 +2928,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs.get(i)); pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i)); + // We need to obfuscate package names, and primitive arrays' native toString is ugly + Pair<List<String>, int[]> carrierPrivilegeState = mCarrierPrivilegeStates.get(i); + pw.println( + "mCarrierPrivilegeState=<packages=" + pii(carrierPrivilegeState.first) + + ", uids=" + Arrays.toString(carrierPrivilegeState.second) + ">"); pw.decreaseIndent(); } @@ -3540,4 +3659,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private static String pii(String packageName) { return Build.IS_DEBUGGABLE ? packageName : "***"; } + + /** Redacts an entire list of package names if necessary. */ + private static String pii(List<String> packageNames) { + if (packageNames.isEmpty() || Build.IS_DEBUGGABLE) return packageNames.toString(); + return "[***, size=" + packageNames.size() + "]"; + } } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index ff480d1f614c..794b149bbde1 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -2872,29 +2872,18 @@ public class OomAdjuster { void setAttachingSchedGroupLSP(ProcessRecord app) { int initialSchedGroup = ProcessList.SCHED_GROUP_DEFAULT; final ProcessStateRecord state = app.mState; - // If the process has been marked as foreground via Zygote.START_FLAG_USE_TOP_APP_PRIORITY, - // then verify that the top priority is actually is applied. + // If the process has been marked as foreground, it is starting as the top app (with + // Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread. if (state.hasForegroundActivities()) { - String fallbackReason = null; try { // The priority must be the same as how does {@link #applyOomAdjLSP} set for // {@link ProcessList.SCHED_GROUP_TOP_APP}. We don't check render thread because it // is not ready when attaching. - if (Process.getProcessGroup(app.getPid()) == THREAD_GROUP_TOP_APP) { - app.getWindowProcessController().onTopProcChanged(); - setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST); - } else { - fallbackReason = "not expected top priority"; - } - } catch (Exception e) { - fallbackReason = e.toString(); - } - if (fallbackReason == null) { + app.getWindowProcessController().onTopProcChanged(); + setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST); initialSchedGroup = ProcessList.SCHED_GROUP_TOP_APP; - } else { - // The real scheduling group will depend on if there is any component of the process - // did something during attaching. - Slog.w(TAG, "Fallback pre-set sched group to default: " + fallbackReason); + } catch (Exception e) { + Slog.w(TAG, "Failed to pre-set top priority to " + app + " " + e); } } diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index b94cea4d5d40..55d0728d803e 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -783,7 +783,7 @@ public final class PlaybackActivityMonitor // the same time if we still have a public client. while (clientIterator.hasNext()) { PlayMonitorClient pmc = clientIterator.next(); - if (pcdb.equals(pmc.mDispatcherCb)) { + if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) { pmc.release(); clientIterator.remove(); } else { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 5de5fd3cc79c..dee69e02b371 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -2456,7 +2456,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { networkId, templateMeteredness, NetworkStats.ROAMING_ALL, NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL, NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule); - if (template.isPersistable()) { + if (NetworkPolicy.isTemplatePersistable(template)) { mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred)); @@ -2663,7 +2663,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = 0; i < mNetworkPolicy.size(); i++) { final NetworkPolicy policy = mNetworkPolicy.valueAt(i); final NetworkTemplate template = policy.template; - if (!template.isPersistable()) continue; + if (!NetworkPolicy.isTemplatePersistable(template)) continue; out.startTag(null, TAG_NETWORK_POLICY); writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule()); diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index 4a913e4edd71..cecbeed67f68 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -124,16 +124,10 @@ public final class SELinuxMMAC { } // Vendor mac permissions. - // The filename has been renamed from nonplat_mac_permissions to - // vendor_mac_permissions. Either of them should exist. final File vendorMacPermission = new File( Environment.getVendorDirectory(), "/etc/selinux/vendor_mac_permissions.xml"); if (vendorMacPermission.exists()) { sMacPermissions.add(vendorMacPermission); - } else { - // For backward compatibility. - sMacPermissions.add(new File(Environment.getVendorDirectory(), - "/etc/selinux/nonplat_mac_permissions.xml")); } // ODM mac permissions (optional). diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index d0457b08aa34..1108c7752777 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1498,11 +1498,15 @@ public class DisplayPolicy { statusBarBottom); } - sTmpRect.set(windowFrames.mFrame); - sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); - sTmpRect.top = windowFrames.mFrame.top; // Ignore top display cutout inset - sTmpRect.bottom = statusBarBottom; // Use collapsed status bar size - contentFrame.set(sTmpRect); + final InsetsState state = displayFrames.mInsetsState; + sTmpRect.set(displayFrames.mDisplayCutoutSafe); + // The status bar content can extend into regular display cutout insets but not + // waterfall insets. + sTmpRect.top = Math.max(state.getDisplayCutout().getWaterfallInsets().top, 0); + + contentFrame.set(windowFrames.mFrame); + contentFrame.intersect(sTmpRect); + contentFrame.bottom = statusBarBottom; // Use collapsed status bar size } private int layoutNavigationBar(DisplayFrames displayFrames, Rect contentFrame) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index bd688a618c63..52da4b80a75d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2125,6 +2125,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final Task rootTask; if (singleActivity) { rootTask = task; + + // Apply the last recents animation leash transform to the task entering PIP + rootTask.maybeApplyLastRecentsAnimationTransaction(); } else { // In the case of multiple activities, we will create a new task for it and then // move the PIP activity into the task. Note that we explicitly defer the task diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cae4f22f913f..dca0bacf1af7 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2787,7 +2787,15 @@ class Task extends WindowContainer<WindowContainer> { if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { - if (WindowConfiguration.isFloating(windowingMode)) { + // When entering to or exiting from Pip, the PipTaskOrganizer will set the + // windowing mode of the activity in the task to WINDOWING_MODE_FULLSCREEN and + // temporarily set the bounds of the task to fullscreen size for transitioning. + // It will get the wrong value if the calculation is based on this temporary + // fullscreen bounds. + // We should just inherit the value from parent for this temporary state. + final boolean inPipTransition = windowingMode == WINDOWING_MODE_PINNED + && !mTmpFullBounds.isEmpty() && mTmpFullBounds.equals(parentBounds); + if (WindowConfiguration.isFloating(windowingMode) && !inPipTransition) { // For floating tasks, calculate the smallest width from the bounds of the task inOutConfig.smallestScreenWidthDp = (int) ( Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); diff --git a/services/proguard.flags b/services/proguard.flags index 30dd6cf545b9..5d01d3e7f85c 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -1,11 +1,21 @@ # TODO(b/196084106): Refine and optimize this configuration. Note that this # configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`. -keep,allowoptimization,allowaccessmodification class ** { - *; + !synthetic *; } # Various classes subclassed in ethernet-service (avoid marking final). -keep public class android.net.** { *; } # Referenced via CarServiceHelperService in car-frameworks-service (avoid removing). --keep public class com.android.server.utils.Slogf { *; }
\ No newline at end of file +-keep public class com.android.server.utils.Slogf { *; } + +# Allows making private and protected methods/fields public as part of +# optimization. This enables inlining of trivial getter/setter methods. +-allowaccessmodification + +# Disallow accessmodification for soundtrigger classes. Logging via reflective +# public member traversal can cause infinite loops. See b/210901706. +-keep,allowoptimization class com.android.server.soundtrigger_middleware.** { + !synthetic *; +} diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java index e2d62f868d52..6d9b3210ea70 100644 --- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java +++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java @@ -17,7 +17,6 @@ package com.google.android.mms.util; -import android.app.ActivityManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; @@ -25,49 +24,15 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.net.Uri; -import android.os.Build; import android.util.Log; -import android.widget.Toast; public final class SqliteWrapper { private static final String TAG = "SqliteWrapper"; - private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE - = "unable to open database file"; private SqliteWrapper() { // Forbidden being instantiated. } - // FIXME: It looks like outInfo.lowMemory does not work well as we expected. - // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false. - private static boolean isLowMemory(Context context) { - if (null == context) { - return false; - } - - ActivityManager am = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo(); - am.getMemoryInfo(outInfo); - - return outInfo.lowMemory; - } - - // FIXME: need to optimize this method. - private static boolean isLowMemory(SQLiteException e) { - return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE); - } - - @UnsupportedAppUsage - public static void checkSQLiteException(Context context, SQLiteException e) { - if (isLowMemory(e)) { - Toast.makeText(context, com.android.internal.R.string.low_memory, - Toast.LENGTH_SHORT).show(); - } else { - throw e; - } - } - @UnsupportedAppUsage public static Cursor query(Context context, ContentResolver resolver, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { @@ -75,21 +40,10 @@ public final class SqliteWrapper { return resolver.query(uri, projection, selection, selectionArgs, sortOrder); } catch (SQLiteException e) { Log.e(TAG, "Catch a SQLiteException when query: ", e); - checkSQLiteException(context, e); return null; } } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean requery(Context context, Cursor cursor) { - try { - return cursor.requery(); - } catch (SQLiteException e) { - Log.e(TAG, "Catch a SQLiteException when requery: ", e); - checkSQLiteException(context, e); - return false; - } - } @UnsupportedAppUsage public static int update(Context context, ContentResolver resolver, Uri uri, ContentValues values, String where, String[] selectionArgs) { @@ -97,7 +51,6 @@ public final class SqliteWrapper { return resolver.update(uri, values, where, selectionArgs); } catch (SQLiteException e) { Log.e(TAG, "Catch a SQLiteException when update: ", e); - checkSQLiteException(context, e); return -1; } } @@ -109,7 +62,6 @@ public final class SqliteWrapper { return resolver.delete(uri, where, selectionArgs); } catch (SQLiteException e) { Log.e(TAG, "Catch a SQLiteException when delete: ", e); - checkSQLiteException(context, e); return -1; } } @@ -121,7 +73,6 @@ public final class SqliteWrapper { return resolver.insert(uri, values); } catch (SQLiteException e) { Log.e(TAG, "Catch a SQLiteException when insert: ", e); - checkSQLiteException(context, e); return null; } } diff --git a/telephony/java/android/service/carrier/CarrierService.java b/telephony/java/android/service/carrier/CarrierService.java index ca27998ec8a8..ae91d4d9b595 100644 --- a/telephony/java/android/service/carrier/CarrierService.java +++ b/telephony/java/android/service/carrier/CarrierService.java @@ -15,6 +15,8 @@ package android.service.carrier; import android.annotation.CallSuper; +import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -22,9 +24,12 @@ import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.os.ResultReceiver; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyRegistryManager; import android.util.Log; +import com.android.internal.util.ArrayUtils; + import java.io.FileDescriptor; import java.io.PrintWriter; @@ -87,7 +92,7 @@ public abstract class CarrierService extends Service { * PersistableBundle} may be overridden by the system's default configuration service. * </p> * - * @param id contains details about the current carrier that can be used do decide what + * @param id contains details about the current carrier that can be used to decide what * configuration values to return. Instead of using details like MCCMNC to decide * current carrier, it also contains subscription carrier id * {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide @@ -95,10 +100,61 @@ public abstract class CarrierService extends Service { * id as the key to look up the carrier info. * @return a {@link PersistableBundle} object containing the configuration or null if default * values should be used. + * @deprecated use {@link #onLoadConfig(int, CarrierIdentifier)} instead. */ + @Deprecated public abstract PersistableBundle onLoadConfig(CarrierIdentifier id); /** + * Override this method to set carrier configuration on the given {@code subscriptionId}. + * <p> + * This method will be called by telephony services to get carrier-specific configuration + * values. The returned config will be saved by the system until, + * <ol> + * <li>The carrier app package is updated, or</li> + * <li>The carrier app requests a reload with + * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId + * notifyConfigChangedForSubId}.</li> + * </ol> + * This method can be called after a SIM card loads, which may be before or after boot. + * </p> + * <p> + * This method should not block for a long time. If expensive operations (e.g. network access) + * are required, this method can schedule the work and return null. Then, use + * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId + * notifyConfigChangedForSubId} to trigger a reload when the config is ready. + * </p> + * <p> + * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager + * CarrierConfigManager}. Any configuration values not set in the returned {@link + * PersistableBundle} may be overridden by the system's default configuration service. + * </p> + * <p> + * By default, this method just calls {@link #onLoadConfig(CarrierIdentifier)} with specified + * CarrierIdentifier {@code id}. Carrier app with target SDK + * {@link android.os.Build.VERSION_CODES#TIRAMISU} and above should override this method to + * load carrier configuration on the given {@code subscriptionId}. + * Note that {@link #onLoadConfig(CarrierIdentifier)} is still called prior to + * {@link android.os.Build.VERSION_CODES#TIRAMISU}. + * </p> + * + * @param subscriptionId the subscription on which the carrier app should load configuration + * @param id contains details about the current carrier that can be used to decide what + * configuration values to return. Instead of using details like MCCMNC to decide + * current carrier, it also contains subscription carrier id + * {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide + * unique identifier for each carrier, CarrierConfigService can directly use carrier + * id as the key to look up the carrier info. + * @return a {@link PersistableBundle} object containing the configuration or null if default + * values should be used. + */ + @SuppressLint("NullableCollection") + @Nullable + public PersistableBundle onLoadConfig(int subscriptionId, @Nullable CarrierIdentifier id) { + return onLoadConfig(id); + } + + /** * Informs the system of an intentional upcoming carrier network change by * a carrier app. This call is optional and is only used to allow the * system to provide alternative UI while telephony is performing an action @@ -179,10 +235,16 @@ public abstract class CarrierService extends Service { public static final String KEY_CONFIG_BUNDLE = "config_bundle"; @Override - public void getCarrierConfig(CarrierIdentifier id, ResultReceiver result) { + public void getCarrierConfig(int phoneId, CarrierIdentifier id, ResultReceiver result) { try { + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + int[] subIds = SubscriptionManager.getSubId(phoneId); + if (!ArrayUtils.isEmpty(subIds)) { + // There should be at most one active subscription mapping to the phoneId. + subId = subIds[0]; + } Bundle data = new Bundle(); - data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(id)); + data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(subId, id)); result.send(RESULT_OK, data); } catch (Exception e) { Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e); diff --git a/telephony/java/android/service/carrier/ICarrierService.aidl b/telephony/java/android/service/carrier/ICarrierService.aidl index ac6f9614d8f5..054a280c3fe8 100644 --- a/telephony/java/android/service/carrier/ICarrierService.aidl +++ b/telephony/java/android/service/carrier/ICarrierService.aidl @@ -29,5 +29,5 @@ import android.service.carrier.CarrierIdentifier; interface ICarrierService { /** @see android.service.carrier.CarrierService#onLoadConfig */ - oneway void getCarrierConfig(in CarrierIdentifier id, in ResultReceiver result); + oneway void getCarrierConfig(in int phoneId, in CarrierIdentifier id, in ResultReceiver result); } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 95b9fda34211..5851ee182368 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -964,6 +964,21 @@ public class CarrierConfigManager { = "carrier_use_ims_first_for_emergency_bool"; /** + * When {@code true}, the determination of whether to place a call as an emergency call will be + * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which + * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers + * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, + * it will not be treated as an emergency call in this case. + * When {@code false}, the determination is based on the emergency numbers from all device SIMs, + * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers + * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, + * the call will be dialed as an emergency number, but with an unspecified routing. + * @hide + */ + public static final String KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL = + "use_only_dialed_sim_ecc_list_bool"; + + /** * When IMS instant lettering is available for a carrier (see * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters * which may not be contained in messages. Should be specified as a regular expression suitable @@ -5339,6 +5354,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true); + sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, ""); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 6286390ba139..30cb8ca64ad3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -70,6 +70,7 @@ import android.os.SystemProperties; import android.os.WorkSource; import android.provider.Settings.SettingNotFoundException; import android.service.carrier.CarrierIdentifier; +import android.service.carrier.CarrierService; import android.sysprop.TelephonyProperties; import android.telecom.CallScreeningService; import android.telecom.InCallService; @@ -9178,6 +9179,57 @@ public class TelephonyManager { return null; } + /** + * Returns the package name that provides the {@link CarrierService} implementation for the + * current subscription, or {@code null} if no package with carrier privileges declares one. + * + * <p>If this object has been created with {@link #createForSubscriptionId}, then the provided + * subscription ID is used. Otherwise, the default subscription ID will be used. + * + * @return The system-selected package that provides the {@link CarrierService} implementation + * for the current subscription, or {@code null} if none is resolved + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public @Nullable String getCarrierServicePackageName() { + // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the + // value instead of re-querying every time. + List<String> carrierServicePackages = + getCarrierPackageNamesForIntent( + new Intent(CarrierService.CARRIER_SERVICE_INTERFACE)); + if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) { + return carrierServicePackages.get(0); + } + return null; + } + + /** + * Returns the package name that provides the {@link CarrierService} implementation for the + * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges + * declares one. + * + * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for + * @return The system-selected package that provides the {@link CarrierService} implementation + * for the slot, or {@code null} if none is resolved + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { + // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the + // value instead of re-querying every time. + List<String> carrierServicePackages = + getCarrierPackageNamesForIntentAndPhone( + new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex); + if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) { + return carrierServicePackages.get(0); + } + return null; + } + /** @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public List<String> getPackagesWithCarrierPrivileges() { @@ -15976,4 +16028,76 @@ public class TelephonyManager { } return null; } + + /** + * Callback to listen for when the set of packages with carrier privileges for a SIM changes. + * + * @hide + */ + @SystemApi + public interface CarrierPrivilegesListener { + /** + * Called when the set of packages with carrier privileges has changed. + * + * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile + * switch and the same set of packages remains privileged after the switch. + * + * <p>At registration, the callback will receive the current set of privileged packages. + * + * @param privilegedPackageNames The updated set of package names that have carrier + * privileges + * @param privilegedUids The updated set of UIDs that have carrier privileges + */ + void onCarrierPrivilegesChanged( + @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids); + } + + /** + * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to + * receive callbacks when the set of packages with carrier privileges changes. The callback will + * immediately be called with the latest state. + * + * @param logicalSlotIndex The SIM slot to listen on + * @param executor The executor where {@code listener} will be invoked + * @param listener The callback to register + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void addCarrierPrivilegesListener( + int logicalSlotIndex, + @NonNull @CallbackExecutor Executor executor, + @NonNull CarrierPrivilegesListener listener) { + if (mContext == null) { + throw new IllegalStateException("Telephony service is null"); + } else if (executor == null || listener == null) { + throw new IllegalArgumentException( + "CarrierPrivilegesListener and executor must be non-null"); + } + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr == null) { + throw new IllegalStateException("Telephony registry service is null"); + } + mTelephonyRegistryMgr.addCarrierPrivilegesListener(logicalSlotIndex, executor, listener); + } + + /** + * Unregisters an existing {@link CarrierPrivilegesListener}. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { + if (mContext == null) { + throw new IllegalStateException("Telephony service is null"); + } else if (listener == null) { + throw new IllegalArgumentException("CarrierPrivilegesListener must be non-null"); + } + mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); + if (mTelephonyRegistryMgr == null) { + throw new IllegalStateException("Telephony registry service is null"); + } + mTelephonyRegistryMgr.removeCarrierPrivilegesListener(listener); + } } diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java index 9293a40d9a33..7a1a2af060d2 100644 --- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -93,8 +93,8 @@ public interface CapabilityExchangeEventListener { * Notify the framework that the ImsService has refreshed the PUBLISH * internally, which has resulted in a new PUBLISH result. * <p> - * This method must return both SUCCESS (200 OK) and FAILURE (300+) codes in order to - * keep the AOSP stack up to date. + * This method must be called to notify the framework of SUCCESS (200 OK) and FAILURE (300+) + * codes in order to keep the AOSP stack up to date. * @param reasonCode The SIP response code sent from the network. * @param reasonPhrase The optional reason response from the network. If the * network provided no reason with the sip code, the string should be empty. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 03010f6b27b6..55778883edde 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2526,4 +2526,14 @@ interface ITelephony { */ CellIdentity getLastKnownCellIdentity(int subId, String callingPackage, String callingFeatureId); + + /** + * @return true if the modem service is set successfully, false otherwise. + */ + boolean setModemService(in String serviceName); + + /** + * @return the service name of the modem service which bind to. + */ + String getModemService(); } |