Merge "[Audiosharing] Refine share then pair flow" into main
This commit is contained in:
@@ -16,10 +16,18 @@
|
||||
|
||||
package com.android.settings.connecteddevice.audiosharing;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
@@ -27,16 +35,21 @@ import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsCategoryController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
implements AudioSharingSwitchBarController.OnAudioSharingStateChangedListener {
|
||||
private static final String TAG = "AudioSharingDashboardFrag";
|
||||
|
||||
public static final int SHARE_THEN_PAIR_REQUEST_CODE = 1002;
|
||||
|
||||
SettingsMainSwitchBar mMainSwitchBar;
|
||||
private AudioSharingDeviceVolumeGroupController mAudioSharingDeviceVolumeGroupController;
|
||||
private AudioSharingCallAudioPreferenceController mAudioSharingCallAudioPreferenceController;
|
||||
private AudioSharingPlaySoundPreferenceController mAudioSharingPlaySoundPreferenceController;
|
||||
private AudioStreamsCategoryController mAudioStreamsCategoryController;
|
||||
private AudioSharingSwitchBarController mAudioSharingSwitchBarController;
|
||||
|
||||
public AudioSharingDashboardFragment() {
|
||||
super();
|
||||
@@ -84,13 +97,38 @@ public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
final SettingsActivity activity = (SettingsActivity) getActivity();
|
||||
mMainSwitchBar = activity.getSwitchBar();
|
||||
mMainSwitchBar.setTitle(getText(R.string.audio_sharing_switch_title));
|
||||
AudioSharingSwitchBarController switchBarController =
|
||||
mAudioSharingSwitchBarController =
|
||||
new AudioSharingSwitchBarController(activity, mMainSwitchBar, this);
|
||||
switchBarController.init(this);
|
||||
getSettingsLifecycle().addObserver(switchBarController);
|
||||
mAudioSharingSwitchBarController.init(this);
|
||||
getSettingsLifecycle().addObserver(mAudioSharingSwitchBarController);
|
||||
mMainSwitchBar.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (!BluetoothUtils.isAudioSharingEnabled()) return;
|
||||
// In share then pair flow, after users be routed to pair new device page and successfully
|
||||
// pair and connect an LEA headset, the pair fragment will be finished with RESULT_OK
|
||||
// and EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE, pass the BT device to switch bar controller,
|
||||
// which is responsible for adding source to the device with loading indicator.
|
||||
if (requestCode == SHARE_THEN_PAIR_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
BluetoothDevice btDevice =
|
||||
data != null
|
||||
? data.getParcelableExtra(EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE,
|
||||
BluetoothDevice.class)
|
||||
: null;
|
||||
Log.d(TAG, "onActivityResult: RESULT_OK with device = " + btDevice);
|
||||
if (btDevice != null) {
|
||||
var unused = ThreadUtils.postOnBackgroundThread(
|
||||
() -> mAudioSharingSwitchBarController.handleAutoAddSourceAfterPair(
|
||||
btDevice));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioSharingStateChanged() {
|
||||
updateVisibilityForAttachedPreferences();
|
||||
@@ -107,11 +145,13 @@ public class AudioSharingDashboardFragment extends DashboardFragment
|
||||
AudioSharingDeviceVolumeGroupController volumeGroupController,
|
||||
AudioSharingCallAudioPreferenceController callAudioController,
|
||||
AudioSharingPlaySoundPreferenceController playSoundController,
|
||||
AudioStreamsCategoryController streamsCategoryController) {
|
||||
AudioStreamsCategoryController streamsCategoryController,
|
||||
AudioSharingSwitchBarController switchBarController) {
|
||||
mAudioSharingDeviceVolumeGroupController = volumeGroupController;
|
||||
mAudioSharingCallAudioPreferenceController = callAudioController;
|
||||
mAudioSharingPlaySoundPreferenceController = playSoundController;
|
||||
mAudioStreamsCategoryController = streamsCategoryController;
|
||||
mAudioSharingSwitchBarController = switchBarController;
|
||||
}
|
||||
|
||||
private void updateVisibilityForAttachedPreferences() {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.settings.connecteddevice.audiosharing;
|
||||
|
||||
import static com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment.SHARE_THEN_PAIR_REQUEST_CODE;
|
||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
@@ -48,19 +51,23 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
// 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 positive button in the dialog. */
|
||||
default void onPositiveClick() {}
|
||||
|
||||
/**
|
||||
* Called when users click the device item for sharing in the dialog.
|
||||
*
|
||||
* @param item The device item clicked.
|
||||
*/
|
||||
void onItemClick(AudioSharingDeviceItem item);
|
||||
default void onItemClick(@NonNull AudioSharingDeviceItem item) {}
|
||||
|
||||
/** Called when users click the cancel button in the dialog. */
|
||||
void onCancelClick();
|
||||
default void onCancelClick() {}
|
||||
}
|
||||
|
||||
@Nullable private static DialogEventListener sListener;
|
||||
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||
@Nullable private static Fragment sHost;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -70,10 +77,10 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
/**
|
||||
* Display the {@link AudioSharingDialogFragment} 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 eligible for audio sharing.
|
||||
* @param listener The callback to handle the user action on this dialog.
|
||||
* @param eventData The eventData to log with for dialog onClick events.
|
||||
* @param listener The callback to handle the user action on this dialog.
|
||||
* @param eventData The eventData to log with for dialog onClick events.
|
||||
*/
|
||||
public static void show(
|
||||
@NonNull Fragment host,
|
||||
@@ -88,6 +95,7 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
sHost = host;
|
||||
sListener = listener;
|
||||
sEventData = eventData;
|
||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||
@@ -136,23 +144,33 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
.setCustomPositiveButton(
|
||||
R.string.audio_sharing_pair_button_label,
|
||||
v -> {
|
||||
dismiss();
|
||||
new SubSettingLauncher(getContext())
|
||||
.setDestination(BluetoothPairingDetail.class.getName())
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.launch();
|
||||
if (sListener != null) {
|
||||
sListener.onPositiveClick();
|
||||
}
|
||||
logDialogPositiveBtnClick();
|
||||
dismiss();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(EXTRA_PAIR_AND_JOIN_SHARING, true);
|
||||
SubSettingLauncher launcher =
|
||||
new SubSettingLauncher(getContext())
|
||||
.setDestination(
|
||||
BluetoothPairingDetail.class.getName())
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.setArguments(args);
|
||||
if (sHost != null) {
|
||||
launcher.setResultListener(sHost, SHARE_THEN_PAIR_REQUEST_CODE);
|
||||
}
|
||||
launcher.launch();
|
||||
})
|
||||
.setCustomNegativeButton(
|
||||
R.string.audio_sharing_qrcode_button_label,
|
||||
v -> {
|
||||
dismiss();
|
||||
onCancelClick();
|
||||
new SubSettingLauncher(getContext())
|
||||
.setTitleRes(R.string.audio_streams_qr_code_page_title)
|
||||
.setDestination(AudioStreamsQrCodeFragment.class.getName())
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.launch();
|
||||
logDialogNegativeBtnClick();
|
||||
});
|
||||
} else if (deviceItems.size() == 1) {
|
||||
AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
|
||||
@@ -166,8 +184,8 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
v -> {
|
||||
if (sListener != null) {
|
||||
sListener.onItemClick(deviceItem);
|
||||
logDialogPositiveBtnClick();
|
||||
}
|
||||
logDialogPositiveBtnClick();
|
||||
dismiss();
|
||||
})
|
||||
.setCustomNegativeButton(
|
||||
@@ -182,8 +200,8 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
(AudioSharingDeviceItem item) -> {
|
||||
if (sListener != null) {
|
||||
sListener.onItemClick(item);
|
||||
logDialogPositiveBtnClick();
|
||||
}
|
||||
logDialogPositiveBtnClick();
|
||||
dismiss();
|
||||
},
|
||||
AudioSharingDeviceAdapter.ActionType.SHARE))
|
||||
@@ -196,8 +214,8 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
private void onCancelClick() {
|
||||
if (sListener != null) {
|
||||
sListener.onCancelClick();
|
||||
logDialogNegativeBtnClick();
|
||||
}
|
||||
logDialogNegativeBtnClick();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
|
||||
public class AudioSharingIncompatibleDialogFragment extends InstrumentedDialogFragment {
|
||||
private static final String TAG = "AudioSharingIncompatDlg";
|
||||
@@ -59,7 +58,7 @@ public class AudioSharingIncompatibleDialogFragment extends InstrumentedDialogFr
|
||||
*
|
||||
* @param host The Fragment this dialog will be hosted.
|
||||
*/
|
||||
public static void show(@Nullable Fragment host, @NonNull CachedBluetoothDevice cachedDevice,
|
||||
public static void show(@Nullable Fragment host, @NonNull String deviceName,
|
||||
@NonNull DialogEventListener listener) {
|
||||
if (host == null || !BluetoothUtils.isAudioSharingEnabled()) return;
|
||||
final FragmentManager manager;
|
||||
@@ -77,7 +76,7 @@ public class AudioSharingIncompatibleDialogFragment extends InstrumentedDialogFr
|
||||
}
|
||||
Log.d(TAG, "Show up the incompatible device dialog.");
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString(BUNDLE_KEY_DEVICE_NAME, cachedDevice.getName());
|
||||
bundle.putString(BUNDLE_KEY_DEVICE_NAME, deviceName);
|
||||
AudioSharingIncompatibleDialogFragment dialogFrag =
|
||||
new AudioSharingIncompatibleDialogFragment();
|
||||
dialogFrag.setArguments(bundle);
|
||||
|
||||
@@ -115,10 +115,6 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
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());
|
||||
@@ -132,6 +128,26 @@ public class AudioSharingLoadingStateDialogFragment extends InstrumentedDialogFr
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
if (mHandler != null) {
|
||||
Log.d(TAG, "onStart, postTimeOut for auto dismiss");
|
||||
mHandler.postDelayed(() -> {
|
||||
Log.d(TAG, "Try to auto dismiss dialog after timeout");
|
||||
try {
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog != null) {
|
||||
Log.d(TAG, "Dialog is not null, dismiss");
|
||||
dismissAllowingStateLoss();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.d(TAG, "Fail to dismiss: " + e.getMessage());
|
||||
}
|
||||
}, AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
|
||||
@@ -56,6 +56,7 @@ import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
@@ -78,9 +79,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
implements DefaultLifecycleObserver,
|
||||
OnCheckedChangeListener,
|
||||
LocalBluetoothProfileManager.ServiceListener,
|
||||
BluetoothCallback {
|
||||
OnCheckedChangeListener,
|
||||
LocalBluetoothProfileManager.ServiceListener,
|
||||
BluetoothCallback {
|
||||
private static final String TAG = "AudioSharingSwitchCtlr";
|
||||
private static final String PREF_KEY = "audio_sharing_main_switch";
|
||||
|
||||
@@ -464,6 +465,18 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
this.mFragment = fragment;
|
||||
}
|
||||
|
||||
/** Handle auto add source to the just paired device in share then pair flow. */
|
||||
public void handleAutoAddSourceAfterPair(@NonNull BluetoothDevice device) {
|
||||
CachedBluetoothDeviceManager deviceManager =
|
||||
mBtManager == null ? null : mBtManager.getCachedDeviceManager();
|
||||
CachedBluetoothDevice cachedDevice =
|
||||
deviceManager == null ? null : deviceManager.findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
Log.d(TAG, "handleAutoAddSourceAfterPair, device = " + device.getAnonymizedAddress());
|
||||
addSourceToTargetSinks(ImmutableList.of(device), cachedDevice.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/** Test only: set callback registration status in tests. */
|
||||
@VisibleForTesting
|
||||
void setCallbacksRegistered(boolean registered) {
|
||||
@@ -610,8 +623,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING);
|
||||
mTargetActiveItem = null;
|
||||
if (mIntentHandleStage.compareAndSet(
|
||||
StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(),
|
||||
StartIntentHandleStage.HANDLED.ordinal())
|
||||
StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(),
|
||||
StartIntentHandleStage.HANDLED.ordinal())
|
||||
&& mDeviceItemsForSharing.size() == 1) {
|
||||
Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device");
|
||||
AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0);
|
||||
@@ -638,6 +651,13 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
private void showDialog(Pair<Integer, Object>[] eventData) {
|
||||
AudioSharingDialogFragment.DialogEventListener listener =
|
||||
new AudioSharingDialogFragment.DialogEventListener() {
|
||||
@Override
|
||||
public void onPositiveClick() {
|
||||
// Could go to other pages, dismiss the loading dialog.
|
||||
dismissLoadingStateDialogIfNeeded();
|
||||
cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(@NonNull AudioSharingDeviceItem item) {
|
||||
List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
|
||||
@@ -648,6 +668,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
|
||||
@Override
|
||||
public void onCancelClick() {
|
||||
// Could go to other pages, dismiss the loading dialog.
|
||||
dismissLoadingStateDialogIfNeeded();
|
||||
cleanUp();
|
||||
}
|
||||
@@ -669,8 +690,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
@NonNull ViewGroup host, @NonNull View view, @NonNull AccessibilityEvent event) {
|
||||
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
|
||||
&& (event.getContentChangeTypes()
|
||||
& AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED)
|
||||
!= 0) {
|
||||
& AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED)
|
||||
!= 0) {
|
||||
Log.d(TAG, "Skip accessibility event for CONTENT_CHANGE_TYPE_ENABLED");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user