Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java +9 −1 Original line number Diff line number Diff line Loading @@ -22,10 +22,12 @@ import android.os.Parcelable; 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() { Loading @@ -36,15 +38,21 @@ public final class AudioSharingDeviceItem implements Parcelable { 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 Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +4 −1 Original line number Diff line number Diff line Loading @@ -120,6 +120,9 @@ public class AudioSharingUtils { /** 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)); } } src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java +36 −5 Original line number Diff line number Diff line Loading @@ -28,9 +28,25 @@ import com.android.settings.R; 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() { Loading @@ -41,28 +57,43 @@ public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment { * 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(); } Loading src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java +75 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -43,17 +62,60 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen @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. * Loading @@ -62,4 +124,12 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen public void init(DashboardFragment fragment) { this.mFragment = fragment; } private void updateDeviceItemsInSharingSession() { mGroupedConnectedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager); mDeviceItemsInSharingSession = AudioSharingUtils.buildOrderedDeviceItemsInSharingSession( mGroupedConnectedDevices, mLocalBtManager); } } Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceItem.java +9 −1 Original line number Diff line number Diff line Loading @@ -22,10 +22,12 @@ import android.os.Parcelable; 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() { Loading @@ -36,15 +38,21 @@ public final class AudioSharingDeviceItem implements Parcelable { 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 Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java +4 −1 Original line number Diff line number Diff line Loading @@ -120,6 +120,9 @@ public class AudioSharingUtils { /** 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)); } }
src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsDialogFragment.java +36 −5 Original line number Diff line number Diff line Loading @@ -28,9 +28,25 @@ import com.android.settings.R; 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() { Loading @@ -41,28 +57,43 @@ public class CallsAndAlarmsDialogFragment extends InstrumentedDialogFragment { * 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(); } Loading
src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java +75 −5 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -43,17 +62,60 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen @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. * Loading @@ -62,4 +124,12 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen public void init(DashboardFragment fragment) { this.mFragment = fragment; } private void updateDeviceItemsInSharingSession() { mGroupedConnectedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager); mDeviceItemsInSharingSession = AudioSharingUtils.buildOrderedDeviceItemsInSharingSession( mGroupedConnectedDevices, mLocalBtManager); } }