diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index fe0890185228f..4208cbf4f9ea3 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -84,7 +84,9 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; - +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; /** * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} * lets you perform fundamental Bluetooth tasks, such as initiate @@ -2003,7 +2005,21 @@ public boolean setActiveDevice(@NonNull BluetoothDevice device, return false; } - + /** @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public boolean isBroadcastActive() { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isBroadcastActive(); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } /** * Connects all enabled and supported bluetooth profiles between the local and remote device. * Connection is asynchronous and you should listen to each profile's broadcast intent @@ -3056,6 +3072,8 @@ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener } else if (profile == BluetoothProfile.HID_DEVICE) { BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this); return true; + } else if (profile == BluetoothProfile.BROADCAST) { + return getBroadcastProfile(context, listener); } else if (profile == BluetoothProfile.HEARING_AID) { if (isHearingAidProfileSupported()) { BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this); @@ -3153,6 +3171,9 @@ public void closeProfileProxy(int profile, BluetoothProfile proxy) { BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; hidDevice.close(); break; + case BluetoothProfile.BROADCAST: + closeBroadcastProfile(proxy); + break; case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); @@ -3168,6 +3189,62 @@ public void closeProfileProxy(int profile, BluetoothProfile proxy) { } } + private boolean getBroadcastProfile(Context context, + BluetoothProfile.ServiceListener listener) { + boolean ret = true; + Class broadcastClass = null; + Constructor bcastConstructor = null; + Object broadcastObj = null; + try { + broadcastClass = Class.forName("android.bluetooth.BluetoothBroadcast"); + } catch (ClassNotFoundException ex) { + Log.e(TAG, "no BluetoothBroadcast: exists"); + } + if (broadcastClass != null) { + try { + bcastConstructor = + broadcastClass.getDeclaredConstructor(new Class[]{Context.class, + BluetoothProfile.ServiceListener.class}); + } catch (NoSuchMethodException ex) { + Log.e(TAG, "bcastConstructor: NoSuchMethodException: gdm" + ex); + } + } + if (bcastConstructor != null) { + try { + broadcastObj = bcastConstructor.newInstance(context, listener); + } catch (InstantiationException | IllegalAccessException | + InvocationTargetException ex) { + ex.printStackTrace(); + } + } + if (broadcastObj == null) { + return false; + } + return true; + } + private void closeBroadcastProfile(BluetoothProfile proxy) { + Class broadcastClass = null; + Method broadcastClose = null; + try { + broadcastClass = Class.forName("android.bluetooth.BluetootBroadcast"); + } catch (ClassNotFoundException ex) { + Log.e(TAG, "no BluetoothBroadcast: exists"); + } + if (broadcastClass != null) { + try { + broadcastClose = broadcastClass.getDeclaredMethod("close", null); + } catch (NoSuchMethodException e) { + Log.e(TAG, "no Broadcast:close method exists"); + } + if (broadcastClose != null) { + try { + broadcastClose.invoke(proxy, null); + } catch(IllegalAccessException | InvocationTargetException ex) { + ex.printStackTrace(); + } + } + } + } private static final IBluetoothManagerCallback sManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 000819f794fef..1c1b264025410 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -218,13 +218,18 @@ public interface BluetoothProfile { */ public int GROUP_CLIENT = 23; + /** + * Broadcast + * @hide + */ + public int BROADCAST = 24; /** * Max profile ID. This value should be updated whenever a new profile is added to match * the largest value assigned to a profile. * * @hide */ - int MAX_PROFILE_ID = 23; + int MAX_PROFILE_ID = 24; /** * Default priority for devices that we try to auto-connect to and @@ -422,6 +427,8 @@ static String getProfileName(int profile) { return "OPP"; case HEARING_AID: return "HEARING_AID"; + case BROADCAST: + return "BROADCAST"; default: return "UNKNOWN_PROFILE"; } diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java index 3642e4dccf34b..2003ebec4a150 100644 --- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java +++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java @@ -83,7 +83,8 @@ public void onServiceDisconnected(int profile) { @VisibleForTesting public boolean isA2dpOrHearingAidConnected() { - return isA2dpConnected() || isHearingAidConnected(); + return isA2dpConnected() || isHearingAidConnected() || + isBroadcastActive(); } @VisibleForTesting @@ -142,4 +143,8 @@ private boolean isHearingAidConnected() { } return hearingAid.getConnectedDevices().size() > 0; } + + private boolean isBroadcastActive() { + return mAdapter.isBroadcastActive(); + } }