[Audiosharing] Impl active device switch for calls and alarms
Flagged with enable_le_audio_sharing
Bug: 305620450
Test: Manual
Change-Id: Id1e417cd1ae48bbb4ddebb4b30e2001e18bef7ee
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java
index a68117a..5998e30 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java
@@ -22,10 +22,12 @@
public final class AudioSharingDeviceItem implements Parcelable {
private final String mName;
private final int mGroupId;
+ private final boolean mIsActive;
- public AudioSharingDeviceItem(String name, int groupId) {
+ public AudioSharingDeviceItem(String name, int groupId, boolean isActive) {
mName = name;
mGroupId = groupId;
+ mIsActive = isActive;
}
public String getName() {
@@ -36,15 +38,21 @@
return mGroupId;
}
+ public boolean isActive() {
+ return mIsActive;
+ }
+
public AudioSharingDeviceItem(Parcel in) {
mName = in.readString();
mGroupId = in.readInt();
+ mIsActive = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mName);
dest.writeInt(mGroupId);
+ dest.writeBoolean(mIsActive);
}
@Override
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
index 4ece70e..a0d44ff 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -120,6 +120,9 @@
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
public static AudioSharingDeviceItem buildAudioSharingDeviceItem(
CachedBluetoothDevice cachedDevice) {
- return new AudioSharingDeviceItem(cachedDevice.getName(), cachedDevice.getGroupId());
+ return new AudioSharingDeviceItem(
+ cachedDevice.getName(),
+ cachedDevice.getGroupId(),
+ BluetoothUtils.isActiveLeAudioDevice(cachedDevice));
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java
index 0577f70..47f70c7 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java
@@ -28,9 +28,25 @@
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.flags.Flags;
+import java.util.ArrayList;
+
/** Provides a dialog to choose the active device for calls and alarms. */
public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment {
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
public int getMetricsCategory() {
@@ -41,28 +57,43 @@
* Display the {@link CallsAndAlarmsDialogFragment} dialog.
*
* @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;
final FragmentManager manager = host.getChildFragmentManager();
+ sListener = listener;
if (manager.findFragmentByTag(TAG) == null) {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(BUNDLE_KEY_DEVICE_ITEMS, deviceItems);
final CallsAndAlarmsDialogFragment dialog = new CallsAndAlarmsDialogFragment();
+ dialog.setArguments(bundle);
dialog.show(manager, TAG);
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- // TODO: use real device names
- String[] choices = {"Buds 1", "Buds 2"};
+ Bundle arguments = requireArguments();
+ 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 =
new AlertDialog.Builder(getActivity())
.setTitle(R.string.calls_and_alarms_device_title)
.setSingleChoiceItems(
choices,
- 0, // TODO: set to current active device.
+ checkedItem,
(dialog, which) -> {
- // TODO: set device to active device for calls and alarms.
+ sListener.onItemClick(deviceItems.get(which));
});
return builder.create();
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
index 44e75ec..a7d18e7 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
@@ -16,23 +16,42 @@
package com.android.settings.connecteddevice.audiosharing;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceScreen;
+import com.android.settings.bluetooth.Utils;
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 */
-public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController {
+public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController
+ implements BluetoothCallback, DefaultLifecycleObserver {
private static final String TAG = "CallsAndAlarmsPreferenceController";
-
private static final String PREF_KEY = "calls_and_alarms";
+
+ private final LocalBluetoothManager mLocalBtManager;
private DashboardFragment mFragment;
+ Map<Integer, List<CachedBluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
+ private ArrayList<AudioSharingDeviceItem> mDeviceItemsInSharingSession = new ArrayList<>();
public CallsAndAlarmsPreferenceController(Context context) {
super(context, PREF_KEY);
+ mLocalBtManager = Utils.getLocalBtManager(mContext);
}
@Override
@@ -43,17 +62,60 @@
@Override
public void displayPreference(PreferenceScreen 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(
preference -> {
- if (mFragment != null) {
- CallsAndAlarmsDialogFragment.show(mFragment);
- } else {
+ if (mFragment == null) {
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;
});
}
+ @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.
*
@@ -62,4 +124,12 @@
public void init(DashboardFragment fragment) {
this.mFragment = fragment;
}
+
+ private void updateDeviceItemsInSharingSession() {
+ mGroupedConnectedDevices =
+ AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
+ mDeviceItemsInSharingSession =
+ AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
+ mGroupedConnectedDevices, mLocalBtManager);
+ }
}