Merge "[Audiosharing] Impl active device switch for calls and alarms" into main

This commit is contained in:
Yiyi Shen
2023-11-17 09:56:18 +00:00
committed by Android (Google) Code Review
4 changed files with 124 additions and 12 deletions

View File

@@ -22,10 +22,12 @@ import android.os.Parcelable;
public final class AudioSharingDeviceItem implements Parcelable { public final class AudioSharingDeviceItem implements Parcelable {
private final String mName; private final String mName;
private final int mGroupId; private final int mGroupId;
private final boolean mIsActive;
public AudioSharingDeviceItem(String name, int groupId) { public AudioSharingDeviceItem(String name, int groupId, boolean isActive) {
mName = name; mName = name;
mGroupId = groupId; mGroupId = groupId;
mIsActive = isActive;
} }
public String getName() { public String getName() {
@@ -36,15 +38,21 @@ public final class AudioSharingDeviceItem implements Parcelable {
return mGroupId; return mGroupId;
} }
public boolean isActive() {
return mIsActive;
}
public AudioSharingDeviceItem(Parcel in) { public AudioSharingDeviceItem(Parcel in) {
mName = in.readString(); mName = in.readString();
mGroupId = in.readInt(); mGroupId = in.readInt();
mIsActive = in.readBoolean();
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName); dest.writeString(mName);
dest.writeInt(mGroupId); dest.writeInt(mGroupId);
dest.writeBoolean(mIsActive);
} }
@Override @Override

View File

@@ -120,6 +120,9 @@ public class AudioSharingUtils {
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */ /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
public static AudioSharingDeviceItem buildAudioSharingDeviceItem( public static AudioSharingDeviceItem buildAudioSharingDeviceItem(
CachedBluetoothDevice cachedDevice) { CachedBluetoothDevice cachedDevice) {
return new AudioSharingDeviceItem(cachedDevice.getName(), cachedDevice.getGroupId()); return new AudioSharingDeviceItem(
cachedDevice.getName(),
cachedDevice.getGroupId(),
BluetoothUtils.isActiveLeAudioDevice(cachedDevice));
} }
} }

View File

@@ -28,9 +28,25 @@ import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.flags.Flags; import com.android.settings.flags.Flags;
import java.util.ArrayList;
/** Provides a dialog to choose the active device for calls and alarms. */ /** Provides a dialog to choose the active device for calls and alarms. */
public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment { public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = "CallsAndAlarmsDialog"; private static final String TAG = "CallsAndAlarmsDialog";
private static final String BUNDLE_KEY_DEVICE_ITEMS = "bundle_key_device_items";
// The host creates an instance of this dialog fragment must implement this interface to receive
// event callbacks.
public interface DialogEventListener {
/**
* Called when users click the device item to set active for calls and alarms in the dialog.
*
* @param item The device item clicked.
*/
void onItemClick(AudioSharingDeviceItem item);
}
private static DialogEventListener sListener;
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
@@ -41,28 +57,43 @@ public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
* Display the {@link CallsAndAlarmsDialogFragment} dialog. * Display the {@link CallsAndAlarmsDialogFragment} dialog.
* *
* @param host The Fragment this dialog will be hosted. * @param host The Fragment this dialog will be hosted.
* @param deviceItems The connected device items in audio sharing session.
* @param listener The callback to handle the user action on this dialog.
*/ */
public static void show(Fragment host) { public static void show(
Fragment host,
ArrayList<AudioSharingDeviceItem> deviceItems,
DialogEventListener listener) {
if (!Flags.enableLeAudioSharing()) return; if (!Flags.enableLeAudioSharing()) return;
final FragmentManager manager = host.getChildFragmentManager(); final FragmentManager manager = host.getChildFragmentManager();
sListener = listener;
if (manager.findFragmentByTag(TAG) == null) { if (manager.findFragmentByTag(TAG) == null) {
final Bundle bundle = new Bundle();
bundle.putParcelableArrayList(BUNDLE_KEY_DEVICE_ITEMS, deviceItems);
final CallsAndAlarmsDialogFragment dialog = new CallsAndAlarmsDialogFragment(); final CallsAndAlarmsDialogFragment dialog = new CallsAndAlarmsDialogFragment();
dialog.setArguments(bundle);
dialog.show(manager, TAG); dialog.show(manager, TAG);
} }
} }
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
// TODO: use real device names Bundle arguments = requireArguments();
String[] choices = {"Buds 1", "Buds 2"}; ArrayList<AudioSharingDeviceItem> deviceItems =
arguments.getParcelableArrayList(BUNDLE_KEY_DEVICE_ITEMS);
int checkedItem = -1;
// deviceItems is ordered. The active device is put in the first place if it does exist
if (!deviceItems.isEmpty() && deviceItems.get(0).isActive()) checkedItem = 0;
String[] choices =
deviceItems.stream().map(AudioSharingDeviceItem::getName).toArray(String[]::new);
AlertDialog.Builder builder = AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity()) new AlertDialog.Builder(getActivity())
.setTitle(R.string.calls_and_alarms_device_title) .setTitle(R.string.calls_and_alarms_device_title)
.setSingleChoiceItems( .setSingleChoiceItems(
choices, choices,
0, // TODO: set to current active device. checkedItem,
(dialog, which) -> { (dialog, which) -> {
// TODO: set device to active device for calls and alarms. sListener.onItemClick(deviceItems.get(which));
}); });
return builder.create(); return builder.create();
} }

View File

@@ -16,23 +16,42 @@
package com.android.settings.connecteddevice.audiosharing; package com.android.settings.connecteddevice.audiosharing;
import android.annotation.Nullable;
import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.bluetooth.Utils;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** PreferenceController to control the dialog to choose the active device for calls and alarms */ /** PreferenceController to control the dialog to choose the active device for calls and alarms */
public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController { public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController
implements BluetoothCallback, DefaultLifecycleObserver {
private static final String TAG = "CallsAndAlarmsPreferenceController"; private static final String TAG = "CallsAndAlarmsPreferenceController";
private static final String PREF_KEY = "calls_and_alarms"; private static final String PREF_KEY = "calls_and_alarms";
private final LocalBluetoothManager mLocalBtManager;
private DashboardFragment mFragment; private DashboardFragment mFragment;
Map<Integer, List<CachedBluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
private ArrayList<AudioSharingDeviceItem> mDeviceItemsInSharingSession = new ArrayList<>();
public CallsAndAlarmsPreferenceController(Context context) { public CallsAndAlarmsPreferenceController(Context context) {
super(context, PREF_KEY); super(context, PREF_KEY);
mLocalBtManager = Utils.getLocalBtManager(mContext);
} }
@Override @Override
@@ -43,17 +62,60 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
@Override @Override
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
updateDeviceItemsInSharingSession();
// mDeviceItemsInSharingSession is ordered. The active device is the first place if exits.
if (!mDeviceItemsInSharingSession.isEmpty()
&& mDeviceItemsInSharingSession.get(0).isActive()) {
mPreference.setSummary(mDeviceItemsInSharingSession.get(0).getName());
} else {
mPreference.setSummary("");
}
mPreference.setOnPreferenceClickListener( mPreference.setOnPreferenceClickListener(
preference -> { preference -> {
if (mFragment != null) { if (mFragment == null) {
CallsAndAlarmsDialogFragment.show(mFragment);
} else {
Log.w(TAG, "Dialog fail to show due to null host."); Log.w(TAG, "Dialog fail to show due to null host.");
return true;
}
updateDeviceItemsInSharingSession();
if (mDeviceItemsInSharingSession.size() >= 2) {
CallsAndAlarmsDialogFragment.show(
mFragment,
mDeviceItemsInSharingSession,
(AudioSharingDeviceItem item) -> {
for (CachedBluetoothDevice device :
mGroupedConnectedDevices.get(item.getGroupId())) {
device.setActive();
}
});
} }
return true; return true;
}); });
} }
@Override
public void onStart(@NonNull LifecycleOwner owner) {
if (mLocalBtManager != null) {
mLocalBtManager.getEventManager().registerCallback(this);
}
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
if (mLocalBtManager != null) {
mLocalBtManager.getEventManager().unregisterCallback(this);
}
}
@Override
public void onActiveDeviceChanged(
@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
if (bluetoothProfile != BluetoothProfile.LE_AUDIO) {
Log.d(TAG, "Ignore onActiveDeviceChanged, not LE_AUDIO profile");
return;
}
mPreference.setSummary(activeDevice == null ? "" : activeDevice.getName());
}
/** /**
* Initialize the controller. * Initialize the controller.
* *
@@ -62,4 +124,12 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
public void init(DashboardFragment fragment) { public void init(DashboardFragment fragment) {
this.mFragment = fragment; this.mFragment = fragment;
} }
private void updateDeviceItemsInSharingSession() {
mGroupedConnectedDevices =
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
mDeviceItemsInSharingSession =
AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
mGroupedConnectedDevices, mLocalBtManager);
}
} }