blob: 35cc65fafe707346721692d2e1afd2666c1e14cc [file] [log] [blame]
/*
* Copyright (C) 2018 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.sound;
import static android.bluetooth.BluetoothHearingAid.HI_SYNC_ID_INVALID;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.text.TextUtils;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.HeadsetProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
/**
* This class allows switching between HFP-connected & HAP-connected BT devices
* while in on-call state.
*/
public class HandsFreeProfileOutputPreferenceController extends AudioSwitchPreferenceController
implements Preference.OnPreferenceChangeListener {
private static final int INVALID_INDEX = -1;
public HandsFreeProfileOutputPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final String address = (String) newValue;
if (!(preference instanceof ListPreference)) {
return false;
}
final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
final ListPreference listPreference = (ListPreference) preference;
if (TextUtils.equals(address, defaultSummary)) {
// Switch to default device which address is device name
mSelectedIndex = getDefaultDeviceIndex();
setActiveBluetoothDevice(null);
listPreference.setSummary(defaultSummary);
} else {
// Switch to BT device which address is hardware address
final int connectedDeviceIndex = getConnectedDeviceIndex(address);
if (connectedDeviceIndex == INVALID_INDEX) {
return false;
}
final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
mSelectedIndex = connectedDeviceIndex;
setActiveBluetoothDevice(btDevice);
listPreference.setSummary(btDevice.getAlias());
}
return true;
}
private int getConnectedDeviceIndex(String hardwareAddress) {
if (mConnectedDevices != null) {
for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
final BluetoothDevice btDevice = mConnectedDevices.get(i);
if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
return i;
}
}
}
return INVALID_INDEX;
}
@Override
public void updateState(Preference preference) {
if (preference == null) {
// In case UI is not ready.
return;
}
if (!Utils.isAudioModeOngoingCall(mContext)) {
// Without phone call, disable the switch entry.
mPreference.setVisible(false);
preference.setSummary(mContext.getText(R.string.media_output_default_summary));
return;
}
// Ongoing call status, list all the connected devices support hands free profile.
// Select current active device.
// Disable switch entry if there is no connected device.
mConnectedDevices.clear();
mConnectedDevices.addAll(getConnectedHfpDevices());
mConnectedDevices.addAll(getConnectedHearingAidDevices());
mConnectedDevices.addAll(getConnectedLeAudioDevices());
final int numDevices = mConnectedDevices.size();
if (numDevices == 0) {
// No connected devices, disable switch entry.
mPreference.setVisible(false);
final CharSequence summary = mContext.getText(R.string.media_output_default_summary);
final CharSequence[] defaultMediaOutput = new CharSequence[]{summary};
mSelectedIndex = getDefaultDeviceIndex();
preference.setSummary(summary);
setPreference(defaultMediaOutput, defaultMediaOutput, preference);
return;
}
mPreference.setVisible(true);
CharSequence[] mediaOutputs = new CharSequence[numDevices + 1];
CharSequence[] mediaValues = new CharSequence[numDevices + 1];
// Setup devices entries, select active connected device
setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());
// Display connected devices, default device and show the active device
setPreference(mediaOutputs, mediaValues, preference);
}
int getDefaultDeviceIndex() {
// Default device is after all connected devices.
return mConnectedDevices.size();
}
void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
BluetoothDevice activeDevice) {
// default to current device
mSelectedIndex = getDefaultDeviceIndex();
// default device is after all connected devices.
final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
mediaOutputs[mSelectedIndex] = defaultSummary;
// use default device name as address
mediaValues[mSelectedIndex] = defaultSummary;
for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
final BluetoothDevice btDevice = mConnectedDevices.get(i);
mediaOutputs[i] = btDevice.getAlias();
mediaValues[i] = btDevice.getAddress();
if (btDevice.equals(activeDevice)) {
// select the active connected device.
mSelectedIndex = i;
}
}
}
void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
Preference preference) {
final ListPreference listPreference = (ListPreference) preference;
listPreference.setEntries(mediaOutputs);
listPreference.setEntryValues(mediaValues);
listPreference.setValueIndex(mSelectedIndex);
listPreference.setSummary(mediaOutputs[mSelectedIndex]);
mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
}
public void setActiveBluetoothDevice(BluetoothDevice device) {
if (!Utils.isAudioModeOngoingCall(mContext)) {
return;
}
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
final HeadsetProfile hfpProfile = mProfileManager.getHeadsetProfile();
if (hapProfile != null && hfpProfile != null && device == null) {
hfpProfile.setActiveDevice(null);
hapProfile.setActiveDevice(null);
} else if (hapProfile != null && device != null
&& hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
hapProfile.setActiveDevice(device);
} else if (hfpProfile != null) {
hfpProfile.setActiveDevice(device);
}
}
@Override
public BluetoothDevice findActiveDevice() {
BluetoothDevice haActiveDevice = findActiveHearingAidDevice();
BluetoothDevice leAudioActiveDevice = findActiveLeAudioDevice();
final HeadsetProfile headsetProfile = mProfileManager.getHeadsetProfile();
if (haActiveDevice != null) {
return haActiveDevice;
}
if (leAudioActiveDevice != null) {
return leAudioActiveDevice;
}
if (headsetProfile != null && headsetProfile.getActiveDevice() != null) {
return headsetProfile.getActiveDevice();
}
return null;
}
}