Loading android/app/aidl/android/bluetooth/IBluetooth.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -325,6 +325,12 @@ interface IBluetooth @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int getActiveAudioDevicePolicy(in BluetoothDevice device, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int setMicrophonePreferredForCalls(in BluetoothDevice device, in boolean enabled, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") boolean isMicrophonePreferredForCalls(in BluetoothDevice device, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)") oneway void killBluetoothProcess(); } android/app/src/com/android/bluetooth/btservice/AdapterService.java +49 −0 Original line number Diff line number Diff line Loading @@ -4327,6 +4327,55 @@ public class AdapterService extends Service { service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.getActiveAudioDevicePolicy(device); } @Override public int setMicrophonePreferredForCalls( BluetoothDevice device, boolean enabled, AttributionSource source) { requireNonNull(device); AdapterService service = getService(); if (service == null) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } if (!callerIsSystemOrActiveOrManagedUser( service, TAG, "setMicrophonePreferredForCalls")) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; } if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { throw new IllegalArgumentException("device cannot have an invalid address"); } if (!Utils.checkConnectPermissionForDataDelivery( service, source, "AdapterService setMicrophonePreferredForCalls")) { return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.setMicrophonePreferredForCalls(device, enabled); } @Override public boolean isMicrophonePreferredForCalls( BluetoothDevice device, AttributionSource source) { requireNonNull(device); AdapterService service = getService(); if (service == null) { return true; } if (!callerIsSystemOrActiveOrManagedUser( service, TAG, "isMicrophonePreferredForCalls")) { throw new IllegalStateException( "Caller is not the system or part of the active/managed user"); } if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { throw new IllegalArgumentException("device cannot have an invalid address"); } if (!Utils.checkConnectPermissionForDataDelivery( service, source, "AdapterService isMicrophonePreferredForCalls")) { return true; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.isMicrophonePreferredForCalls(device); } } /** Loading android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java +50 −0 Original line number Diff line number Diff line Loading @@ -1092,6 +1092,56 @@ public class DatabaseManager { } } /** * Sets the preferred microphone for calls enable status for this device. See {@link * BluetoothDevice#setMicrophonePreferredForCalls()} for more details. * * @param device is the remote device for which we set the preferred microphone for calls enable * status * @param enabled {@code true} to enable the preferred microphone for calls * @return whether the preferred microphone for call enable status was set properly */ public int setMicrophonePreferredForCalls(BluetoothDevice device, boolean enabled) { synchronized (mMetadataCache) { String address = device.getAddress(); if (!mMetadataCache.containsKey(address)) { Log.e(TAG, "device is not bonded"); return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; } Metadata metadata = mMetadataCache.get(address); Log.i(TAG, "setMicrophoneForCallEnabled(" + device + ", " + enabled + ")"); metadata.is_preferred_microphone_for_calls = enabled; updateDatabase(metadata); } return BluetoothStatusCodes.SUCCESS; } /** * Gets the preferred microphone for calls enable status for this device. See {@link * BluetoothDevice#isMicrophonePreferredForCalls()} for more details. * * @param device is the remote device for which we get the preferred microphone for calls enable * status * @return {@code true} if the preferred microphone is enabled for calls */ public boolean isMicrophonePreferredForCalls(BluetoothDevice device) { synchronized (mMetadataCache) { String address = device.getAddress(); if (!mMetadataCache.containsKey(address)) { Log.e(TAG, "device is not bonded"); return true; } Metadata metadata = mMetadataCache.get(address); return metadata.is_preferred_microphone_for_calls; } } /** * Get the {@link Looper} for the handler thread. This is used in testing and helper objects * Loading android/app/src/com/android/bluetooth/btservice/storage/Metadata.java +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,9 @@ public class Metadata { /** This is used to indicate whether device's active audio policy */ public int active_audio_device_policy; /** This is used to indicate whether device's microphone prefer to use during calls */ public boolean is_preferred_microphone_for_calls; Metadata(String address) { this(address, false, false); } Loading @@ -91,6 +94,7 @@ public class Metadata { preferred_output_only_profile = 0; preferred_duplex_profile = 0; active_audio_device_policy = BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; is_preferred_microphone_for_calls = true; } static final class Builder { Loading Loading @@ -470,6 +474,8 @@ public class Metadata { .append(publicMetadata) .append("), hfp client audio policy(") .append(audioPolicyMetadata) .append("), is_preferred_microphone_for_calls(") .append(is_preferred_microphone_for_calls) .append(")}"); return builder.toString(); Loading android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java +22 −0 Original line number Diff line number Diff line Loading @@ -671,4 +671,26 @@ public abstract class MetadataDatabase extends RoomDatabase { } } }; @VisibleForTesting static final Migration MIGRATION_120_121 = new Migration(120, 121) { @Override public void migrate(SupportSQLiteDatabase database) { try { database.execSQL( "ALTER TABLE metadata ADD COLUMN" + " `is_preferred_microphone_for_calls` INTEGER NOT NULL" + " DEFAULT 1"); } catch (SQLException ex) { // Check if user has new schema, but is just missing the version update Cursor cursor = database.query("SELECT * FROM metadata"); if (cursor == null || cursor.getColumnIndex("is_preferred_microphone_for_calls") == -1) { throw ex; } } } }; } Loading
android/app/aidl/android/bluetooth/IBluetooth.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -325,6 +325,12 @@ interface IBluetooth @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int getActiveAudioDevicePolicy(in BluetoothDevice device, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") int setMicrophonePreferredForCalls(in BluetoothDevice device, in boolean enabled, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})") boolean isMicrophonePreferredForCalls(in BluetoothDevice device, in AttributionSource source); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)") oneway void killBluetoothProcess(); }
android/app/src/com/android/bluetooth/btservice/AdapterService.java +49 −0 Original line number Diff line number Diff line Loading @@ -4327,6 +4327,55 @@ public class AdapterService extends Service { service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.getActiveAudioDevicePolicy(device); } @Override public int setMicrophonePreferredForCalls( BluetoothDevice device, boolean enabled, AttributionSource source) { requireNonNull(device); AdapterService service = getService(); if (service == null) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } if (!callerIsSystemOrActiveOrManagedUser( service, TAG, "setMicrophonePreferredForCalls")) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED; } if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { throw new IllegalArgumentException("device cannot have an invalid address"); } if (!Utils.checkConnectPermissionForDataDelivery( service, source, "AdapterService setMicrophonePreferredForCalls")) { return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.setMicrophonePreferredForCalls(device, enabled); } @Override public boolean isMicrophonePreferredForCalls( BluetoothDevice device, AttributionSource source) { requireNonNull(device); AdapterService service = getService(); if (service == null) { return true; } if (!callerIsSystemOrActiveOrManagedUser( service, TAG, "isMicrophonePreferredForCalls")) { throw new IllegalStateException( "Caller is not the system or part of the active/managed user"); } if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) { throw new IllegalArgumentException("device cannot have an invalid address"); } if (!Utils.checkConnectPermissionForDataDelivery( service, source, "AdapterService isMicrophonePreferredForCalls")) { return true; } service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null); return service.mDatabaseManager.isMicrophonePreferredForCalls(device); } } /** Loading
android/app/src/com/android/bluetooth/btservice/storage/DatabaseManager.java +50 −0 Original line number Diff line number Diff line Loading @@ -1092,6 +1092,56 @@ public class DatabaseManager { } } /** * Sets the preferred microphone for calls enable status for this device. See {@link * BluetoothDevice#setMicrophonePreferredForCalls()} for more details. * * @param device is the remote device for which we set the preferred microphone for calls enable * status * @param enabled {@code true} to enable the preferred microphone for calls * @return whether the preferred microphone for call enable status was set properly */ public int setMicrophonePreferredForCalls(BluetoothDevice device, boolean enabled) { synchronized (mMetadataCache) { String address = device.getAddress(); if (!mMetadataCache.containsKey(address)) { Log.e(TAG, "device is not bonded"); return BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED; } Metadata metadata = mMetadataCache.get(address); Log.i(TAG, "setMicrophoneForCallEnabled(" + device + ", " + enabled + ")"); metadata.is_preferred_microphone_for_calls = enabled; updateDatabase(metadata); } return BluetoothStatusCodes.SUCCESS; } /** * Gets the preferred microphone for calls enable status for this device. See {@link * BluetoothDevice#isMicrophonePreferredForCalls()} for more details. * * @param device is the remote device for which we get the preferred microphone for calls enable * status * @return {@code true} if the preferred microphone is enabled for calls */ public boolean isMicrophonePreferredForCalls(BluetoothDevice device) { synchronized (mMetadataCache) { String address = device.getAddress(); if (!mMetadataCache.containsKey(address)) { Log.e(TAG, "device is not bonded"); return true; } Metadata metadata = mMetadataCache.get(address); return metadata.is_preferred_microphone_for_calls; } } /** * Get the {@link Looper} for the handler thread. This is used in testing and helper objects * Loading
android/app/src/com/android/bluetooth/btservice/storage/Metadata.java +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,9 @@ public class Metadata { /** This is used to indicate whether device's active audio policy */ public int active_audio_device_policy; /** This is used to indicate whether device's microphone prefer to use during calls */ public boolean is_preferred_microphone_for_calls; Metadata(String address) { this(address, false, false); } Loading @@ -91,6 +94,7 @@ public class Metadata { preferred_output_only_profile = 0; preferred_duplex_profile = 0; active_audio_device_policy = BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; is_preferred_microphone_for_calls = true; } static final class Builder { Loading Loading @@ -470,6 +474,8 @@ public class Metadata { .append(publicMetadata) .append("), hfp client audio policy(") .append(audioPolicyMetadata) .append("), is_preferred_microphone_for_calls(") .append(is_preferred_microphone_for_calls) .append(")}"); return builder.toString(); Loading
android/app/src/com/android/bluetooth/btservice/storage/MetadataDatabase.java +22 −0 Original line number Diff line number Diff line Loading @@ -671,4 +671,26 @@ public abstract class MetadataDatabase extends RoomDatabase { } } }; @VisibleForTesting static final Migration MIGRATION_120_121 = new Migration(120, 121) { @Override public void migrate(SupportSQLiteDatabase database) { try { database.execSQL( "ALTER TABLE metadata ADD COLUMN" + " `is_preferred_microphone_for_calls` INTEGER NOT NULL" + " DEFAULT 1"); } catch (SQLException ex) { // Check if user has new schema, but is just missing the version update Cursor cursor = database.query("SELECT * FROM metadata"); if (cursor == null || cursor.getColumnIndex("is_preferred_microphone_for_calls") == -1) { throw ex; } } } }; }