Loading android/app/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,7 @@ android_app { "-Xep:OperatorPrecedence:ERROR", "-Xep:ReferenceEquality:ERROR", "-Xep:ReturnAtTheEndOfVoidFunction:ERROR", "-Xep:StaticAssignmentInConstructor:ERROR", "-Xep:StaticGuardedByInstance:ERROR", "-Xep:StringCaseLocaleUsage:ERROR", "-Xep:StringCharset:ERROR", Loading android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java +24 −22 Original line number Diff line number Diff line Loading @@ -63,8 +63,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { @VisibleForTesting static final int AVRCP_MAX_VOL = 127; private static final int STREAM_MUSIC = AudioManager.STREAM_MUSIC; private static final int VOLUME_CHANGE_LOGGER_SIZE = 30; private static int sDeviceMaxVolume = 0; private static int sNewDeviceVolume = 0; private final int mDeviceMaxVolume; private final int mNewDeviceVolume; private final BluetoothEventLogger mVolumeEventLogger = new BluetoothEventLogger(VOLUME_CHANGE_LOGGER_SIZE, VOLUME_CHANGE_LOG_TITLE); Loading @@ -75,7 +75,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { // Absolute volume support map. HashMap<BluetoothDevice, Boolean> mDeviceMap = new HashMap(); // Volume stored is system volume (0 - {@code sDeviceMaxVolume}). // Volume stored is system volume (0 - {@code mDeviceMaxVolume}). HashMap<BluetoothDevice, Integer> mVolumeMap = new HashMap(); BluetoothDevice mCurrentDevice = null; Loading @@ -83,23 +83,25 @@ class AvrcpVolumeManager extends AudioDeviceCallback { /** * Converts given {@code avrcpVolume} (0 - 127) to equivalent in system volume (0 - {@code * sDeviceMaxVolume}). * mDeviceMaxVolume}). * * <p>Max system volume is retrieved from {@link AudioManager}. */ static int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.round((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); @VisibleForTesting int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.round((double) avrcpVolume * mDeviceMaxVolume / AVRCP_MAX_VOL); } /** * Converts given {@code deviceVolume} (0 - {@code sDeviceMaxVolume}) to equivalent in AVRCP * Converts given {@code deviceVolume} (0 - {@code mDeviceMaxVolume}) to equivalent in AVRCP * volume (0 - 127). * * <p>Max system volume is retrieved from {@link AudioManager}. */ static int systemToAvrcpVolume(int deviceVolume) { @VisibleForTesting int systemToAvrcpVolume(int deviceVolume) { int avrcpVolume = (int) Math.round((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); (int) Math.round((double) deviceVolume * AVRCP_MAX_VOL / mDeviceMaxVolume); if (avrcpVolume > 127) avrcpVolume = 127; return avrcpVolume; } Loading Loading @@ -149,7 +151,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { }); // Get the current system volume and try to get the preference volume int savedVolume = getVolume(device, sNewDeviceVolume); int savedVolume = getVolume(device, mNewDeviceVolume); d("switchVolumeDevice: savedVolume=" + savedVolume); Loading @@ -175,8 +177,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { mAdapterService = adapterService; mAudioManager = audioManager; mNativeInterface = nativeInterface; sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); sNewDeviceVolume = sDeviceMaxVolume / 2; mDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); mNewDeviceVolume = mDeviceMaxVolume / 2; mAudioManager.registerAudioDeviceCallback(this, null); Loading @@ -202,7 +204,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Stores system volume (0 - {@code sDeviceMaxVolume}) for device in {@code mVolumeMap} and * Stores system volume (0 - {@code mDeviceMaxVolume}) for device in {@code mVolumeMap} and * writes the map in the {@link SharedPreferences}. */ synchronized void storeVolumeForDevice(@NonNull BluetoothDevice device, int storeVolume) { Loading @@ -224,7 +226,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Retrieves system volume (0 - {@code sDeviceMaxVolume}) and calls {@link * Retrieves system volume (0 - {@code mDeviceMaxVolume}) and calls {@link * #storeVolumeForDevice(BluetoothDevice, int)} with {@code device}. */ synchronized void storeVolumeForDevice(@NonNull BluetoothDevice device) { Loading @@ -251,7 +253,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Returns system volume (0 - {@code sDeviceMaxVolume}) stored in {@code mVolumeMap} for * Returns system volume (0 - {@code mDeviceMaxVolume}) stored in {@code mVolumeMap} for * corresponding {@code device}. * * @param defaultValue Value to return if device is not in the map. Loading @@ -266,9 +268,9 @@ class AvrcpVolumeManager extends AudioDeviceCallback { return mVolumeMap.get(device); } /** Returns the system volume (0 - {@code sDeviceMaxVolume}) applied to a new device */ /** Returns the system volume (0 - {@code mDeviceMaxVolume}) applied to a new device */ public int getNewDeviceVolume() { return sNewDeviceVolume; return mNewDeviceVolume; } /** Loading @@ -289,8 +291,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { + avrcpVolume + " deviceVolume=" + deviceVolume + " sDeviceMaxVolume=" + sDeviceMaxVolume); + " mDeviceMaxVolume=" + mDeviceMaxVolume); mAudioManager.setStreamVolume( AudioManager.STREAM_MUSIC, deviceVolume, Loading @@ -304,7 +306,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { * * <p>See {@link #systemToAvrcpVolume}. * * @param deviceVolume in range (0 - {@code sDeviceMaxVolume}) received from system. * @param deviceVolume in range (0 - {@code mDeviceMaxVolume}) received from system. */ void sendVolumeChanged(@NonNull BluetoothDevice device, int deviceVolume) { if (deviceVolume == getVolume(device, -1)) { Loading @@ -321,8 +323,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { + avrcpVolume + " deviceVolume=" + deviceVolume + " sDeviceMaxVolume=" + sDeviceMaxVolume); + " mDeviceMaxVolume=" + mDeviceMaxVolume); mNativeInterface.sendVolumeChanged(device, avrcpVolume); storeVolumeForDevice(device); } Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +63 −23 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.content.pm.PackageManager.FEATURE_WATCH; import static java.util.Objects.requireNonNull; import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; Loading @@ -46,6 +48,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -65,6 +68,12 @@ import java.util.UUID; public class HeadsetClientService extends ProfileService { private static final String TAG = HeadsetClientService.class.getSimpleName(); // Maximum number of devices we can try connecting to in one session private static final int MAX_STATE_MACHINES_POSSIBLE = 100; @VisibleForTesting static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec. @VisibleForTesting static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec. // This is also used as a lock for shared data in {@link HeadsetClientService} @GuardedBy("mStateMachineMap") private final HashMap<BluetoothDevice, HeadsetClientStateMachine> mStateMachineMap = Loading @@ -74,19 +83,26 @@ public class HeadsetClientService extends ProfileService { private NativeInterface mNativeInterface = null; private HandlerThread mSmThread = null; private HeadsetClientStateMachineFactory mSmFactory = null; private DatabaseManager mDatabaseManager; private AudioManager mAudioManager = null; private final AdapterService mAdapterService; private final DatabaseManager mDatabaseManager; private final AudioManager mAudioManager; private BatteryManager mBatteryManager = null; private int mLastBatteryLevel = -1; // Maximum number of devices we can try connecting to in one session private static final int MAX_STATE_MACHINES_POSSIBLE = 100; private final int mMaxAmVcVol; private final int mMinAmVcVol; private final Object mStartStopLock = new Object(); public static final String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag"; public HeadsetClientService(Context ctx) { super(ctx); public HeadsetClientService(AdapterService adapterService) { super(requireNonNull(adapterService)); mAdapterService = adapterService; mDatabaseManager = requireNonNull(adapterService.getDatabase()); mAudioManager = requireNonNull(getSystemService(AudioManager.class)); mMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL); mMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL); } public static boolean isEnabled() { Loading @@ -106,24 +122,14 @@ public class HeadsetClientService extends ProfileService { throw new IllegalStateException("start() called twice"); } mDatabaseManager = Objects.requireNonNull( AdapterService.getAdapterService().getDatabase(), "DatabaseManager cannot be null when HeadsetClientService starts"); // Setup the JNI service mNativeInterface = NativeInterface.getInstance(); mNativeInterface.initialize(); mBatteryManager = getSystemService(BatteryManager.class); mAudioManager = getSystemService(AudioManager.class); if (mAudioManager == null) { Log.e(TAG, "AudioManager service doesn't exist?"); } else { // start AudioManager in a known state mAudioManager.setHfpEnabled(false); } mSmFactory = new HeadsetClientStateMachineFactory(); synchronized (mStateMachineMap) { Loading Loading @@ -192,6 +198,42 @@ public class HeadsetClientService extends ProfileService { } } int hfToAmVol(int hfVol) { int amRange = mMaxAmVcVol - mMinAmVcVol; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int amVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { amVol = (int) Math.round( (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME) * ((double) amRange / hfRange)) + mMinAmVcVol; } else { int amOffset = (amRange * (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME)) / hfRange; amVol = mMinAmVcVol + amOffset; } Log.d(TAG, "HF -> AM " + hfVol + " " + amVol); return amVol; } @VisibleForTesting int amToHfVol(int amVol) { int amRange = (mMaxAmVcVol > mMinAmVcVol) ? (mMaxAmVcVol - mMinAmVcVol) : 1; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int hfVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { hfVol = (int) Math.round((amVol - mMinAmVcVol) * ((double) hfRange / amRange)) + MIN_HFP_SCO_VOICE_CALL_VOLUME; } else { int hfOffset = (hfRange * (amVol - mMinAmVcVol)) / amRange; hfVol = MIN_HFP_SCO_VOICE_CALL_VOLUME + hfOffset; } Log.d(TAG, "AM -> HF " + amVol + " " + hfVol); return hfVol; } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override Loading @@ -214,7 +256,7 @@ public class HeadsetClientService extends ProfileService { if (streamType == AudioManager.STREAM_VOICE_CALL) { int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); int hfVol = HeadsetClientStateMachine.amToHfVol(streamValue); int hfVol = amToHfVol(streamValue); Log.d( TAG, "Setting volume to audio manager: " Loading Loading @@ -1265,7 +1307,7 @@ public class HeadsetClientService extends ProfileService { // Allocate a new SM Log.d(TAG, "Creating a new state machine"); sm = mSmFactory.make(this, mSmThread, mNativeInterface); sm = mSmFactory.make(mAdapterService, this, mSmThread, mNativeInterface); mStateMachineMap.put(device, sm); return sm; } Loading Loading @@ -1295,9 +1337,7 @@ public class HeadsetClientService extends ProfileService { } void handleBatteryLevelChanged(BluetoothDevice device, int batteryLevel) { AdapterService.getAdapterService() .getRemoteDevices() .handleAgBatteryLevelChanged(device, batteryLevel); mAdapterService.getRemoteDevices().handleAgBatteryLevelChanged(device, batteryLevel); } @Override Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +14 −62 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.flags.Flags; import com.android.bluetooth.hfp.HeadsetService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IState; Loading Loading @@ -118,9 +117,6 @@ public class HeadsetClientStateMachine extends StateMachine { @VisibleForTesting static final int CONNECTING_TIMEOUT_MS = 10000; // 10s private static final int ROUTING_DELAY_MS = 250; @VisibleForTesting static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec. @VisibleForTesting static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec. static final int HF_ORIGINATED_CALL_ID = -1; private static final long OUTGOING_TIMEOUT_MILLI = 10 * 1000; // 10 seconds private static final long QUERY_CURRENT_CALLS_WAIT_MILLIS = 2 * 1000; // 2 seconds Loading @@ -134,6 +130,7 @@ public class HeadsetClientStateMachine extends StateMachine { private final AudioOn mAudioOn; private State mPrevState; private final AdapterService mAdapterService; private final HeadsetClientService mService; private final HeadsetService mHeadsetService; Loading @@ -153,9 +150,6 @@ public class HeadsetClientStateMachine extends StateMachine { private String mOperatorName; @VisibleForTesting String mSubscriberInfo; private static int sMaxAmVcVol; private static int sMinAmVcVol; // queue of send actions (pair action, action_data) @VisibleForTesting ArrayDeque<Pair<Integer, Object>> mQueuedActions; Loading Loading @@ -878,11 +872,13 @@ public class HeadsetClientStateMachine extends StateMachine { } HeadsetClientStateMachine( AdapterService adapterService, HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mAdapterService = requireNonNull(adapterService); mService = requireNonNull(context); mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); Loading Loading @@ -924,9 +920,6 @@ public class HeadsetClientStateMachine extends StateMachine { mIndicatorNetworkSignal = 0; mIndicatorBatteryLevel = 0; sMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL); sMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL); mOperatorName = null; mSubscriberInfo = null; Loading @@ -949,6 +942,7 @@ public class HeadsetClientStateMachine extends StateMachine { } static HeadsetClientStateMachine make( AdapterService adapterService, HeadsetClientService context, HeadsetService headsetService, Looper looper, Loading @@ -956,17 +950,12 @@ public class HeadsetClientStateMachine extends StateMachine { Log.d(TAG, "make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine( context, headsetService, looper, nativeInterface); adapterService, context, headsetService, looper, nativeInterface); hfcsm.start(); return hfcsm; } synchronized void routeHfpAudio(boolean enable) { if (mAudioManager == null) { error("AudioManager is null!"); return; } debug("hfp_enable=" + enable); if (enable && !sAudioIsRouted) { mAudioManager.setHfpEnabled(true); Loading Loading @@ -1011,41 +1000,6 @@ public class HeadsetClientStateMachine extends StateMachine { mAudioFocusRequest = null; } static int hfToAmVol(int hfVol) { int amRange = sMaxAmVcVol - sMinAmVcVol; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int amVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { amVol = (int) Math.round( (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME) * ((double) amRange / hfRange)) + sMinAmVcVol; } else { int amOffset = (amRange * (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME)) / hfRange; amVol = sMinAmVcVol + amOffset; } Log.d(TAG, "HF -> AM " + hfVol + " " + amVol); return amVol; } static int amToHfVol(int amVol) { int amRange = (sMaxAmVcVol > sMinAmVcVol) ? (sMaxAmVcVol - sMinAmVcVol) : 1; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int hfVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { hfVol = (int) Math.round((amVol - sMinAmVcVol) * ((double) hfRange / amRange)) + MIN_HFP_SCO_VOICE_CALL_VOLUME; } else { int hfOffset = (hfRange * (amVol - sMinAmVcVol)) / amRange; hfVol = MIN_HFP_SCO_VOICE_CALL_VOLUME + hfOffset; } Log.d(TAG, "AM -> HF " + amVol + " " + hfVol); return hfVol; } class Disconnected extends State { @Override public void enter() { Loading Loading @@ -1162,7 +1116,7 @@ public class HeadsetClientStateMachine extends StateMachine { "Incoming AG rejected. connectionPolicy=" + mService.getConnectionPolicy(device) + " bondState=" + AdapterService.getAdapterService().getBondState(device)); + mAdapterService.getBondState(device)); // reject the connection and stay in Disconnected state // itself mNativeInterface.disconnect(device); Loading Loading @@ -1529,7 +1483,7 @@ public class HeadsetClientStateMachine extends StateMachine { case SET_SPEAKER_VOLUME: // This message should always contain the volume in AudioManager max normalized. int amVol = message.arg1; int hfVol = amToHfVol(amVol); int hfVol = mService.amToHfVol(amVol); if (amVol != mCommandedSpeakerVolume) { debug("Volume" + amVol + ":" + mCommandedSpeakerVolume); // Volume was changed by a 3rd party Loading Loading @@ -1735,7 +1689,7 @@ public class HeadsetClientStateMachine extends StateMachine { break; case StackEvent.EVENT_TYPE_VOLUME_CHANGED: if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) { mCommandedSpeakerVolume = hfToAmVol(event.valueInt2); mCommandedSpeakerVolume = mService.hfToAmVol(event.valueInt2); debug("AM volume set to " + mCommandedSpeakerVolume); boolean show_volume = SystemProperties.getBoolean( Loading Loading @@ -1917,7 +1871,7 @@ public class HeadsetClientStateMachine extends StateMachine { // We need to set the volume after switching into HFP mode as some Audio HALs // reset the volume to a known-default on mode switch. final int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); final int hfVol = amToHfVol(amVol); final int hfVol = mService.amToHfVol(amVol); debug("hfp_enable=true mAudioSWB is " + mAudioSWB); debug("hfp_enable=true mAudioWbs is " + mAudioWbs); Loading Loading @@ -2125,10 +2079,10 @@ public class HeadsetClientStateMachine extends StateMachine { BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_SCO_CONNECTION_STATE_CHANGED, AdapterService.getAdapterService().obfuscateAddress(device), mAdapterService.obfuscateAddress(device), getConnectionStateFromAudioState(newState), sco_codec, AdapterService.getAdapterService().getMetricId(device)); mAdapterService.getMetricId(device)); Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); Loading Loading @@ -2266,15 +2220,14 @@ public class HeadsetClientStateMachine extends StateMachine { List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); AdapterService adapterService = AdapterService.getAdapterService(); final BluetoothDevice[] bondedDevices = adapterService.getBondedDevices(); final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices(); if (bondedDevices == null) { return deviceList; } int connectionState; synchronized (this) { for (BluetoothDevice device : bondedDevices) { final ParcelUuid[] featureUuids = adapterService.getRemoteUuids(device); final ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device); if (!Utils.arrayContains(featureUuids, BluetoothUuid.HFP_AG)) { continue; } Loading @@ -2299,8 +2252,7 @@ public class HeadsetClientStateMachine extends StateMachine { // connection. Allow this connection, provided the device is bonded if ((BluetoothProfile.CONNECTION_POLICY_FORBIDDEN < connectionPolicy) || ((BluetoothProfile.CONNECTION_POLICY_UNKNOWN == connectionPolicy) && (AdapterService.getAdapterService().getBondState(device) != BluetoothDevice.BOND_NONE))) { && (mAdapterService.getBondState(device) != BluetoothDevice.BOND_NONE))) { ret = true; } return ret; Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java +10 −2 Original line number Diff line number Diff line Loading @@ -18,14 +18,22 @@ package com.android.bluetooth.hfpclient; import android.os.HandlerThread; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.hfp.HeadsetService; // Factory so that StateMachine objected can be mocked public class HeadsetClientStateMachineFactory { /** Factory method to create state machine for headset client */ public HeadsetClientStateMachine make( HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { AdapterService adapterService, HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { return HeadsetClientStateMachine.make( context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); adapterService, context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); } } Loading
android/app/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,7 @@ android_app { "-Xep:OperatorPrecedence:ERROR", "-Xep:ReferenceEquality:ERROR", "-Xep:ReturnAtTheEndOfVoidFunction:ERROR", "-Xep:StaticAssignmentInConstructor:ERROR", "-Xep:StaticGuardedByInstance:ERROR", "-Xep:StringCaseLocaleUsage:ERROR", "-Xep:StringCharset:ERROR", Loading
android/app/src/com/android/bluetooth/avrcp/AvrcpVolumeManager.java +24 −22 Original line number Diff line number Diff line Loading @@ -63,8 +63,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { @VisibleForTesting static final int AVRCP_MAX_VOL = 127; private static final int STREAM_MUSIC = AudioManager.STREAM_MUSIC; private static final int VOLUME_CHANGE_LOGGER_SIZE = 30; private static int sDeviceMaxVolume = 0; private static int sNewDeviceVolume = 0; private final int mDeviceMaxVolume; private final int mNewDeviceVolume; private final BluetoothEventLogger mVolumeEventLogger = new BluetoothEventLogger(VOLUME_CHANGE_LOGGER_SIZE, VOLUME_CHANGE_LOG_TITLE); Loading @@ -75,7 +75,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { // Absolute volume support map. HashMap<BluetoothDevice, Boolean> mDeviceMap = new HashMap(); // Volume stored is system volume (0 - {@code sDeviceMaxVolume}). // Volume stored is system volume (0 - {@code mDeviceMaxVolume}). HashMap<BluetoothDevice, Integer> mVolumeMap = new HashMap(); BluetoothDevice mCurrentDevice = null; Loading @@ -83,23 +83,25 @@ class AvrcpVolumeManager extends AudioDeviceCallback { /** * Converts given {@code avrcpVolume} (0 - 127) to equivalent in system volume (0 - {@code * sDeviceMaxVolume}). * mDeviceMaxVolume}). * * <p>Max system volume is retrieved from {@link AudioManager}. */ static int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.round((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); @VisibleForTesting int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.round((double) avrcpVolume * mDeviceMaxVolume / AVRCP_MAX_VOL); } /** * Converts given {@code deviceVolume} (0 - {@code sDeviceMaxVolume}) to equivalent in AVRCP * Converts given {@code deviceVolume} (0 - {@code mDeviceMaxVolume}) to equivalent in AVRCP * volume (0 - 127). * * <p>Max system volume is retrieved from {@link AudioManager}. */ static int systemToAvrcpVolume(int deviceVolume) { @VisibleForTesting int systemToAvrcpVolume(int deviceVolume) { int avrcpVolume = (int) Math.round((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); (int) Math.round((double) deviceVolume * AVRCP_MAX_VOL / mDeviceMaxVolume); if (avrcpVolume > 127) avrcpVolume = 127; return avrcpVolume; } Loading Loading @@ -149,7 +151,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { }); // Get the current system volume and try to get the preference volume int savedVolume = getVolume(device, sNewDeviceVolume); int savedVolume = getVolume(device, mNewDeviceVolume); d("switchVolumeDevice: savedVolume=" + savedVolume); Loading @@ -175,8 +177,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { mAdapterService = adapterService; mAudioManager = audioManager; mNativeInterface = nativeInterface; sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); sNewDeviceVolume = sDeviceMaxVolume / 2; mDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); mNewDeviceVolume = mDeviceMaxVolume / 2; mAudioManager.registerAudioDeviceCallback(this, null); Loading @@ -202,7 +204,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Stores system volume (0 - {@code sDeviceMaxVolume}) for device in {@code mVolumeMap} and * Stores system volume (0 - {@code mDeviceMaxVolume}) for device in {@code mVolumeMap} and * writes the map in the {@link SharedPreferences}. */ synchronized void storeVolumeForDevice(@NonNull BluetoothDevice device, int storeVolume) { Loading @@ -224,7 +226,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Retrieves system volume (0 - {@code sDeviceMaxVolume}) and calls {@link * Retrieves system volume (0 - {@code mDeviceMaxVolume}) and calls {@link * #storeVolumeForDevice(BluetoothDevice, int)} with {@code device}. */ synchronized void storeVolumeForDevice(@NonNull BluetoothDevice device) { Loading @@ -251,7 +253,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { } /** * Returns system volume (0 - {@code sDeviceMaxVolume}) stored in {@code mVolumeMap} for * Returns system volume (0 - {@code mDeviceMaxVolume}) stored in {@code mVolumeMap} for * corresponding {@code device}. * * @param defaultValue Value to return if device is not in the map. Loading @@ -266,9 +268,9 @@ class AvrcpVolumeManager extends AudioDeviceCallback { return mVolumeMap.get(device); } /** Returns the system volume (0 - {@code sDeviceMaxVolume}) applied to a new device */ /** Returns the system volume (0 - {@code mDeviceMaxVolume}) applied to a new device */ public int getNewDeviceVolume() { return sNewDeviceVolume; return mNewDeviceVolume; } /** Loading @@ -289,8 +291,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { + avrcpVolume + " deviceVolume=" + deviceVolume + " sDeviceMaxVolume=" + sDeviceMaxVolume); + " mDeviceMaxVolume=" + mDeviceMaxVolume); mAudioManager.setStreamVolume( AudioManager.STREAM_MUSIC, deviceVolume, Loading @@ -304,7 +306,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback { * * <p>See {@link #systemToAvrcpVolume}. * * @param deviceVolume in range (0 - {@code sDeviceMaxVolume}) received from system. * @param deviceVolume in range (0 - {@code mDeviceMaxVolume}) received from system. */ void sendVolumeChanged(@NonNull BluetoothDevice device, int deviceVolume) { if (deviceVolume == getVolume(device, -1)) { Loading @@ -321,8 +323,8 @@ class AvrcpVolumeManager extends AudioDeviceCallback { + avrcpVolume + " deviceVolume=" + deviceVolume + " sDeviceMaxVolume=" + sDeviceMaxVolume); + " mDeviceMaxVolume=" + mDeviceMaxVolume); mNativeInterface.sendVolumeChanged(device, avrcpVolume); storeVolumeForDevice(device); } Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +63 −23 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static android.content.pm.PackageManager.FEATURE_WATCH; import static java.util.Objects.requireNonNull; import android.annotation.RequiresPermission; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; Loading @@ -46,6 +48,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.btservice.storage.DatabaseManager; import com.android.bluetooth.flags.Flags; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -65,6 +68,12 @@ import java.util.UUID; public class HeadsetClientService extends ProfileService { private static final String TAG = HeadsetClientService.class.getSimpleName(); // Maximum number of devices we can try connecting to in one session private static final int MAX_STATE_MACHINES_POSSIBLE = 100; @VisibleForTesting static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec. @VisibleForTesting static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec. // This is also used as a lock for shared data in {@link HeadsetClientService} @GuardedBy("mStateMachineMap") private final HashMap<BluetoothDevice, HeadsetClientStateMachine> mStateMachineMap = Loading @@ -74,19 +83,26 @@ public class HeadsetClientService extends ProfileService { private NativeInterface mNativeInterface = null; private HandlerThread mSmThread = null; private HeadsetClientStateMachineFactory mSmFactory = null; private DatabaseManager mDatabaseManager; private AudioManager mAudioManager = null; private final AdapterService mAdapterService; private final DatabaseManager mDatabaseManager; private final AudioManager mAudioManager; private BatteryManager mBatteryManager = null; private int mLastBatteryLevel = -1; // Maximum number of devices we can try connecting to in one session private static final int MAX_STATE_MACHINES_POSSIBLE = 100; private final int mMaxAmVcVol; private final int mMinAmVcVol; private final Object mStartStopLock = new Object(); public static final String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag"; public HeadsetClientService(Context ctx) { super(ctx); public HeadsetClientService(AdapterService adapterService) { super(requireNonNull(adapterService)); mAdapterService = adapterService; mDatabaseManager = requireNonNull(adapterService.getDatabase()); mAudioManager = requireNonNull(getSystemService(AudioManager.class)); mMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL); mMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL); } public static boolean isEnabled() { Loading @@ -106,24 +122,14 @@ public class HeadsetClientService extends ProfileService { throw new IllegalStateException("start() called twice"); } mDatabaseManager = Objects.requireNonNull( AdapterService.getAdapterService().getDatabase(), "DatabaseManager cannot be null when HeadsetClientService starts"); // Setup the JNI service mNativeInterface = NativeInterface.getInstance(); mNativeInterface.initialize(); mBatteryManager = getSystemService(BatteryManager.class); mAudioManager = getSystemService(AudioManager.class); if (mAudioManager == null) { Log.e(TAG, "AudioManager service doesn't exist?"); } else { // start AudioManager in a known state mAudioManager.setHfpEnabled(false); } mSmFactory = new HeadsetClientStateMachineFactory(); synchronized (mStateMachineMap) { Loading Loading @@ -192,6 +198,42 @@ public class HeadsetClientService extends ProfileService { } } int hfToAmVol(int hfVol) { int amRange = mMaxAmVcVol - mMinAmVcVol; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int amVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { amVol = (int) Math.round( (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME) * ((double) amRange / hfRange)) + mMinAmVcVol; } else { int amOffset = (amRange * (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME)) / hfRange; amVol = mMinAmVcVol + amOffset; } Log.d(TAG, "HF -> AM " + hfVol + " " + amVol); return amVol; } @VisibleForTesting int amToHfVol(int amVol) { int amRange = (mMaxAmVcVol > mMinAmVcVol) ? (mMaxAmVcVol - mMinAmVcVol) : 1; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int hfVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { hfVol = (int) Math.round((amVol - mMinAmVcVol) * ((double) hfRange / amRange)) + MIN_HFP_SCO_VOICE_CALL_VOLUME; } else { int hfOffset = (hfRange * (amVol - mMinAmVcVol)) / amRange; hfVol = MIN_HFP_SCO_VOICE_CALL_VOLUME + hfOffset; } Log.d(TAG, "AM -> HF " + amVol + " " + hfVol); return hfVol; } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override Loading @@ -214,7 +256,7 @@ public class HeadsetClientService extends ProfileService { if (streamType == AudioManager.STREAM_VOICE_CALL) { int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); int hfVol = HeadsetClientStateMachine.amToHfVol(streamValue); int hfVol = amToHfVol(streamValue); Log.d( TAG, "Setting volume to audio manager: " Loading Loading @@ -1265,7 +1307,7 @@ public class HeadsetClientService extends ProfileService { // Allocate a new SM Log.d(TAG, "Creating a new state machine"); sm = mSmFactory.make(this, mSmThread, mNativeInterface); sm = mSmFactory.make(mAdapterService, this, mSmThread, mNativeInterface); mStateMachineMap.put(device, sm); return sm; } Loading Loading @@ -1295,9 +1337,7 @@ public class HeadsetClientService extends ProfileService { } void handleBatteryLevelChanged(BluetoothDevice device, int batteryLevel) { AdapterService.getAdapterService() .getRemoteDevices() .handleAgBatteryLevelChanged(device, batteryLevel); mAdapterService.getRemoteDevices().handleAgBatteryLevelChanged(device, batteryLevel); } @Override Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +14 −62 Original line number Diff line number Diff line Loading @@ -56,7 +56,6 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.flags.Flags; import com.android.bluetooth.hfp.HeadsetService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IState; Loading Loading @@ -118,9 +117,6 @@ public class HeadsetClientStateMachine extends StateMachine { @VisibleForTesting static final int CONNECTING_TIMEOUT_MS = 10000; // 10s private static final int ROUTING_DELAY_MS = 250; @VisibleForTesting static final int MAX_HFP_SCO_VOICE_CALL_VOLUME = 15; // HFP 1.5 spec. @VisibleForTesting static final int MIN_HFP_SCO_VOICE_CALL_VOLUME = 1; // HFP 1.5 spec. static final int HF_ORIGINATED_CALL_ID = -1; private static final long OUTGOING_TIMEOUT_MILLI = 10 * 1000; // 10 seconds private static final long QUERY_CURRENT_CALLS_WAIT_MILLIS = 2 * 1000; // 2 seconds Loading @@ -134,6 +130,7 @@ public class HeadsetClientStateMachine extends StateMachine { private final AudioOn mAudioOn; private State mPrevState; private final AdapterService mAdapterService; private final HeadsetClientService mService; private final HeadsetService mHeadsetService; Loading @@ -153,9 +150,6 @@ public class HeadsetClientStateMachine extends StateMachine { private String mOperatorName; @VisibleForTesting String mSubscriberInfo; private static int sMaxAmVcVol; private static int sMinAmVcVol; // queue of send actions (pair action, action_data) @VisibleForTesting ArrayDeque<Pair<Integer, Object>> mQueuedActions; Loading Loading @@ -878,11 +872,13 @@ public class HeadsetClientStateMachine extends StateMachine { } HeadsetClientStateMachine( AdapterService adapterService, HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mAdapterService = requireNonNull(adapterService); mService = requireNonNull(context); mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); Loading Loading @@ -924,9 +920,6 @@ public class HeadsetClientStateMachine extends StateMachine { mIndicatorNetworkSignal = 0; mIndicatorBatteryLevel = 0; sMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL); sMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL); mOperatorName = null; mSubscriberInfo = null; Loading @@ -949,6 +942,7 @@ public class HeadsetClientStateMachine extends StateMachine { } static HeadsetClientStateMachine make( AdapterService adapterService, HeadsetClientService context, HeadsetService headsetService, Looper looper, Loading @@ -956,17 +950,12 @@ public class HeadsetClientStateMachine extends StateMachine { Log.d(TAG, "make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine( context, headsetService, looper, nativeInterface); adapterService, context, headsetService, looper, nativeInterface); hfcsm.start(); return hfcsm; } synchronized void routeHfpAudio(boolean enable) { if (mAudioManager == null) { error("AudioManager is null!"); return; } debug("hfp_enable=" + enable); if (enable && !sAudioIsRouted) { mAudioManager.setHfpEnabled(true); Loading Loading @@ -1011,41 +1000,6 @@ public class HeadsetClientStateMachine extends StateMachine { mAudioFocusRequest = null; } static int hfToAmVol(int hfVol) { int amRange = sMaxAmVcVol - sMinAmVcVol; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int amVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { amVol = (int) Math.round( (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME) * ((double) amRange / hfRange)) + sMinAmVcVol; } else { int amOffset = (amRange * (hfVol - MIN_HFP_SCO_VOICE_CALL_VOLUME)) / hfRange; amVol = sMinAmVcVol + amOffset; } Log.d(TAG, "HF -> AM " + hfVol + " " + amVol); return amVol; } static int amToHfVol(int amVol) { int amRange = (sMaxAmVcVol > sMinAmVcVol) ? (sMaxAmVcVol - sMinAmVcVol) : 1; int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME; int hfVol = 0; if (Flags.headsetClientAmHfVolumeSymmetric()) { hfVol = (int) Math.round((amVol - sMinAmVcVol) * ((double) hfRange / amRange)) + MIN_HFP_SCO_VOICE_CALL_VOLUME; } else { int hfOffset = (hfRange * (amVol - sMinAmVcVol)) / amRange; hfVol = MIN_HFP_SCO_VOICE_CALL_VOLUME + hfOffset; } Log.d(TAG, "AM -> HF " + amVol + " " + hfVol); return hfVol; } class Disconnected extends State { @Override public void enter() { Loading Loading @@ -1162,7 +1116,7 @@ public class HeadsetClientStateMachine extends StateMachine { "Incoming AG rejected. connectionPolicy=" + mService.getConnectionPolicy(device) + " bondState=" + AdapterService.getAdapterService().getBondState(device)); + mAdapterService.getBondState(device)); // reject the connection and stay in Disconnected state // itself mNativeInterface.disconnect(device); Loading Loading @@ -1529,7 +1483,7 @@ public class HeadsetClientStateMachine extends StateMachine { case SET_SPEAKER_VOLUME: // This message should always contain the volume in AudioManager max normalized. int amVol = message.arg1; int hfVol = amToHfVol(amVol); int hfVol = mService.amToHfVol(amVol); if (amVol != mCommandedSpeakerVolume) { debug("Volume" + amVol + ":" + mCommandedSpeakerVolume); // Volume was changed by a 3rd party Loading Loading @@ -1735,7 +1689,7 @@ public class HeadsetClientStateMachine extends StateMachine { break; case StackEvent.EVENT_TYPE_VOLUME_CHANGED: if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) { mCommandedSpeakerVolume = hfToAmVol(event.valueInt2); mCommandedSpeakerVolume = mService.hfToAmVol(event.valueInt2); debug("AM volume set to " + mCommandedSpeakerVolume); boolean show_volume = SystemProperties.getBoolean( Loading Loading @@ -1917,7 +1871,7 @@ public class HeadsetClientStateMachine extends StateMachine { // We need to set the volume after switching into HFP mode as some Audio HALs // reset the volume to a known-default on mode switch. final int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); final int hfVol = amToHfVol(amVol); final int hfVol = mService.amToHfVol(amVol); debug("hfp_enable=true mAudioSWB is " + mAudioSWB); debug("hfp_enable=true mAudioWbs is " + mAudioWbs); Loading Loading @@ -2125,10 +2079,10 @@ public class HeadsetClientStateMachine extends StateMachine { BluetoothStatsLog.write( BluetoothStatsLog.BLUETOOTH_SCO_CONNECTION_STATE_CHANGED, AdapterService.getAdapterService().obfuscateAddress(device), mAdapterService.obfuscateAddress(device), getConnectionStateFromAudioState(newState), sco_codec, AdapterService.getAdapterService().getMetricId(device)); mAdapterService.getMetricId(device)); Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); Loading Loading @@ -2266,15 +2220,14 @@ public class HeadsetClientStateMachine extends StateMachine { List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); AdapterService adapterService = AdapterService.getAdapterService(); final BluetoothDevice[] bondedDevices = adapterService.getBondedDevices(); final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices(); if (bondedDevices == null) { return deviceList; } int connectionState; synchronized (this) { for (BluetoothDevice device : bondedDevices) { final ParcelUuid[] featureUuids = adapterService.getRemoteUuids(device); final ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device); if (!Utils.arrayContains(featureUuids, BluetoothUuid.HFP_AG)) { continue; } Loading @@ -2299,8 +2252,7 @@ public class HeadsetClientStateMachine extends StateMachine { // connection. Allow this connection, provided the device is bonded if ((BluetoothProfile.CONNECTION_POLICY_FORBIDDEN < connectionPolicy) || ((BluetoothProfile.CONNECTION_POLICY_UNKNOWN == connectionPolicy) && (AdapterService.getAdapterService().getBondState(device) != BluetoothDevice.BOND_NONE))) { && (mAdapterService.getBondState(device) != BluetoothDevice.BOND_NONE))) { ret = true; } return ret; Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java +10 −2 Original line number Diff line number Diff line Loading @@ -18,14 +18,22 @@ package com.android.bluetooth.hfpclient; import android.os.HandlerThread; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.hfp.HeadsetService; // Factory so that StateMachine objected can be mocked public class HeadsetClientStateMachineFactory { /** Factory method to create state machine for headset client */ public HeadsetClientStateMachine make( HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { AdapterService adapterService, HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { return HeadsetClientStateMachine.make( context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); adapterService, context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); } }