Root Cause: Only setMicrophonePreferredForCalls and show UI to current device, but audioManager might hold other device in the same set Solution: setMicrophonePreferredForCalls to whole device set and also check if any address in device set contain in audioManager GET_DEVICES_INPUTS list Bug: 392902067 Test: atest BluetoothDetailsHearingDeviceInputRoutingControllerTest Flag: EXEMPT bugfix Change-Id: Ic5846de26df4a8db67fa8efcf474fa4509f7918a
152 lines
6.3 KiB
Java
152 lines
6.3 KiB
Java
/*
|
|
* Copyright (C) 2024 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.settings.bluetooth;
|
|
|
|
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
|
|
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_HEARING_DEVICE_INPUT_ROUTING;
|
|
|
|
import android.content.Context;
|
|
import android.media.AudioDeviceInfo;
|
|
import android.media.AudioManager;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.collection.ArraySet;
|
|
import androidx.preference.PreferenceCategory;
|
|
import androidx.preference.PreferenceFragmentCompat;
|
|
import androidx.preference.PreferenceScreen;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.bluetooth.HearingDeviceInputRoutingPreference.InputRoutingValue;
|
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
|
import com.android.settingslib.bluetooth.HapClientProfile;
|
|
import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants;
|
|
import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper;
|
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* The controller of the hearing device input routing
|
|
*
|
|
* <p> It manages the input routing preference and update the routing according to the value.
|
|
*/
|
|
public class BluetoothDetailsHearingDeviceInputRoutingController extends
|
|
BluetoothDetailsController implements
|
|
HearingDeviceInputRoutingPreference.InputRoutingCallback {
|
|
|
|
private static final String TAG = "BluetoothDetailsHearingDeviceInputRoutingController";
|
|
static final String KEY_HEARING_DEVICE_INPUT_ROUTING = "hearing_device_input_routing";
|
|
|
|
private final HearingAidAudioRoutingHelper mAudioRoutingHelper;
|
|
private final AudioManager mAudioManager;
|
|
|
|
public BluetoothDetailsHearingDeviceInputRoutingController(
|
|
@NonNull Context context,
|
|
@NonNull PreferenceFragmentCompat fragment,
|
|
@NonNull CachedBluetoothDevice device,
|
|
@NonNull Lifecycle lifecycle) {
|
|
super(context, fragment, device, lifecycle);
|
|
mAudioRoutingHelper = new HearingAidAudioRoutingHelper(context);
|
|
mAudioManager = mContext.getSystemService(AudioManager.class);
|
|
}
|
|
|
|
@Override
|
|
public boolean isAvailable() {
|
|
final Set<CachedBluetoothDevice> memberDevices = mCachedDevice.getMemberDevice();
|
|
final AudioDeviceInfo[] inputInfos = mAudioManager.getDevices(
|
|
AudioManager.GET_DEVICES_INPUTS);
|
|
final Set<String> supportedInputDeviceAddresses = new ArraySet<>();
|
|
supportedInputDeviceAddresses.add(mCachedDevice.getAddress());
|
|
if (!memberDevices.isEmpty()) {
|
|
memberDevices.forEach(member -> supportedInputDeviceAddresses.add(member.getAddress()));
|
|
}
|
|
|
|
boolean isHapHearingDevice = mCachedDevice.getProfiles().stream().anyMatch(
|
|
profile -> profile instanceof HapClientProfile);
|
|
// Not support ASHA hearing device for input routing feature
|
|
boolean isValidInputDevice = Arrays.stream(inputInfos).anyMatch(
|
|
info -> supportedInputDeviceAddresses.contains(info.getAddress()));
|
|
|
|
if (isHapHearingDevice && !isValidInputDevice) {
|
|
Log.d(TAG, "Not supported input type hearing device.");
|
|
}
|
|
return isHapHearingDevice && isValidInputDevice;
|
|
}
|
|
|
|
@Override
|
|
protected void init(PreferenceScreen screen) {
|
|
PreferenceCategory hearingCategory = screen.findPreference(KEY_HEARING_DEVICE_GROUP);
|
|
if (hearingCategory != null) {
|
|
hearingCategory.addPreference(
|
|
createInputRoutingPreference(hearingCategory.getContext()));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void refresh() {}
|
|
|
|
@Nullable
|
|
@Override
|
|
public String getPreferenceKey() {
|
|
return KEY_HEARING_DEVICE_INPUT_ROUTING;
|
|
}
|
|
|
|
private HearingDeviceInputRoutingPreference createInputRoutingPreference(Context context) {
|
|
HearingDeviceInputRoutingPreference pref = new HearingDeviceInputRoutingPreference(context);
|
|
pref.setKey(KEY_HEARING_DEVICE_INPUT_ROUTING);
|
|
pref.setOrder(ORDER_HEARING_DEVICE_INPUT_ROUTING);
|
|
pref.setTitle(context.getString(R.string.bluetooth_hearing_device_input_routing_title));
|
|
pref.setChecked(getUserPreferredInputRoutingValue());
|
|
pref.setInputRoutingCallback(this);
|
|
return pref;
|
|
}
|
|
|
|
@InputRoutingValue
|
|
private int getUserPreferredInputRoutingValue() {
|
|
return mCachedDevice.getDevice().isMicrophonePreferredForCalls()
|
|
? InputRoutingValue.HEARING_DEVICE : InputRoutingValue.BUILTIN_MIC;
|
|
}
|
|
|
|
@Override
|
|
public void onInputRoutingUpdated(int selectedInputRoutingUiValue) {
|
|
boolean useBuiltinMic =
|
|
(selectedInputRoutingUiValue == InputRoutingValue.BUILTIN_MIC);
|
|
boolean status = mAudioRoutingHelper.setPreferredInputDeviceForCalls(mCachedDevice,
|
|
useBuiltinMic ? HearingAidAudioRoutingConstants.RoutingValue.BUILTIN_DEVICE
|
|
: HearingAidAudioRoutingConstants.RoutingValue.AUTO);
|
|
if (!status) {
|
|
Log.d(TAG, "Fail to configure setPreferredInputDeviceForCalls");
|
|
}
|
|
setMicrophonePreferredForCallsForDeviceSet(mCachedDevice, !useBuiltinMic);
|
|
}
|
|
|
|
private void setMicrophonePreferredForCallsForDeviceSet(CachedBluetoothDevice device,
|
|
boolean enabled) {
|
|
if (device == null) {
|
|
return;
|
|
}
|
|
device.getDevice().setMicrophonePreferredForCalls(enabled);
|
|
final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
|
|
if (!memberDevices.isEmpty()) {
|
|
memberDevices.forEach(d -> d.getDevice().setMicrophonePreferredForCalls(enabled));
|
|
}
|
|
}
|
|
}
|