Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java +14 −9 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr private static final String TAG = "AudioSharingLoadingDlg"; private static final String BUNDLE_KEY_MESSAGE = "bundle_key_message"; private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(10); private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15); private static final int AUTO_DISMISS_MESSAGE_ID = R.id.message; private static String sMessage = ""; Loading Loading @@ -74,14 +74,16 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr } AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG); if (dialog != null) { if (sMessage.equals(message)) { Log.d(TAG, "Dialog is showing with same message, return."); return; } else { Log.d(TAG, "Dialog is showing with different message, dismiss and reshow."); dialog.dismiss(); if (!sMessage.equals(message)) { Log.d(TAG, "Update dialog message."); TextView messageView = dialog.findViewById(R.id.message); if (messageView != null) { messageView.setText(message); } } Log.d(TAG, "Dialog is showing, return."); return; } sMessage = message; Log.d(TAG, "Show up the loading dialog."); Bundle args = new Bundle(); Loading Loading @@ -113,8 +115,10 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr @NonNull public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { mHandler = new Handler(Looper.getMainLooper()); mHandler.postDelayed(() -> dismiss(), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS); mHandler.postDelayed(() -> { Log.d(TAG, "Auto dismiss dialog after timeout"); dismiss(); }, AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS); Bundle args = requireArguments(); String message = args.getString(BUNDLE_KEY_MESSAGE, ""); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); Loading @@ -132,6 +136,7 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr public void onDismiss(@NonNull DialogInterface dialog) { super.onDismiss(dialog); if (mHandler != null) { Log.d(TAG, "Dialog dismissed, remove auto dismiss task"); mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID); } } Loading src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +57 −18 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; Loading Loading @@ -112,12 +113,13 @@ public class AudioSharingSwitchBarController extends BasePreferenceController private final MetricsFeatureProvider mMetricsFeatureProvider; private final OnAudioSharingStateChangedListener mListener; private Map<Integer, List<BluetoothDevice>> mGroupedConnectedDevices = new HashMap<>(); private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>(); @Nullable private AudioSharingDeviceItem mTargetActiveItem; private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>(); @VisibleForTesting IntentFilter mIntentFilter; private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); private AtomicInteger mIntentHandleStage = new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal()); private CopyOnWriteArrayList<BluetoothDevice> mSinksInAdding = new CopyOnWriteArrayList<>(); @VisibleForTesting BroadcastReceiver mReceiver = Loading Loading @@ -294,7 +296,16 @@ public class AudioSharingSwitchBarController extends BasePreferenceController public void onReceiveStateChanged( @NonNull BluetoothDevice sink, int sourceId, @NonNull BluetoothLeBroadcastReceiveState state) {} @NonNull BluetoothLeBroadcastReceiveState state) { if (BluetoothUtils.isConnected(state)) { if (mSinksInAdding.contains(sink)) { mSinksInAdding.remove(sink); } dismissLoadingStateDialogIfNeeded(); Log.d(TAG, "onReceiveStateChanged() connected, sink = " + sink + ", remaining sinks = " + mSinksInAdding); } } }; AudioSharingSwitchBarController( Loading Loading @@ -506,17 +517,20 @@ public class AudioSharingSwitchBarController extends BasePreferenceController mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ false); // deviceItems is ordered. The active device is the first place if exits. mDeviceItemsForSharing = new ArrayList<>(deviceItems); mTargetActiveSinks = new ArrayList<>(); mTargetActiveItem = null; if (!deviceItems.isEmpty() && deviceItems.get(0).isActive()) { // If active device exists for audio sharing, share to it // automatically once the broadcast is started. mTargetActiveSinks = mGroupedConnectedDevices.getOrDefault( deviceItems.get(0).getGroupId(), ImmutableList.of()); mTargetActiveItem = deviceItems.get(0); mDeviceItemsForSharing.remove(0); } if (mBroadcast != null) { mBroadcast.startPrivateBroadcast(); mSinksInAdding.clear(); // TODO: use string res once finalized. AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.show(mFragment, "Starting audio stream...")); mMetricsFeatureProvider.action( mContext, SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_ON, Loading Loading @@ -580,27 +594,30 @@ public class AudioSharingSwitchBarController extends BasePreferenceController } private void handleOnBroadcastReady() { List<BluetoothDevice> targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of() : mGroupedConnectedDevices.getOrDefault( mTargetActiveItem.getGroupId(), ImmutableList.of()); Pair<Integer, Object>[] eventData = AudioSharingUtils.buildAudioSharingDialogEventData( SettingsEnums.AUDIO_SHARING_SETTINGS, SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE, /* userTriggered= */ false, /* deviceCountInSharing= */ mTargetActiveSinks.isEmpty() ? 0 : 1, /* deviceCountInSharing= */ targetActiveSinks.isEmpty() ? 0 : 1, /* candidateDeviceCount= */ mDeviceItemsForSharing.size()); if (!mTargetActiveSinks.isEmpty()) { if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) { Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks."); AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager); addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName()); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING); mTargetActiveSinks.clear(); mTargetActiveItem = null; if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()) && mDeviceItemsForSharing.size() == 1) { Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device"); AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()), mBtManager); AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0); List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( target.getGroupId(), ImmutableList.of()); addSourceToTargetSinks(targetSinks, target.getName()); cleanUp(); // TODO: Add metric for auto add by intent return; Loading @@ -611,6 +628,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController StartIntentHandleStage.HANDLED.ordinal()); if (mFragment == null) { Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment."); dismissLoadingStateDialogIfNeeded(); cleanUp(); return; } Loading @@ -622,15 +640,15 @@ public class AudioSharingSwitchBarController extends BasePreferenceController new AudioSharingDialogFragment.DialogEventListener() { @Override public void onItemClick(@NonNull AudioSharingDeviceItem item) { AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( item.getGroupId(), ImmutableList.of()), mBtManager); List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( item.getGroupId(), ImmutableList.of()); addSourceToTargetSinks(targetSinks, item.getName()); cleanUp(); } @Override public void onCancelClick() { dismissLoadingStateDialogIfNeeded(); cleanUp(); } }; Loading Loading @@ -700,6 +718,27 @@ public class AudioSharingSwitchBarController extends BasePreferenceController }); } private void addSourceToTargetSinks(List<BluetoothDevice> targetActiveSinks, @NonNull String sinkName) { mSinksInAdding.addAll(targetActiveSinks); AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager); // TODO: move to res once finalized String loadingMessage = "Sharing with " + sinkName + "..."; showLoadingStateDialog(loadingMessage); } private void showLoadingStateDialog(@NonNull String loadingMessage) { AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.show(mFragment, loadingMessage)); } private void dismissLoadingStateDialogIfNeeded() { if (mSinksInAdding.isEmpty()) { AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.dismiss(mFragment)); } } private void cleanUp() { mGroupedConnectedDevices.clear(); mDeviceItemsForSharing.clear(); Loading tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java +2 −7 Original line number Diff line number Diff line Loading @@ -150,7 +150,7 @@ public class AudioSharingLoadingStateDialogFragmentTest { } @Test public void showDialog_newMessage_dismissAndShowNewDialog() { public void showDialog_newMessage_keepAndUpdateDialog() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1); shadowMainLooper().idle(); Loading @@ -163,12 +163,7 @@ public class AudioSharingLoadingStateDialogFragmentTest { AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE2); shadowMainLooper().idle(); assertThat(dialog.isShowing()).isFalse(); AlertDialog newDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(newDialog).isNotNull(); assertThat(newDialog.isShowing()).isTrue(); view = newDialog.findViewById(R.id.message); assertThat(view).isNotNull(); assertThat(dialog.isShowing()).isTrue(); assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE2); } } tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +129 −20 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java +14 −9 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr private static final String TAG = "AudioSharingLoadingDlg"; private static final String BUNDLE_KEY_MESSAGE = "bundle_key_message"; private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(10); private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15); private static final int AUTO_DISMISS_MESSAGE_ID = R.id.message; private static String sMessage = ""; Loading Loading @@ -74,14 +74,16 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr } AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG); if (dialog != null) { if (sMessage.equals(message)) { Log.d(TAG, "Dialog is showing with same message, return."); return; } else { Log.d(TAG, "Dialog is showing with different message, dismiss and reshow."); dialog.dismiss(); if (!sMessage.equals(message)) { Log.d(TAG, "Update dialog message."); TextView messageView = dialog.findViewById(R.id.message); if (messageView != null) { messageView.setText(message); } } Log.d(TAG, "Dialog is showing, return."); return; } sMessage = message; Log.d(TAG, "Show up the loading dialog."); Bundle args = new Bundle(); Loading Loading @@ -113,8 +115,10 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr @NonNull public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { mHandler = new Handler(Looper.getMainLooper()); mHandler.postDelayed(() -> dismiss(), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS); mHandler.postDelayed(() -> { Log.d(TAG, "Auto dismiss dialog after timeout"); dismiss(); }, AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS); Bundle args = requireArguments(); String message = args.getString(BUNDLE_KEY_MESSAGE, ""); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); Loading @@ -132,6 +136,7 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr public void onDismiss(@NonNull DialogInterface dialog) { super.onDismiss(dialog); if (mHandler != null) { Log.d(TAG, "Dialog dismissed, remove auto dismiss task"); mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID); } } Loading
src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java +57 −18 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; Loading Loading @@ -112,12 +113,13 @@ public class AudioSharingSwitchBarController extends BasePreferenceController private final MetricsFeatureProvider mMetricsFeatureProvider; private final OnAudioSharingStateChangedListener mListener; private Map<Integer, List<BluetoothDevice>> mGroupedConnectedDevices = new HashMap<>(); private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>(); @Nullable private AudioSharingDeviceItem mTargetActiveItem; private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>(); @VisibleForTesting IntentFilter mIntentFilter; private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); private AtomicInteger mIntentHandleStage = new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal()); private CopyOnWriteArrayList<BluetoothDevice> mSinksInAdding = new CopyOnWriteArrayList<>(); @VisibleForTesting BroadcastReceiver mReceiver = Loading Loading @@ -294,7 +296,16 @@ public class AudioSharingSwitchBarController extends BasePreferenceController public void onReceiveStateChanged( @NonNull BluetoothDevice sink, int sourceId, @NonNull BluetoothLeBroadcastReceiveState state) {} @NonNull BluetoothLeBroadcastReceiveState state) { if (BluetoothUtils.isConnected(state)) { if (mSinksInAdding.contains(sink)) { mSinksInAdding.remove(sink); } dismissLoadingStateDialogIfNeeded(); Log.d(TAG, "onReceiveStateChanged() connected, sink = " + sink + ", remaining sinks = " + mSinksInAdding); } } }; AudioSharingSwitchBarController( Loading Loading @@ -506,17 +517,20 @@ public class AudioSharingSwitchBarController extends BasePreferenceController mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ false); // deviceItems is ordered. The active device is the first place if exits. mDeviceItemsForSharing = new ArrayList<>(deviceItems); mTargetActiveSinks = new ArrayList<>(); mTargetActiveItem = null; if (!deviceItems.isEmpty() && deviceItems.get(0).isActive()) { // If active device exists for audio sharing, share to it // automatically once the broadcast is started. mTargetActiveSinks = mGroupedConnectedDevices.getOrDefault( deviceItems.get(0).getGroupId(), ImmutableList.of()); mTargetActiveItem = deviceItems.get(0); mDeviceItemsForSharing.remove(0); } if (mBroadcast != null) { mBroadcast.startPrivateBroadcast(); mSinksInAdding.clear(); // TODO: use string res once finalized. AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.show(mFragment, "Starting audio stream...")); mMetricsFeatureProvider.action( mContext, SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_ON, Loading Loading @@ -580,27 +594,30 @@ public class AudioSharingSwitchBarController extends BasePreferenceController } private void handleOnBroadcastReady() { List<BluetoothDevice> targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of() : mGroupedConnectedDevices.getOrDefault( mTargetActiveItem.getGroupId(), ImmutableList.of()); Pair<Integer, Object>[] eventData = AudioSharingUtils.buildAudioSharingDialogEventData( SettingsEnums.AUDIO_SHARING_SETTINGS, SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE, /* userTriggered= */ false, /* deviceCountInSharing= */ mTargetActiveSinks.isEmpty() ? 0 : 1, /* deviceCountInSharing= */ targetActiveSinks.isEmpty() ? 0 : 1, /* candidateDeviceCount= */ mDeviceItemsForSharing.size()); if (!mTargetActiveSinks.isEmpty()) { if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) { Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks."); AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager); addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName()); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING); mTargetActiveSinks.clear(); mTargetActiveItem = null; if (mIntentHandleStage.compareAndSet( StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(), StartIntentHandleStage.HANDLED.ordinal()) && mDeviceItemsForSharing.size() == 1) { Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device"); AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()), mBtManager); AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0); List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( target.getGroupId(), ImmutableList.of()); addSourceToTargetSinks(targetSinks, target.getName()); cleanUp(); // TODO: Add metric for auto add by intent return; Loading @@ -611,6 +628,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController StartIntentHandleStage.HANDLED.ordinal()); if (mFragment == null) { Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment."); dismissLoadingStateDialogIfNeeded(); cleanUp(); return; } Loading @@ -622,15 +640,15 @@ public class AudioSharingSwitchBarController extends BasePreferenceController new AudioSharingDialogFragment.DialogEventListener() { @Override public void onItemClick(@NonNull AudioSharingDeviceItem item) { AudioSharingUtils.addSourceToTargetSinks( mGroupedConnectedDevices.getOrDefault( item.getGroupId(), ImmutableList.of()), mBtManager); List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault( item.getGroupId(), ImmutableList.of()); addSourceToTargetSinks(targetSinks, item.getName()); cleanUp(); } @Override public void onCancelClick() { dismissLoadingStateDialogIfNeeded(); cleanUp(); } }; Loading Loading @@ -700,6 +718,27 @@ public class AudioSharingSwitchBarController extends BasePreferenceController }); } private void addSourceToTargetSinks(List<BluetoothDevice> targetActiveSinks, @NonNull String sinkName) { mSinksInAdding.addAll(targetActiveSinks); AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager); // TODO: move to res once finalized String loadingMessage = "Sharing with " + sinkName + "..."; showLoadingStateDialog(loadingMessage); } private void showLoadingStateDialog(@NonNull String loadingMessage) { AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.show(mFragment, loadingMessage)); } private void dismissLoadingStateDialogIfNeeded() { if (mSinksInAdding.isEmpty()) { AudioSharingUtils.postOnMainThread(mContext, () -> AudioSharingLoadingStateDialogFragment.dismiss(mFragment)); } } private void cleanUp() { mGroupedConnectedDevices.clear(); mDeviceItemsForSharing.clear(); Loading
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java +2 −7 Original line number Diff line number Diff line Loading @@ -150,7 +150,7 @@ public class AudioSharingLoadingStateDialogFragmentTest { } @Test public void showDialog_newMessage_dismissAndShowNewDialog() { public void showDialog_newMessage_keepAndUpdateDialog() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1); shadowMainLooper().idle(); Loading @@ -163,12 +163,7 @@ public class AudioSharingLoadingStateDialogFragmentTest { AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE2); shadowMainLooper().idle(); assertThat(dialog.isShowing()).isFalse(); AlertDialog newDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(newDialog).isNotNull(); assertThat(newDialog.isShowing()).isTrue(); view = newDialog.findViewById(R.id.message); assertThat(view).isNotNull(); assertThat(dialog.isShowing()).isTrue(); assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE2); } }
tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java +129 −20 File changed.Preview size limit exceeded, changes collapsed. Show changes