[Audiosharing] Log action in audio sharing dialogs
P3 for add audio sharing loggings Bug: 331515891 Test: atest Change-Id: Iea29e74e00c239e8cb8cddee6eae71ba902add01
This commit is contained in:
@@ -20,9 +20,11 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
@@ -48,13 +50,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
* @param item The device item clicked.
|
* @param item The device item clicked.
|
||||||
*/
|
*/
|
||||||
void onItemClick(AudioSharingDeviceItem item);
|
void onItemClick(AudioSharingDeviceItem item);
|
||||||
|
|
||||||
|
/** Called when users click the cancel button in the dialog. */
|
||||||
|
void onCancelClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable private static DialogEventListener sListener;
|
@Nullable private static DialogEventListener sListener;
|
||||||
|
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
return SettingsEnums.DIALOG_START_AUDIO_SHARING;
|
return SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,14 +69,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
* @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 deviceItems The connected device items eligible for audio sharing.
|
||||||
* @param listener The callback to handle the user action on this dialog.
|
* @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(
|
public static void show(
|
||||||
@NonNull Fragment host,
|
@NonNull Fragment host,
|
||||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||||
@NonNull DialogEventListener listener) {
|
@NonNull DialogEventListener listener,
|
||||||
|
@NonNull Pair<Integer, Object>[] eventData) {
|
||||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||||
final FragmentManager manager = host.getChildFragmentManager();
|
final FragmentManager manager = host.getChildFragmentManager();
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
|
sEventData = eventData;
|
||||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||||
if (dialog != null) {
|
if (dialog != null) {
|
||||||
Log.d(TAG, "Dialog is showing, return.");
|
Log.d(TAG, "Dialog is showing, return.");
|
||||||
@@ -84,7 +93,19 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
dialogFrag.show(manager, TAG);
|
dialogFrag.show(manager, TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the tag of {@link AudioSharingDialogFragment} dialog. */
|
||||||
|
public static @NonNull String tag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test only: get the event data passed to the dialog. */
|
||||||
|
@VisibleForTesting
|
||||||
|
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||||
|
return sEventData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
List<AudioSharingDeviceItem> deviceItems =
|
List<AudioSharingDeviceItem> deviceItems =
|
||||||
@@ -93,12 +114,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
AudioSharingDialogFactory.newBuilder(getActivity())
|
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||||
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||||
.setIsCustomBodyEnabled(true);
|
.setIsCustomBodyEnabled(true);
|
||||||
|
if (deviceItems == null) {
|
||||||
|
Log.d(TAG, "Create dialog error: null deviceItems");
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
if (deviceItems.isEmpty()) {
|
if (deviceItems.isEmpty()) {
|
||||||
builder.setTitle(R.string.audio_sharing_share_dialog_title)
|
builder.setTitle(R.string.audio_sharing_share_dialog_title)
|
||||||
.setCustomImage(R.drawable.audio_sharing_guidance)
|
.setCustomImage(R.drawable.audio_sharing_guidance)
|
||||||
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
|
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
|
||||||
.setNegativeButton(
|
.setNegativeButton(
|
||||||
R.string.audio_sharing_close_button_label, (dig, which) -> dismiss());
|
R.string.audio_sharing_close_button_label,
|
||||||
|
(dig, which) -> onCancelClick());
|
||||||
} else if (deviceItems.size() == 1) {
|
} else if (deviceItems.size() == 1) {
|
||||||
AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
|
AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
|
||||||
builder.setTitle(
|
builder.setTitle(
|
||||||
@@ -111,11 +137,16 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
v -> {
|
v -> {
|
||||||
if (sListener != null) {
|
if (sListener != null) {
|
||||||
sListener.onItemClick(deviceItem);
|
sListener.onItemClick(deviceItem);
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
})
|
})
|
||||||
.setCustomNegativeButton(
|
.setCustomNegativeButton(
|
||||||
R.string.audio_sharing_no_thanks_button_label, v -> dismiss());
|
R.string.audio_sharing_no_thanks_button_label, v -> onCancelClick());
|
||||||
} else {
|
} else {
|
||||||
builder.setTitle(R.string.audio_sharing_share_with_more_dialog_title)
|
builder.setTitle(R.string.audio_sharing_share_with_more_dialog_title)
|
||||||
.setCustomMessage(R.string.audio_sharing_dialog_share_more_content)
|
.setCustomMessage(R.string.audio_sharing_dialog_share_more_content)
|
||||||
@@ -130,8 +161,20 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
|||||||
dismiss();
|
dismiss();
|
||||||
},
|
},
|
||||||
AudioSharingDeviceAdapter.ActionType.SHARE))
|
AudioSharingDeviceAdapter.ActionType.SHARE))
|
||||||
.setCustomNegativeButton(com.android.settings.R.string.cancel, v -> dismiss());
|
.setCustomNegativeButton(
|
||||||
|
com.android.settings.R.string.cancel, v -> onCancelClick());
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onCancelClick() {
|
||||||
|
if (sListener != null) {
|
||||||
|
sListener.onCancelClick();
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
|
}
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import android.bluetooth.BluetoothLeBroadcastMetadata;
|
|||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -33,15 +34,21 @@ import androidx.fragment.app.Fragment;
|
|||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public class AudioSharingDialogHandler {
|
public class AudioSharingDialogHandler {
|
||||||
@@ -51,6 +58,7 @@ public class AudioSharingDialogHandler {
|
|||||||
@Nullable private final LocalBluetoothManager mLocalBtManager;
|
@Nullable private final LocalBluetoothManager mLocalBtManager;
|
||||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private List<BluetoothDevice> mTargetSinks = new ArrayList<>();
|
private List<BluetoothDevice> mTargetSinks = new ArrayList<>();
|
||||||
|
|
||||||
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
||||||
@@ -119,9 +127,7 @@ public class AudioSharingDialogHandler {
|
|||||||
new SubSettingLauncher(mContext)
|
new SubSettingLauncher(mContext)
|
||||||
.setDestination(AudioSharingDashboardFragment.class.getName())
|
.setDestination(AudioSharingDashboardFragment.class.getName())
|
||||||
.setSourceMetricsCategory(
|
.setSourceMetricsCategory(
|
||||||
(mHostFragment != null
|
(mHostFragment instanceof DashboardFragment)
|
||||||
&& mHostFragment
|
|
||||||
instanceof DashboardFragment)
|
|
||||||
? ((DashboardFragment) mHostFragment)
|
? ((DashboardFragment) mHostFragment)
|
||||||
.getMetricsCategory()
|
.getMetricsCategory()
|
||||||
: SettingsEnums.PAGE_UNKNOWN)
|
: SettingsEnums.PAGE_UNKNOWN)
|
||||||
@@ -146,6 +152,7 @@ public class AudioSharingDialogHandler {
|
|||||||
mLocalBtManager != null
|
mLocalBtManager != null
|
||||||
? mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile()
|
? mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile()
|
||||||
: null;
|
: null;
|
||||||
|
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Register callbacks for dialog handler */
|
/** Register callbacks for dialog handler */
|
||||||
@@ -191,6 +198,18 @@ public class AudioSharingDialogHandler {
|
|||||||
List<AudioSharingDeviceItem> deviceItemsInSharingSession =
|
List<AudioSharingDeviceItem> deviceItemsInSharingSession =
|
||||||
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
|
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
|
||||||
mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
|
mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
|
||||||
|
AudioSharingStopDialogFragment.DialogEventListener listener =
|
||||||
|
() -> {
|
||||||
|
cachedDevice.setActive();
|
||||||
|
AudioSharingUtils.stopBroadcasting(mLocalBtManager);
|
||||||
|
};
|
||||||
|
Pair<Integer, Object>[] eventData =
|
||||||
|
AudioSharingUtils.buildAudioSharingDialogEventData(
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY,
|
||||||
|
SettingsEnums.DIALOG_STOP_AUDIO_SHARING,
|
||||||
|
userTriggered,
|
||||||
|
deviceItemsInSharingSession.size(),
|
||||||
|
/* candidateDeviceCount= */ 0);
|
||||||
postOnMainThread(
|
postOnMainThread(
|
||||||
() -> {
|
() -> {
|
||||||
closeOpeningDialogsOtherThan(AudioSharingStopDialogFragment.tag());
|
closeOpeningDialogsOtherThan(AudioSharingStopDialogFragment.tag());
|
||||||
@@ -198,10 +217,8 @@ public class AudioSharingDialogHandler {
|
|||||||
mHostFragment,
|
mHostFragment,
|
||||||
deviceItemsInSharingSession,
|
deviceItemsInSharingSession,
|
||||||
cachedDevice,
|
cachedDevice,
|
||||||
() -> {
|
listener,
|
||||||
cachedDevice.setActive();
|
eventData);
|
||||||
AudioSharingUtils.stopBroadcasting(mLocalBtManager);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (userTriggered) {
|
if (userTriggered) {
|
||||||
@@ -252,6 +269,20 @@ public class AudioSharingDialogHandler {
|
|||||||
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
|
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
|
||||||
// connected during a sharing session.
|
// connected during a sharing session.
|
||||||
if (deviceItemsInSharingSession.size() >= 2) {
|
if (deviceItemsInSharingSession.size() >= 2) {
|
||||||
|
AudioSharingDisconnectDialogFragment.DialogEventListener listener =
|
||||||
|
(AudioSharingDeviceItem item) -> {
|
||||||
|
// Remove all sources from the device user clicked
|
||||||
|
removeSourceForGroup(item.getGroupId(), groupedDevices);
|
||||||
|
// Add current broadcast to the latest connected device
|
||||||
|
addSourceForGroup(groupId, groupedDevices);
|
||||||
|
};
|
||||||
|
Pair<Integer, Object>[] eventData =
|
||||||
|
AudioSharingUtils.buildAudioSharingDialogEventData(
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY,
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE,
|
||||||
|
userTriggered,
|
||||||
|
deviceItemsInSharingSession.size(),
|
||||||
|
/* candidateDeviceCount= */ 1);
|
||||||
postOnMainThread(
|
postOnMainThread(
|
||||||
() -> {
|
() -> {
|
||||||
closeOpeningDialogsOtherThan(
|
closeOpeningDialogsOtherThan(
|
||||||
@@ -260,23 +291,13 @@ public class AudioSharingDialogHandler {
|
|||||||
mHostFragment,
|
mHostFragment,
|
||||||
deviceItemsInSharingSession,
|
deviceItemsInSharingSession,
|
||||||
cachedDevice,
|
cachedDevice,
|
||||||
(AudioSharingDeviceItem item) -> {
|
listener,
|
||||||
// Remove all sources from the device user clicked
|
eventData);
|
||||||
removeSourceForGroup(item.getGroupId(), groupedDevices);
|
|
||||||
// Add current broadcast to the latest connected device
|
|
||||||
addSourceForGroup(groupId, groupedDevices);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Show audio sharing join dialog when the first or second eligible (LE audio)
|
// Show audio sharing join dialog when the first or second eligible (LE audio)
|
||||||
// remote device connected during a sharing session.
|
// remote device connected during a sharing session.
|
||||||
postOnMainThread(
|
AudioSharingJoinDialogFragment.DialogEventListener listener =
|
||||||
() -> {
|
|
||||||
closeOpeningDialogsOtherThan(AudioSharingJoinDialogFragment.tag());
|
|
||||||
AudioSharingJoinDialogFragment.show(
|
|
||||||
mHostFragment,
|
|
||||||
deviceItemsInSharingSession,
|
|
||||||
cachedDevice,
|
|
||||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onShareClick() {
|
public void onShareClick() {
|
||||||
@@ -285,7 +306,23 @@ public class AudioSharingDialogHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancelClick() {}
|
public void onCancelClick() {}
|
||||||
});
|
};
|
||||||
|
Pair<Integer, Object>[] eventData =
|
||||||
|
AudioSharingUtils.buildAudioSharingDialogEventData(
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY,
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE,
|
||||||
|
userTriggered,
|
||||||
|
deviceItemsInSharingSession.size(),
|
||||||
|
/* candidateDeviceCount= */ 1);
|
||||||
|
postOnMainThread(
|
||||||
|
() -> {
|
||||||
|
closeOpeningDialogsOtherThan(AudioSharingJoinDialogFragment.tag());
|
||||||
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mHostFragment,
|
||||||
|
deviceItemsInSharingSession,
|
||||||
|
cachedDevice,
|
||||||
|
listener,
|
||||||
|
eventData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -302,13 +339,7 @@ public class AudioSharingDialogHandler {
|
|||||||
// Show audio sharing join dialog when the second eligible (LE audio) remote
|
// Show audio sharing join dialog when the second eligible (LE audio) remote
|
||||||
// device connect and no sharing session.
|
// device connect and no sharing session.
|
||||||
if (deviceItems.size() == 1) {
|
if (deviceItems.size() == 1) {
|
||||||
postOnMainThread(
|
AudioSharingJoinDialogFragment.DialogEventListener listener =
|
||||||
() -> {
|
|
||||||
closeOpeningDialogsOtherThan(AudioSharingJoinDialogFragment.tag());
|
|
||||||
AudioSharingJoinDialogFragment.show(
|
|
||||||
mHostFragment,
|
|
||||||
deviceItems,
|
|
||||||
cachedDevice,
|
|
||||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onShareClick() {
|
public void onShareClick() {
|
||||||
@@ -319,10 +350,7 @@ public class AudioSharingDialogHandler {
|
|||||||
mTargetSinks.add(device.getDevice());
|
mTargetSinks.add(device.getDevice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(
|
Log.d(TAG, "Start broadcast with sinks = " + mTargetSinks.size());
|
||||||
TAG,
|
|
||||||
"Start broadcast with sinks: "
|
|
||||||
+ mTargetSinks.size());
|
|
||||||
if (mBroadcast != null) {
|
if (mBroadcast != null) {
|
||||||
mBroadcast.startPrivateBroadcast();
|
mBroadcast.startPrivateBroadcast();
|
||||||
}
|
}
|
||||||
@@ -334,7 +362,20 @@ public class AudioSharingDialogHandler {
|
|||||||
cachedDevice.setActive();
|
cachedDevice.setActive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
Pair<Integer, Object>[] eventData =
|
||||||
|
AudioSharingUtils.buildAudioSharingDialogEventData(
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY,
|
||||||
|
SettingsEnums.DIALOG_START_AUDIO_SHARING,
|
||||||
|
userTriggered,
|
||||||
|
/* deviceCountInSharing= */ 0,
|
||||||
|
/* candidateDeviceCount= */ 2);
|
||||||
|
postOnMainThread(
|
||||||
|
() -> {
|
||||||
|
closeOpeningDialogsOtherThan(AudioSharingJoinDialogFragment.tag());
|
||||||
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mHostFragment, deviceItems, cachedDevice, listener, eventData);
|
||||||
});
|
});
|
||||||
} else if (userTriggered) {
|
} else if (userTriggered) {
|
||||||
cachedDevice.setActive();
|
cachedDevice.setActive();
|
||||||
@@ -346,9 +387,12 @@ public class AudioSharingDialogHandler {
|
|||||||
if (mHostFragment == null) return;
|
if (mHostFragment == null) return;
|
||||||
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
|
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
|
||||||
for (Fragment fragment : fragments) {
|
for (Fragment fragment : fragments) {
|
||||||
if (fragment instanceof DialogFragment && !fragment.getTag().equals(tag)) {
|
if (fragment instanceof DialogFragment
|
||||||
|
&& fragment.getTag() != null
|
||||||
|
&& !fragment.getTag().equals(tag)) {
|
||||||
Log.d(TAG, "Remove staled opening dialog " + fragment.getTag());
|
Log.d(TAG, "Remove staled opening dialog " + fragment.getTag());
|
||||||
((DialogFragment) fragment).dismiss();
|
((DialogFragment) fragment).dismiss();
|
||||||
|
logDialogDismissEvent(fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,6 +409,7 @@ public class AudioSharingDialogHandler {
|
|||||||
&& AudioSharingUtils.getGroupId(device) == groupId) {
|
&& AudioSharingUtils.getGroupId(device) == groupId) {
|
||||||
Log.d(TAG, "Remove staled opening dialog for group " + groupId);
|
Log.d(TAG, "Remove staled opening dialog for group " + groupId);
|
||||||
((DialogFragment) fragment).dismiss();
|
((DialogFragment) fragment).dismiss();
|
||||||
|
logDialogDismissEvent(fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,6 +427,7 @@ public class AudioSharingDialogHandler {
|
|||||||
"Remove staled opening dialog for device "
|
"Remove staled opening dialog for device "
|
||||||
+ cachedDevice.getDevice().getAnonymizedAddress());
|
+ cachedDevice.getDevice().getAnonymizedAddress());
|
||||||
((DialogFragment) fragment).dismiss();
|
((DialogFragment) fragment).dismiss();
|
||||||
|
logDialogDismissEvent(fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,9 +455,9 @@ public class AudioSharingDialogHandler {
|
|||||||
Log.d(TAG, "Fail to remove source for group " + groupId);
|
Log.d(TAG, "Fail to remove source for group " + groupId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
groupedDevices.get(groupId).stream()
|
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
|
||||||
.map(CachedBluetoothDevice::getDevice)
|
.map(CachedBluetoothDevice::getDevice)
|
||||||
.filter(device -> device != null)
|
.filter(Objects::nonNull)
|
||||||
.forEach(
|
.forEach(
|
||||||
device -> {
|
device -> {
|
||||||
for (BluetoothLeBroadcastReceiveState source :
|
for (BluetoothLeBroadcastReceiveState source :
|
||||||
@@ -431,9 +477,9 @@ public class AudioSharingDialogHandler {
|
|||||||
Log.d(TAG, "Fail to add source due to invalid group id, group = " + groupId);
|
Log.d(TAG, "Fail to add source due to invalid group id, group = " + groupId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
groupedDevices.get(groupId).stream()
|
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
|
||||||
.map(CachedBluetoothDevice::getDevice)
|
.map(CachedBluetoothDevice::getDevice)
|
||||||
.filter(device -> device != null)
|
.filter(Objects::nonNull)
|
||||||
.forEach(
|
.forEach(
|
||||||
device ->
|
device ->
|
||||||
mAssistant.addSource(
|
mAssistant.addSource(
|
||||||
@@ -449,4 +495,29 @@ public class AudioSharingDialogHandler {
|
|||||||
private boolean isBroadcasting() {
|
private boolean isBroadcasting() {
|
||||||
return mBroadcast != null && mBroadcast.isEnabled(null);
|
return mBroadcast != null && mBroadcast.isEnabled(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logDialogDismissEvent(Fragment fragment) {
|
||||||
|
var unused =
|
||||||
|
ThreadUtils.postOnBackgroundThread(
|
||||||
|
() -> {
|
||||||
|
int pageId = SettingsEnums.PAGE_UNKNOWN;
|
||||||
|
if (fragment instanceof AudioSharingJoinDialogFragment) {
|
||||||
|
pageId =
|
||||||
|
((AudioSharingJoinDialogFragment) fragment)
|
||||||
|
.getMetricsCategory();
|
||||||
|
} else if (fragment instanceof AudioSharingStopDialogFragment) {
|
||||||
|
pageId =
|
||||||
|
((AudioSharingStopDialogFragment) fragment)
|
||||||
|
.getMetricsCategory();
|
||||||
|
} else if (fragment instanceof AudioSharingDisconnectDialogFragment) {
|
||||||
|
pageId =
|
||||||
|
((AudioSharingDisconnectDialogFragment) fragment)
|
||||||
|
.getMetricsCategory();
|
||||||
|
}
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
mContext,
|
||||||
|
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS,
|
||||||
|
pageId);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,16 +20,20 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -55,6 +59,7 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
|||||||
|
|
||||||
@Nullable private static DialogEventListener sListener;
|
@Nullable private static DialogEventListener sListener;
|
||||||
@Nullable private static CachedBluetoothDevice sNewDevice;
|
@Nullable private static CachedBluetoothDevice sNewDevice;
|
||||||
|
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -70,12 +75,14 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
|||||||
* @param deviceItems The existing connected device items in audio sharing session.
|
* @param deviceItems The existing connected device items in audio sharing session.
|
||||||
* @param newDevice The latest connected device triggered this dialog.
|
* @param newDevice The latest connected device triggered this dialog.
|
||||||
* @param listener The callback to handle the user action on this dialog.
|
* @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(
|
public static void show(
|
||||||
@NonNull Fragment host,
|
@NonNull Fragment host,
|
||||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||||
@NonNull CachedBluetoothDevice newDevice,
|
@NonNull CachedBluetoothDevice newDevice,
|
||||||
@NonNull DialogEventListener listener) {
|
@NonNull DialogEventListener listener,
|
||||||
|
@NonNull Pair<Integer, Object>[] eventData) {
|
||||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||||
FragmentManager manager = host.getChildFragmentManager();
|
FragmentManager manager = host.getChildFragmentManager();
|
||||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||||
@@ -91,6 +98,7 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
|||||||
newGroupId));
|
newGroupId));
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
sNewDevice = newDevice;
|
sNewDevice = newDevice;
|
||||||
|
sEventData = eventData;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Log.d(
|
Log.d(
|
||||||
@@ -101,10 +109,22 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
|||||||
+ "dismiss current dialog.",
|
+ "dismiss current dialog.",
|
||||||
newGroupId));
|
newGroupId));
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
|
var unused =
|
||||||
|
ThreadUtils.postOnBackgroundThread(
|
||||||
|
() ->
|
||||||
|
FeatureFactory.getFeatureFactory()
|
||||||
|
.getMetricsFeatureProvider()
|
||||||
|
.action(
|
||||||
|
dialog.getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS,
|
||||||
|
SettingsEnums
|
||||||
|
.DIALOG_AUDIO_SHARING_SWITCH_DEVICE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
sNewDevice = newDevice;
|
sNewDevice = newDevice;
|
||||||
|
sEventData = eventData;
|
||||||
Log.d(TAG, "Show up the dialog.");
|
Log.d(TAG, "Show up the dialog.");
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
||||||
@@ -125,28 +145,54 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
|||||||
return sNewDevice;
|
return sNewDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test only: get the event data passed to the dialog. */
|
||||||
|
@VisibleForTesting
|
||||||
|
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||||
|
return sEventData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
List<AudioSharingDeviceItem> deviceItems =
|
List<AudioSharingDeviceItem> deviceItems =
|
||||||
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
||||||
return AudioSharingDialogFactory.newBuilder(getActivity())
|
AudioSharingDialogFactory.DialogBuilder builder =
|
||||||
|
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||||
.setTitle(R.string.audio_sharing_disconnect_dialog_title)
|
.setTitle(R.string.audio_sharing_disconnect_dialog_title)
|
||||||
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||||
.setIsCustomBodyEnabled(true)
|
.setIsCustomBodyEnabled(true)
|
||||||
.setCustomMessage(R.string.audio_sharing_dialog_disconnect_content)
|
.setCustomMessage(R.string.audio_sharing_dialog_disconnect_content)
|
||||||
.setCustomDeviceActions(
|
.setCustomNegativeButton(
|
||||||
|
com.android.settings.R.string.cancel,
|
||||||
|
v -> {
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
if (deviceItems == null) {
|
||||||
|
Log.d(TAG, "Create dialog error: null deviceItems");
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
builder.setCustomDeviceActions(
|
||||||
new AudioSharingDeviceAdapter(
|
new AudioSharingDeviceAdapter(
|
||||||
getContext(),
|
getContext(),
|
||||||
deviceItems,
|
deviceItems,
|
||||||
(AudioSharingDeviceItem item) -> {
|
(AudioSharingDeviceItem item) -> {
|
||||||
if (sListener != null) {
|
if (sListener != null) {
|
||||||
sListener.onItemClick(item);
|
sListener.onItemClick(item);
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
},
|
},
|
||||||
AudioSharingDeviceAdapter.ActionType.REMOVE))
|
AudioSharingDeviceAdapter.ActionType.REMOVE));
|
||||||
.setCustomNegativeButton(com.android.settings.R.string.cancel, v -> dismiss())
|
return builder.build();
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,9 +20,11 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
@@ -52,6 +54,7 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
|||||||
|
|
||||||
@Nullable private static DialogEventListener sListener;
|
@Nullable private static DialogEventListener sListener;
|
||||||
@Nullable private static CachedBluetoothDevice sNewDevice;
|
@Nullable private static CachedBluetoothDevice sNewDevice;
|
||||||
|
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -69,16 +72,19 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
|||||||
* @param deviceItems The existing connected device items eligible for audio sharing.
|
* @param deviceItems The existing connected device items eligible for audio sharing.
|
||||||
* @param newDevice The latest connected device triggered this dialog.
|
* @param newDevice The latest connected device triggered this dialog.
|
||||||
* @param listener The callback to handle the user action on this dialog.
|
* @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(
|
public static void show(
|
||||||
@NonNull Fragment host,
|
@NonNull Fragment host,
|
||||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||||
@NonNull CachedBluetoothDevice newDevice,
|
@NonNull CachedBluetoothDevice newDevice,
|
||||||
@NonNull DialogEventListener listener) {
|
@NonNull DialogEventListener listener,
|
||||||
|
@NonNull Pair<Integer, Object>[] eventData) {
|
||||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||||
final FragmentManager manager = host.getChildFragmentManager();
|
final FragmentManager manager = host.getChildFragmentManager();
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
sNewDevice = newDevice;
|
sNewDevice = newDevice;
|
||||||
|
sEventData = eventData;
|
||||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||||
if (dialog != null) {
|
if (dialog != null) {
|
||||||
Log.d(TAG, "Dialog is showing, update the content.");
|
Log.d(TAG, "Dialog is showing, update the content.");
|
||||||
@@ -104,7 +110,14 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
|||||||
return sNewDevice;
|
return sNewDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test only: get the event data passed to the dialog. */
|
||||||
|
@VisibleForTesting
|
||||||
|
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||||
|
return sEventData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
List<AudioSharingDeviceItem> deviceItems =
|
List<AudioSharingDeviceItem> deviceItems =
|
||||||
@@ -121,6 +134,11 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
|||||||
v -> {
|
v -> {
|
||||||
if (sListener != null) {
|
if (sListener != null) {
|
||||||
sListener.onShareClick();
|
sListener.onShareClick();
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
})
|
})
|
||||||
@@ -129,11 +147,20 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
|||||||
v -> {
|
v -> {
|
||||||
if (sListener != null) {
|
if (sListener != null) {
|
||||||
sListener.onCancelClick();
|
sListener.onCancelClick();
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
if (deviceItems == null) {
|
||||||
|
Log.d(TAG, "Fail to create dialog: null deviceItems");
|
||||||
|
} else {
|
||||||
updateDialog(deviceItems, newDeviceName, dialog);
|
updateDialog(deviceItems, newDeviceName, dialog);
|
||||||
|
}
|
||||||
dialog.show();
|
dialog.show();
|
||||||
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
||||||
return dialog;
|
return dialog;
|
||||||
|
@@ -20,16 +20,20 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
@@ -52,6 +56,7 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
|
|
||||||
@Nullable private static DialogEventListener sListener;
|
@Nullable private static DialogEventListener sListener;
|
||||||
@Nullable private static CachedBluetoothDevice sCachedDevice;
|
@Nullable private static CachedBluetoothDevice sCachedDevice;
|
||||||
|
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMetricsCategory() {
|
public int getMetricsCategory() {
|
||||||
@@ -67,12 +72,14 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
* @param deviceItems The existing connected device items in audio sharing session.
|
* @param deviceItems The existing connected device items in audio sharing session.
|
||||||
* @param newDevice The latest connected device triggered this dialog.
|
* @param newDevice The latest connected device triggered this dialog.
|
||||||
* @param listener The callback to handle the user action on this dialog.
|
* @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(
|
public static void show(
|
||||||
@NonNull Fragment host,
|
@NonNull Fragment host,
|
||||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||||
@NonNull CachedBluetoothDevice newDevice,
|
@NonNull CachedBluetoothDevice newDevice,
|
||||||
@NonNull DialogEventListener listener) {
|
@NonNull DialogEventListener listener,
|
||||||
|
@NonNull Pair<Integer, Object>[] eventData) {
|
||||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||||
final FragmentManager manager = host.getChildFragmentManager();
|
final FragmentManager manager = host.getChildFragmentManager();
|
||||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||||
@@ -88,6 +95,7 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
newGroupId));
|
newGroupId));
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
sCachedDevice = newDevice;
|
sCachedDevice = newDevice;
|
||||||
|
sEventData = eventData;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Log.d(
|
Log.d(
|
||||||
@@ -98,10 +106,21 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
+ "dismiss current dialog.",
|
+ "dismiss current dialog.",
|
||||||
newGroupId));
|
newGroupId));
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
|
var unused =
|
||||||
|
ThreadUtils.postOnBackgroundThread(
|
||||||
|
() ->
|
||||||
|
FeatureFactory.getFeatureFactory()
|
||||||
|
.getMetricsFeatureProvider()
|
||||||
|
.action(
|
||||||
|
dialog.getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS,
|
||||||
|
SettingsEnums.DIALOG_STOP_AUDIO_SHARING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sListener = listener;
|
sListener = listener;
|
||||||
sCachedDevice = newDevice;
|
sCachedDevice = newDevice;
|
||||||
|
sEventData = eventData;
|
||||||
Log.d(TAG, "Show up the dialog.");
|
Log.d(TAG, "Show up the dialog.");
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
||||||
@@ -121,13 +140,22 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
return sCachedDevice;
|
return sCachedDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test only: get the event data passed to the dialog. */
|
||||||
|
@VisibleForTesting
|
||||||
|
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||||
|
return sEventData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
List<AudioSharingDeviceItem> deviceItems =
|
List<AudioSharingDeviceItem> deviceItems =
|
||||||
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
||||||
String newDeviceName = arguments.getString(BUNDLE_KEY_NEW_DEVICE_NAME);
|
String newDeviceName = arguments.getString(BUNDLE_KEY_NEW_DEVICE_NAME);
|
||||||
String customMessage =
|
String customMessage = "";
|
||||||
|
if (deviceItems != null) {
|
||||||
|
customMessage =
|
||||||
deviceItems.size() == 1
|
deviceItems.size() == 1
|
||||||
? getString(
|
? getString(
|
||||||
R.string.audio_sharing_stop_dialog_content,
|
R.string.audio_sharing_stop_dialog_content,
|
||||||
@@ -137,7 +165,9 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
R.string.audio_sharing_stop_dialog_with_two_content,
|
R.string.audio_sharing_stop_dialog_with_two_content,
|
||||||
deviceItems.get(0).getName(),
|
deviceItems.get(0).getName(),
|
||||||
deviceItems.get(1).getName())
|
deviceItems.get(1).getName())
|
||||||
: getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
: getString(
|
||||||
|
R.string.audio_sharing_stop_dialog_with_more_content));
|
||||||
|
}
|
||||||
AlertDialog dialog =
|
AlertDialog dialog =
|
||||||
AudioSharingDialogFactory.newBuilder(getActivity())
|
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||||
.setTitle(
|
.setTitle(
|
||||||
@@ -150,10 +180,21 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
|||||||
(dlg, which) -> {
|
(dlg, which) -> {
|
||||||
if (sListener != null) {
|
if (sListener != null) {
|
||||||
sListener.onStopSharingClick();
|
sListener.onStopSharingClick();
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||||
|
sEventData);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(
|
.setNegativeButton(
|
||||||
com.android.settings.R.string.cancel, (dlg, which) -> dismiss())
|
com.android.settings.R.string.cancel,
|
||||||
|
(dlg, which) ->
|
||||||
|
mMetricsFeatureProvider.action(
|
||||||
|
getContext(),
|
||||||
|
SettingsEnums
|
||||||
|
.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||||
|
sEventData))
|
||||||
.build();
|
.build();
|
||||||
dialog.show();
|
dialog.show();
|
||||||
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing;
|
package com.android.settings.connecteddevice.audiosharing;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcast;
|
import android.bluetooth.BluetoothLeBroadcast;
|
||||||
@@ -29,24 +30,27 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.util.FeatureFlagUtils;
|
import android.util.FeatureFlagUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
|
||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@@ -56,6 +60,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -91,14 +96,15 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
||||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
@Nullable private DashboardFragment mFragment;
|
@Nullable private Fragment mFragment;
|
||||||
private final Executor mExecutor;
|
private final Executor mExecutor;
|
||||||
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
private final OnAudioSharingStateChangedListener mListener;
|
private final OnAudioSharingStateChangedListener mListener;
|
||||||
private Map<Integer, List<CachedBluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
|
private Map<Integer, List<CachedBluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
|
||||||
private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>();
|
private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>();
|
||||||
private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>();
|
private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>();
|
||||||
@VisibleForTesting IntentFilter mIntentFilter;
|
@VisibleForTesting IntentFilter mIntentFilter;
|
||||||
private AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
|
private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BroadcastReceiver mReceiver =
|
BroadcastReceiver mReceiver =
|
||||||
@@ -110,7 +116,8 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
@VisibleForTesting
|
||||||
|
protected final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
||||||
new BluetoothLeBroadcast.Callback() {
|
new BluetoothLeBroadcast.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onBroadcastStarted(int reason, int broadcastId) {
|
public void onBroadcastStarted(int reason, int broadcastId) {
|
||||||
@@ -182,7 +189,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
public void onPlaybackStopped(int reason, int broadcastId) {}
|
public void onPlaybackStopped(int reason, int broadcastId) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
||||||
new BluetoothLeBroadcastAssistant.Callback() {
|
new BluetoothLeBroadcastAssistant.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSearchStarted(int reason) {}
|
public void onSearchStarted(int reason) {}
|
||||||
@@ -251,9 +258,9 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceiveStateChanged(
|
public void onReceiveStateChanged(
|
||||||
BluetoothDevice sink,
|
@NonNull BluetoothDevice sink,
|
||||||
int sourceId,
|
int sourceId,
|
||||||
BluetoothLeBroadcastReceiveState state) {}
|
@NonNull BluetoothLeBroadcastReceiveState state) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioSharingSwitchBarController(
|
AudioSharingSwitchBarController(
|
||||||
@@ -273,6 +280,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
? null
|
? null
|
||||||
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
||||||
mExecutor = Executors.newSingleThreadExecutor();
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -378,7 +386,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
*
|
*
|
||||||
* @param fragment The fragment to host the {@link AudioSharingSwitchBarController} dialog.
|
* @param fragment The fragment to host the {@link AudioSharingSwitchBarController} dialog.
|
||||||
*/
|
*/
|
||||||
public void init(DashboardFragment fragment) {
|
public void init(@NonNull Fragment fragment) {
|
||||||
this.mFragment = fragment;
|
this.mFragment = fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,34 +502,58 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnBroadcastReady() {
|
private void handleOnBroadcastReady() {
|
||||||
|
Pair<Integer, Object>[] eventData =
|
||||||
|
AudioSharingUtils.buildAudioSharingDialogEventData(
|
||||||
|
SettingsEnums.AUDIO_SHARING_SETTINGS,
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE,
|
||||||
|
/* userTriggered= */ false,
|
||||||
|
/* deviceCountInSharing= */ mTargetActiveSinks.isEmpty() ? 0 : 1,
|
||||||
|
/* candidateDeviceCount= */ mDeviceItemsForSharing.size());
|
||||||
|
if (!mTargetActiveSinks.isEmpty()) {
|
||||||
|
Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks.");
|
||||||
AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager);
|
AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager);
|
||||||
|
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING);
|
||||||
mTargetActiveSinks.clear();
|
mTargetActiveSinks.clear();
|
||||||
|
}
|
||||||
if (mFragment == null) {
|
if (mFragment == null) {
|
||||||
Log.w(TAG, "Dialog fail to show due to null fragment.");
|
Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment.");
|
||||||
mGroupedConnectedDevices.clear();
|
mGroupedConnectedDevices.clear();
|
||||||
mDeviceItemsForSharing.clear();
|
mDeviceItemsForSharing.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
showDialog(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDialog(Pair<Integer, Object>[] eventData) {
|
||||||
|
AudioSharingDialogFragment.DialogEventListener listener =
|
||||||
|
new AudioSharingDialogFragment.DialogEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(@NonNull AudioSharingDeviceItem item) {
|
||||||
|
AudioSharingUtils.addSourceToTargetSinks(
|
||||||
|
mGroupedConnectedDevices
|
||||||
|
.getOrDefault(item.getGroupId(), ImmutableList.of())
|
||||||
|
.stream()
|
||||||
|
.map(CachedBluetoothDevice::getDevice)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList()),
|
||||||
|
mBtManager);
|
||||||
|
mGroupedConnectedDevices.clear();
|
||||||
|
mDeviceItemsForSharing.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {
|
||||||
|
mGroupedConnectedDevices.clear();
|
||||||
|
mDeviceItemsForSharing.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
AudioSharingUtils.postOnMainThread(
|
AudioSharingUtils.postOnMainThread(
|
||||||
mContext,
|
mContext,
|
||||||
() -> {
|
() -> {
|
||||||
// Check nullability to pass NullAway check
|
// Check nullability to pass NullAway check
|
||||||
if (mFragment != null) {
|
if (mFragment != null) {
|
||||||
AudioSharingDialogFragment.show(
|
AudioSharingDialogFragment.show(
|
||||||
mFragment,
|
mFragment, mDeviceItemsForSharing, listener, eventData);
|
||||||
mDeviceItemsForSharing,
|
|
||||||
item -> {
|
|
||||||
AudioSharingUtils.addSourceToTargetSinks(
|
|
||||||
mGroupedConnectedDevices
|
|
||||||
.getOrDefault(
|
|
||||||
item.getGroupId(), ImmutableList.of())
|
|
||||||
.stream()
|
|
||||||
.map(CachedBluetoothDevice::getDevice)
|
|
||||||
.collect(Collectors.toList()),
|
|
||||||
mBtManager);
|
|
||||||
mGroupedConnectedDevices.clear();
|
|
||||||
mDeviceItemsForSharing.clear();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,12 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing;
|
package com.android.settings.connecteddevice.audiosharing;
|
||||||
|
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT;
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING;
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID;
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID;
|
||||||
|
import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED;
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothCsipSetCoordinator;
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -25,6 +31,7 @@ import android.bluetooth.BluetoothStatusCodes;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -54,6 +61,14 @@ public class AudioSharingUtils {
|
|||||||
private static final String TAG = "AudioSharingUtils";
|
private static final String TAG = "AudioSharingUtils";
|
||||||
private static final boolean DEBUG = BluetoothUtils.D;
|
private static final boolean DEBUG = BluetoothUtils.D;
|
||||||
|
|
||||||
|
public enum MetricKey {
|
||||||
|
METRIC_KEY_SOURCE_PAGE_ID,
|
||||||
|
METRIC_KEY_PAGE_ID,
|
||||||
|
METRIC_KEY_USER_TRIGGERED,
|
||||||
|
METRIC_KEY_DEVICE_COUNT_IN_SHARING,
|
||||||
|
METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch {@link CachedBluetoothDevice}s connected to the broadcast assistant. The devices are
|
* Fetch {@link CachedBluetoothDevice}s connected to the broadcast assistant. The devices are
|
||||||
* grouped by CSIP group id.
|
* grouped by CSIP group id.
|
||||||
@@ -121,7 +136,7 @@ public class AudioSharingUtils {
|
|||||||
boolean filterByInSharing) {
|
boolean filterByInSharing) {
|
||||||
List<CachedBluetoothDevice> orderedDevices = new ArrayList<>();
|
List<CachedBluetoothDevice> orderedDevices = new ArrayList<>();
|
||||||
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
|
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
|
||||||
@Nullable CachedBluetoothDevice leadDevice = getLeadDevice(devices);
|
CachedBluetoothDevice leadDevice = getLeadDevice(devices);
|
||||||
if (leadDevice == null) {
|
if (leadDevice == null) {
|
||||||
Log.d(TAG, "Skip due to no lead device");
|
Log.d(TAG, "Skip due to no lead device");
|
||||||
continue;
|
continue;
|
||||||
@@ -206,7 +221,7 @@ public class AudioSharingUtils {
|
|||||||
return buildOrderedConnectedLeadDevices(
|
return buildOrderedConnectedLeadDevices(
|
||||||
localBtManager, groupedConnectedDevices, filterByInSharing)
|
localBtManager, groupedConnectedDevices, filterByInSharing)
|
||||||
.stream()
|
.stream()
|
||||||
.map(device -> buildAudioSharingDeviceItem(device))
|
.map(AudioSharingUtils::buildAudioSharingDeviceItem)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,9 +330,10 @@ public class AudioSharingUtils {
|
|||||||
manager.getProfileManager().getLeAudioBroadcastProfile();
|
manager.getProfileManager().getLeAudioBroadcastProfile();
|
||||||
if (broadcast == null) {
|
if (broadcast == null) {
|
||||||
Log.d(TAG, "Skip stop broadcasting due to broadcast profile is null");
|
Log.d(TAG, "Skip stop broadcasting due to broadcast profile is null");
|
||||||
}
|
} else {
|
||||||
broadcast.stopBroadcast(broadcast.getLatestBroadcastId());
|
broadcast.stopBroadcast(broadcast.getLatestBroadcastId());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get CSIP group id for {@link CachedBluetoothDevice}.
|
* Get CSIP group id for {@link CachedBluetoothDevice}.
|
||||||
@@ -378,9 +394,32 @@ public class AudioSharingUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
VolumeControlProfile vc = profileManager.getVolumeControlProfile();
|
VolumeControlProfile vc = profileManager.getVolumeControlProfile();
|
||||||
if (vc == null || !vc.isProfileReady()) {
|
return vc != null && vc.isProfileReady();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
/**
|
||||||
|
* Build audio sharing dialog log event data
|
||||||
|
*
|
||||||
|
* @param sourcePageId The source page id on which the dialog is shown. *
|
||||||
|
* @param pageId The page id of the dialog.
|
||||||
|
* @param userTriggered Indicates whether the dialog is triggered by user click.
|
||||||
|
* @param deviceCountInSharing The count of the devices joining the audio sharing.
|
||||||
|
* @param candidateDeviceCount The count of the eligible devices to join the audio sharing.
|
||||||
|
* @return The event data to be attached to the audio sharing action logs.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static Pair<Integer, Object>[] buildAudioSharingDialogEventData(
|
||||||
|
int sourcePageId,
|
||||||
|
int pageId,
|
||||||
|
boolean userTriggered,
|
||||||
|
int deviceCountInSharing,
|
||||||
|
int candidateDeviceCount) {
|
||||||
|
return new Pair[] {
|
||||||
|
Pair.create(METRIC_KEY_SOURCE_PAGE_ID.ordinal(), sourcePageId),
|
||||||
|
Pair.create(METRIC_KEY_PAGE_ID.ordinal(), pageId),
|
||||||
|
Pair.create(METRIC_KEY_USER_TRIGGERED.ordinal(), userTriggered ? 1 : 0),
|
||||||
|
Pair.create(METRIC_KEY_DEVICE_COUNT_IN_SHARING.ordinal(), deviceCountInSharing),
|
||||||
|
Pair.create(METRIC_KEY_CANDIDATE_DEVICE_COUNT.ordinal(), candidateDeviceCount)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,11 +18,17 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
|
import android.content.Context;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -34,6 +40,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settingslib.flags.Flags;
|
import com.android.settingslib.flags.Flags;
|
||||||
@@ -72,30 +79,50 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, /* groupId= */ 2, /* isActive= */ false);
|
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, /* groupId= */ 2, /* isActive= */ false);
|
||||||
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
||||||
new AudioSharingDeviceItem(TEST_DEVICE_NAME3, /* groupId= */ 3, /* isActive= */ false);
|
new AudioSharingDeviceItem(TEST_DEVICE_NAME3, /* groupId= */ 3, /* isActive= */ false);
|
||||||
|
private static final AudioSharingDialogFragment.DialogEventListener EMPTY_EVENT_LISTENER =
|
||||||
|
new AudioSharingDialogFragment.DialogEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AudioSharingDeviceItem item) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {}
|
||||||
|
};
|
||||||
|
private static final Pair<Integer, Object> TEST_EVENT_DATA = Pair.create(1, 1);
|
||||||
|
private static final Pair<Integer, Object>[] TEST_EVENT_DATA_LIST =
|
||||||
|
new Pair[] {TEST_EVENT_DATA};
|
||||||
|
|
||||||
private Fragment mParent;
|
private Fragment mParent;
|
||||||
private AudioSharingDialogFragment mFragment;
|
private AudioSharingDialogFragment mFragment;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
ShadowAlertDialogCompat.reset();
|
ShadowAlertDialogCompat.reset();
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
ShadowBluetoothAdapter shadowBluetoothAdapter =
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
shadowBluetoothAdapter.setEnabled(true);
|
||||||
|
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
mFragment = new AudioSharingDialogFragment();
|
mFragment = new AudioSharingDialogFragment();
|
||||||
mParent = new Fragment();
|
mParent = new Fragment();
|
||||||
FragmentController.setupFragment(
|
FragmentController.setupFragment(
|
||||||
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMetricsCategory_correctValue() {
|
||||||
|
assertThat(mFragment.getMetricsCategory())
|
||||||
|
.isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOff_dialogNotExist() {
|
public void onCreateDialog_flagOff_dialogNotExist() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
|
AudioSharingDialogFragment.show(
|
||||||
|
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
@@ -105,14 +132,20 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOn_noConnectedDevice() {
|
public void onCreateDialog_flagOn_noConnectedDevice() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
|
AudioSharingDialogFragment.show(
|
||||||
|
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
TextView description = dialog.findViewById(R.id.description_text);
|
TextView description = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(description).isNotNull();
|
||||||
ImageView image = dialog.findViewById(R.id.description_image);
|
ImageView image = dialog.findViewById(R.id.description_image);
|
||||||
|
assertThat(image).isNotNull();
|
||||||
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
||||||
|
assertThat(shareBtn).isNotNull();
|
||||||
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(cancelBtn).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
assertThat(description.getVisibility()).isEqualTo(View.VISIBLE);
|
assertThat(description.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
assertThat(description.getText().toString())
|
assertThat(description.getText().toString())
|
||||||
@@ -125,13 +158,22 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_noConnectedDevice_dialogDismiss() {
|
public void onCreateDialog_noConnectedDevice_dialogDismiss() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
|
AudioSharingDialogFragment.show(
|
||||||
|
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(android.R.id.button2).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(android.R.id.button2);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -139,15 +181,21 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
mFragment.show(mParent, list, (item) -> {});
|
AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
TextView title = dialog.findViewById(R.id.title_text);
|
TextView title = dialog.findViewById(R.id.title_text);
|
||||||
|
assertThat(title).isNotNull();
|
||||||
TextView description = dialog.findViewById(R.id.description_text);
|
TextView description = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(description).isNotNull();
|
||||||
ImageView image = dialog.findViewById(R.id.description_image);
|
ImageView image = dialog.findViewById(R.id.description_image);
|
||||||
|
assertThat(image).isNotNull();
|
||||||
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
||||||
|
assertThat(shareBtn).isNotNull();
|
||||||
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(cancelBtn).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
assertThat(title.getText().toString())
|
assertThat(title.getText().toString())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
@@ -166,12 +214,22 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
mFragment.show(mParent, list, (item) -> {});
|
AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.negative_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -180,13 +238,35 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
AtomicBoolean isShareBtnClicked = new AtomicBoolean(false);
|
AtomicBoolean isShareBtnClicked = new AtomicBoolean(false);
|
||||||
mFragment.show(mParent, list, (item) -> isShareBtnClicked.set(true));
|
AudioSharingDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
list,
|
||||||
|
new AudioSharingDialogFragment.DialogEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AudioSharingDeviceItem item) {
|
||||||
|
isShareBtnClicked.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {}
|
||||||
|
},
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.positive_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.positive_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isShareBtnClicked.get()).isTrue();
|
assertThat(isShareBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -196,15 +276,21 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
list.add(TEST_DEVICE_ITEM2);
|
list.add(TEST_DEVICE_ITEM2);
|
||||||
list.add(TEST_DEVICE_ITEM3);
|
list.add(TEST_DEVICE_ITEM3);
|
||||||
mFragment.show(mParent, list, (item) -> {});
|
AudioSharingDialogFragment.show(mParent, list, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
TextView description = dialog.findViewById(R.id.description_text);
|
TextView description = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(description).isNotNull();
|
||||||
ImageView image = dialog.findViewById(R.id.description_image);
|
ImageView image = dialog.findViewById(R.id.description_image);
|
||||||
|
assertThat(image).isNotNull();
|
||||||
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
Button shareBtn = dialog.findViewById(R.id.positive_btn);
|
||||||
|
assertThat(shareBtn).isNotNull();
|
||||||
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(cancelBtn).isNotNull();
|
||||||
RecyclerView recyclerView = dialog.findViewById(R.id.device_btn_list);
|
RecyclerView recyclerView = dialog.findViewById(R.id.device_btn_list);
|
||||||
|
assertThat(recyclerView).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
assertThat(description.getVisibility()).isEqualTo(View.VISIBLE);
|
assertThat(description.getVisibility()).isEqualTo(View.VISIBLE);
|
||||||
assertThat(description.getText().toString())
|
assertThat(description.getText().toString())
|
||||||
@@ -223,11 +309,35 @@ public class AudioSharingDialogFragmentTest {
|
|||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
list.add(TEST_DEVICE_ITEM2);
|
list.add(TEST_DEVICE_ITEM2);
|
||||||
list.add(TEST_DEVICE_ITEM3);
|
list.add(TEST_DEVICE_ITEM3);
|
||||||
mFragment.show(mParent, list, (item) -> {});
|
AtomicBoolean isCancelBtnClicked = new AtomicBoolean(false);
|
||||||
|
AudioSharingDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
list,
|
||||||
|
new AudioSharingDialogFragment.DialogEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AudioSharingDeviceItem item) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {
|
||||||
|
isCancelBtnClicked.set(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.negative_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
assertThat(isCancelBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
@@ -32,6 +33,7 @@ import android.bluetooth.BluetoothStatusCodes;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -39,6 +41,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
@@ -51,6 +54,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
|||||||
import com.android.settingslib.flags.Flags;
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.truth.Correspondence;
|
import com.google.common.truth.Correspondence;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -87,6 +91,7 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
Correspondence.from(
|
Correspondence.from(
|
||||||
(Fragment fragment, String tag) ->
|
(Fragment fragment, String tag) ->
|
||||||
fragment instanceof DialogFragment
|
fragment instanceof DialogFragment
|
||||||
|
&& ((DialogFragment) fragment).getTag() != null
|
||||||
&& ((DialogFragment) fragment).getTag().equals(tag),
|
&& ((DialogFragment) fragment).getTag().equals(tag),
|
||||||
"is equal to");
|
"is equal to");
|
||||||
|
|
||||||
@@ -107,20 +112,22 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
private Fragment mParentFragment;
|
private Fragment mParentFragment;
|
||||||
@Mock private BluetoothLeBroadcastReceiveState mState;
|
@Mock private BluetoothLeBroadcastReceiveState mState;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
|
||||||
private AudioSharingDialogHandler mHandler;
|
private AudioSharingDialogHandler mHandler;
|
||||||
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
mContext = ApplicationProvider.getApplicationContext();
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
|
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
|
||||||
mLocalBtManager = Utils.getLocalBtManager(mContext);
|
mLocalBtManager = Utils.getLocalBtManager(mContext);
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
ShadowBluetoothAdapter shadowBluetoothAdapter =
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
shadowBluetoothAdapter.setEnabled(true);
|
||||||
|
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
when(mLocalBtManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
|
when(mLocalBtManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
|
||||||
when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
||||||
@@ -183,9 +190,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ true);
|
mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ true);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingStopDialogFragment.tag());
|
.containsExactly(AudioSharingStopDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingStopDialogFragment fragment =
|
||||||
|
(AudioSharingStopDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_STOP_AUDIO_SHARING),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -211,9 +242,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingJoinDialogFragment fragment =
|
||||||
|
(AudioSharingJoinDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_START_AUDIO_SHARING),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -227,9 +282,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(mDevice3)).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(mDevice3)).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingJoinDialogFragment fragment =
|
||||||
|
(AudioSharingJoinDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -245,9 +324,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(mDevice4)).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(mDevice4)).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ true);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingDisconnectDialogFragment.tag());
|
.containsExactly(AudioSharingDisconnectDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingDisconnectDialogFragment fragment =
|
||||||
|
(AudioSharingDisconnectDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
2),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -273,9 +376,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ false);
|
mHandler.handleDeviceConnected(mCachedDevice2, /* userTriggered= */ false);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingStopDialogFragment.tag());
|
.containsExactly(AudioSharingStopDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingStopDialogFragment fragment =
|
||||||
|
(AudioSharingStopDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_STOP_AUDIO_SHARING),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -301,9 +428,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingJoinDialogFragment fragment =
|
||||||
|
(AudioSharingJoinDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_START_AUDIO_SHARING),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -317,9 +468,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(mDevice3)).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(mDevice3)).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
.containsExactly(AudioSharingJoinDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingJoinDialogFragment fragment =
|
||||||
|
(AudioSharingJoinDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -334,9 +509,33 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
when(mAssistant.getAllSources(mDevice4)).thenReturn(ImmutableList.of(mState));
|
when(mAssistant.getAllSources(mDevice4)).thenReturn(ImmutableList.of(mState));
|
||||||
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
mHandler.handleDeviceConnected(mCachedDevice1, /* userTriggered= */ false);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments())
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
.comparingElementsUsing(TAG_EQUALS)
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
.containsExactly(AudioSharingDisconnectDialogFragment.tag());
|
.containsExactly(AudioSharingDisconnectDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingDisconnectDialogFragment fragment =
|
||||||
|
(AudioSharingDisconnectDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
2),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -357,6 +556,11 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
mHandler.closeOpeningDialogsForLeaDevice(mCachedDevice1);
|
mHandler.closeOpeningDialogsForLeaDevice(mCachedDevice1);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments()).isEmpty();
|
assertThat(mParentFragment.getChildFragmentManager().getFragments()).isEmpty();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
mContext,
|
||||||
|
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS,
|
||||||
|
SettingsEnums.DIALOG_START_AUDIO_SHARING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -377,6 +581,11 @@ public class AudioSharingDialogHandlerTest {
|
|||||||
mHandler.closeOpeningDialogsForNonLeaDevice(mCachedDevice2);
|
mHandler.closeOpeningDialogsForNonLeaDevice(mCachedDevice2);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
assertThat(mParentFragment.getChildFragmentManager().getFragments()).isEmpty();
|
assertThat(mParentFragment.getChildFragmentManager().getFragments()).isEmpty();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
mContext,
|
||||||
|
SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS,
|
||||||
|
SettingsEnums.DIALOG_STOP_AUDIO_SHARING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpBroadcast(boolean isBroadcasting) {
|
private void setUpBroadcast(boolean isBroadcasting) {
|
||||||
|
@@ -18,13 +18,21 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
|
import android.content.Context;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -33,6 +41,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
@@ -78,15 +87,19 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, TEST_GROUP_ID2, /* isActive= */ false);
|
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, TEST_GROUP_ID2, /* isActive= */ false);
|
||||||
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
||||||
new AudioSharingDeviceItem(TEST_DEVICE_NAME3, TEST_GROUP_ID3, /* isActive= */ false);
|
new AudioSharingDeviceItem(TEST_DEVICE_NAME3, TEST_GROUP_ID3, /* isActive= */ false);
|
||||||
|
private static final AudioSharingDisconnectDialogFragment.DialogEventListener
|
||||||
|
EMPTY_EVENT_LISTENER = (AudioSharingDeviceItem item) -> {};
|
||||||
|
private static final Pair<Integer, Object> TEST_EVENT_DATA = Pair.create(1, 1);
|
||||||
|
private static final Pair<Integer, Object>[] TEST_EVENT_DATA_LIST =
|
||||||
|
new Pair[] {TEST_EVENT_DATA};
|
||||||
|
|
||||||
@Mock private BluetoothDevice mDevice1;
|
@Mock private BluetoothDevice mDevice1;
|
||||||
@Mock private BluetoothDevice mDevice3;
|
@Mock private BluetoothDevice mDevice3;
|
||||||
|
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice1;
|
@Mock private CachedBluetoothDevice mCachedDevice1;
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice3;
|
@Mock private CachedBluetoothDevice mCachedDevice3;
|
||||||
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
private Fragment mParent;
|
private Fragment mParent;
|
||||||
private AudioSharingDisconnectDialogFragment mFragment;
|
private AudioSharingDisconnectDialogFragment mFragment;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
|
||||||
private ArrayList<AudioSharingDeviceItem> mDeviceItems = new ArrayList<>();
|
private ArrayList<AudioSharingDeviceItem> mDeviceItems = new ArrayList<>();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -96,12 +109,14 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
latestAlertDialog.dismiss();
|
latestAlertDialog.dismiss();
|
||||||
ShadowAlertDialogCompat.reset();
|
ShadowAlertDialogCompat.reset();
|
||||||
}
|
}
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
ShadowBluetoothAdapter shadowBluetoothAdapter =
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
shadowBluetoothAdapter.setEnabled(true);
|
||||||
|
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
when(mDevice1.getAnonymizedAddress()).thenReturn(TEST_ADDRESS1);
|
when(mDevice1.getAnonymizedAddress()).thenReturn(TEST_ADDRESS1);
|
||||||
when(mDevice3.getAnonymizedAddress()).thenReturn(TEST_ADDRESS3);
|
when(mDevice3.getAnonymizedAddress()).thenReturn(TEST_ADDRESS3);
|
||||||
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
||||||
@@ -116,13 +131,20 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMetricsCategory_correctValue() {
|
||||||
|
assertThat(mFragment.getMetricsCategory())
|
||||||
|
.isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOff_dialogNotExist() {
|
public void onCreateDialog_flagOff_dialogNotExist() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mDeviceItems = new ArrayList<>();
|
mDeviceItems = new ArrayList<>();
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent, mDeviceItems, mCachedDevice3, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
@@ -135,12 +157,15 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
mDeviceItems = new ArrayList<>();
|
mDeviceItems = new ArrayList<>();
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent, mDeviceItems, mCachedDevice3, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +175,14 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
mDeviceItems = new ArrayList<>();
|
mDeviceItems = new ArrayList<>();
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent, mDeviceItems, mCachedDevice3, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AtomicBoolean isItemBtnClicked = new AtomicBoolean(false);
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
||||||
Button btn1 =
|
Button btn1 =
|
||||||
view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
||||||
@@ -173,37 +200,71 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
TEST_DEVICE_NAME2));
|
TEST_DEVICE_NAME2));
|
||||||
|
|
||||||
// Update dialog content for device with same group
|
// Update dialog content for device with same group
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> isItemBtnClicked.set(true));
|
AtomicBoolean isItemBtnClicked = new AtomicBoolean(false);
|
||||||
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
mDeviceItems,
|
||||||
|
mCachedDevice3,
|
||||||
|
(AudioSharingDeviceItem item) -> isItemBtnClicked.set(true),
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider, times(0))
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE));
|
||||||
|
|
||||||
btn1 = view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
btn1 = view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
||||||
btn1.performClick();
|
btn1.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isItemBtnClicked.get()).isTrue();
|
assertThat(isItemBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_dialogIsShowingForNewGroup_updateDialog() {
|
public void onCreateDialog_dialogIsShowingForNewGroup_showNewDialog() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mDeviceItems = new ArrayList<>();
|
mDeviceItems = new ArrayList<>();
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent, mDeviceItems, mCachedDevice3, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
RecyclerView view = dialog.findViewById(R.id.device_btn_list);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
||||||
|
|
||||||
// Show new dialog for device with new group
|
// Show new dialog for device with new group
|
||||||
ArrayList<AudioSharingDeviceItem> newDeviceItems = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> newDeviceItems = new ArrayList<>();
|
||||||
newDeviceItems.add(TEST_DEVICE_ITEM2);
|
newDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
newDeviceItems.add(TEST_DEVICE_ITEM3);
|
newDeviceItems.add(TEST_DEVICE_ITEM3);
|
||||||
mFragment.show(mParent, newDeviceItems, mCachedDevice1, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
newDeviceItems,
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE));
|
||||||
|
|
||||||
view = dialog.findViewById(R.id.device_btn_list);
|
view = dialog.findViewById(R.id.device_btn_list);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
|
||||||
Button btn1 =
|
Button btn1 =
|
||||||
view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
view.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.device_button);
|
||||||
@@ -227,12 +288,27 @@ public class AudioSharingDisconnectDialogFragmentTest {
|
|||||||
mDeviceItems = new ArrayList<>();
|
mDeviceItems = new ArrayList<>();
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
mDeviceItems.add(TEST_DEVICE_ITEM1);
|
||||||
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
mDeviceItems.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, mDeviceItems, mCachedDevice3, (item) -> {});
|
AudioSharingDisconnectDialogFragment.show(
|
||||||
|
mParent, mDeviceItems, mCachedDevice3, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
|
shadowMainLooper().idle();
|
||||||
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
assertThat(dialog).isNotNull();
|
||||||
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
|
View btnView = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
|
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
|
||||||
dialog.findViewById(R.id.negative_btn).performClick();
|
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider, times(0))
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE));
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,13 +18,19 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
|
import android.content.Context;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
@@ -32,6 +38,7 @@ import androidx.fragment.app.FragmentActivity;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||||
@@ -82,6 +89,9 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
@Override
|
@Override
|
||||||
public void onCancelClick() {}
|
public void onCancelClick() {}
|
||||||
};
|
};
|
||||||
|
private static final Pair<Integer, Object> TEST_EVENT_DATA = Pair.create(1, 1);
|
||||||
|
private static final Pair<Integer, Object>[] TEST_EVENT_DATA_LIST =
|
||||||
|
new Pair[] {TEST_EVENT_DATA};
|
||||||
|
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice1;
|
@Mock private CachedBluetoothDevice mCachedDevice1;
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice2;
|
@Mock private CachedBluetoothDevice mCachedDevice2;
|
||||||
@@ -90,7 +100,7 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
@Mock private LocalBluetoothLeBroadcast mBroadcast;
|
@Mock private LocalBluetoothLeBroadcast mBroadcast;
|
||||||
private Fragment mParent;
|
private Fragment mParent;
|
||||||
private AudioSharingJoinDialogFragment mFragment;
|
private AudioSharingJoinDialogFragment mFragment;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -99,12 +109,14 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
latestAlertDialog.dismiss();
|
latestAlertDialog.dismiss();
|
||||||
ShadowAlertDialogCompat.reset();
|
ShadowAlertDialogCompat.reset();
|
||||||
}
|
}
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
ShadowBluetoothAdapter shadowBluetoothAdapter =
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
shadowBluetoothAdapter.setEnabled(true);
|
||||||
|
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
||||||
when(mCachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME2);
|
when(mCachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME2);
|
||||||
mFragment = new AudioSharingJoinDialogFragment();
|
mFragment = new AudioSharingJoinDialogFragment();
|
||||||
@@ -137,7 +149,12 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOff_dialogNotExist() {
|
public void onCreateDialog_flagOff_dialogNotExist() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), mCachedDevice2, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
new ArrayList<>(),
|
||||||
|
mCachedDevice2,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNull();
|
assertThat(dialog).isNull();
|
||||||
@@ -146,7 +163,12 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() {
|
public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), mCachedDevice2, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
new ArrayList<>(),
|
||||||
|
mCachedDevice2,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
@@ -160,7 +182,8 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
mFragment.show(mParent, list, mCachedDevice2, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent, list, mCachedDevice2, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
@@ -179,7 +202,8 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
|
||||||
list.add(TEST_DEVICE_ITEM1);
|
list.add(TEST_DEVICE_ITEM1);
|
||||||
mFragment.show(mParent, list, mCachedDevice2, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent, list, mCachedDevice2, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
@@ -188,7 +212,8 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
// Update the content
|
// Update the content
|
||||||
ArrayList<AudioSharingDeviceItem> list2 = new ArrayList<>();
|
ArrayList<AudioSharingDeviceItem> list2 = new ArrayList<>();
|
||||||
list2.add(TEST_DEVICE_ITEM2);
|
list2.add(TEST_DEVICE_ITEM2);
|
||||||
mFragment.show(mParent, list2, mCachedDevice1, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent, list2, mCachedDevice1, EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
@@ -205,11 +230,25 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_clickCancel_dialogDismiss() {
|
public void onCreateDialog_clickCancel_dialogDismiss() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, new ArrayList<>(), mCachedDevice2, EMPTY_EVENT_LISTENER);
|
AudioSharingJoinDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
new ArrayList<>(),
|
||||||
|
mCachedDevice2,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.negative_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -228,12 +267,22 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCancelClick() {}
|
public void onCancelClick() {}
|
||||||
});
|
},
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.positive_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.positive_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isShareBtnClicked.get()).isTrue();
|
assertThat(isShareBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -252,11 +301,21 @@ public class AudioSharingJoinDialogFragmentTest {
|
|||||||
public void onCancelClick() {
|
public void onCancelClick() {
|
||||||
isCancelBtnClicked.set(true);
|
isCancelBtnClicked.set(true);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(R.id.negative_btn).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(R.id.negative_btn);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isCancelBtnClicked.get()).isTrue();
|
assertThat(isCancelBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,13 +18,21 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
|
import android.content.Context;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -32,6 +40,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
@@ -76,14 +85,19 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
|
||||||
new AudioSharingDeviceItem(
|
new AudioSharingDeviceItem(
|
||||||
TEST_DEVICE_NAME3, TEST_DEVICE_GROUP_ID3, /* isActive= */ false);
|
TEST_DEVICE_NAME3, TEST_DEVICE_GROUP_ID3, /* isActive= */ false);
|
||||||
|
private static final AudioSharingStopDialogFragment.DialogEventListener EMPTY_EVENT_LISTENER =
|
||||||
|
() -> {};
|
||||||
|
private static final Pair<Integer, Object> TEST_EVENT_DATA = Pair.create(1, 1);
|
||||||
|
private static final Pair<Integer, Object>[] TEST_EVENT_DATA_LIST =
|
||||||
|
new Pair[] {TEST_EVENT_DATA};
|
||||||
|
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice1;
|
@Mock private CachedBluetoothDevice mCachedDevice1;
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice2;
|
@Mock private CachedBluetoothDevice mCachedDevice2;
|
||||||
@Mock private BluetoothDevice mDevice1;
|
@Mock private BluetoothDevice mDevice1;
|
||||||
@Mock private BluetoothDevice mDevice2;
|
@Mock private BluetoothDevice mDevice2;
|
||||||
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
private Fragment mParent;
|
private Fragment mParent;
|
||||||
private AudioSharingStopDialogFragment mFragment;
|
private AudioSharingStopDialogFragment mFragment;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -92,12 +106,14 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
latestAlertDialog.dismiss();
|
latestAlertDialog.dismiss();
|
||||||
ShadowAlertDialogCompat.reset();
|
ShadowAlertDialogCompat.reset();
|
||||||
}
|
}
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
ShadowBluetoothAdapter shadowBluetoothAdapter =
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
shadowBluetoothAdapter.setEnabled(true);
|
||||||
|
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
|
||||||
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
BluetoothStatusCodes.FEATURE_SUPPORTED);
|
||||||
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
||||||
when(mCachedDevice1.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID1);
|
when(mCachedDevice1.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID1);
|
||||||
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
|
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
|
||||||
@@ -110,10 +126,21 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMetricsCategory_correctValue() {
|
||||||
|
assertThat(mFragment.getMetricsCategory())
|
||||||
|
.isEqualTo(SettingsEnums.DIALOG_STOP_AUDIO_SHARING);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_flagOff_dialogNotExist() {
|
public void onCreateDialog_flagOff_dialogNotExist() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, ImmutableList.of(), mCachedDevice1, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNull();
|
assertThat(dialog).isNull();
|
||||||
@@ -122,12 +149,18 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_oneDeviceInSharing_showDialogWithCorrectMessage() {
|
public void onCreateDialog_oneDeviceInSharing_showDialogWithCorrectMessage() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, ImmutableList.of(TEST_DEVICE_ITEM2), mCachedDevice1, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(TEST_DEVICE_ITEM2),
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
TextView view = dialog.findViewById(R.id.description_text);
|
TextView view = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getText().toString())
|
assertThat(view.getText().toString())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
mParent.getString(
|
mParent.getString(
|
||||||
@@ -137,16 +170,18 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_twoDeviceInSharing_showDialogWithCorrectMessage() {
|
public void onCreateDialog_twoDeviceInSharing_showDialogWithCorrectMessage() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(
|
AudioSharingStopDialogFragment.show(
|
||||||
mParent,
|
mParent,
|
||||||
ImmutableList.of(TEST_DEVICE_ITEM2, TEST_DEVICE_ITEM3),
|
ImmutableList.of(TEST_DEVICE_ITEM2, TEST_DEVICE_ITEM3),
|
||||||
mCachedDevice1,
|
mCachedDevice1,
|
||||||
() -> {});
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
TextView view = dialog.findViewById(R.id.description_text);
|
TextView view = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getText().toString())
|
assertThat(view.getText().toString())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
mParent.getString(
|
mParent.getString(
|
||||||
@@ -158,57 +193,99 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_dialogIsShowingForSameDevice_updateDialog() {
|
public void onCreateDialog_dialogIsShowingForSameDevice_updateDialog() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, ImmutableList.of(), mCachedDevice1, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
TextView view = dialog.findViewById(R.id.description_text);
|
TextView view = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getText().toString())
|
assertThat(view.getText().toString())
|
||||||
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
||||||
|
|
||||||
// Update the content
|
// Update the content
|
||||||
AtomicBoolean isStopBtnClicked = new AtomicBoolean(false);
|
AtomicBoolean isStopBtnClicked = new AtomicBoolean(false);
|
||||||
mFragment.show(
|
AudioSharingStopDialogFragment.show(
|
||||||
mParent, ImmutableList.of(), mCachedDevice1, () -> isStopBtnClicked.set(true));
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
() -> isStopBtnClicked.set(true),
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider, times(0))
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_STOP_AUDIO_SHARING));
|
||||||
|
|
||||||
dialog.findViewById(android.R.id.button1).performClick();
|
View btnView = dialog.findViewById(android.R.id.button1);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isStopBtnClicked.get()).isTrue();
|
assertThat(isStopBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_dialogIsShowingForNewDevice_showNewDialog() {
|
public void onCreateDialog_dialogIsShowingForNewDevice_showNewDialog() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, ImmutableList.of(), mCachedDevice1, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
TextView view = dialog.findViewById(R.id.description_text);
|
TextView view = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getText().toString())
|
assertThat(view.getText().toString())
|
||||||
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
||||||
TextView title = dialog.findViewById(R.id.title_text);
|
TextView title = dialog.findViewById(R.id.title_text);
|
||||||
|
assertThat(title).isNotNull();
|
||||||
assertThat(title.getText().toString())
|
assertThat(title.getText().toString())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
mParent.getString(
|
mParent.getString(
|
||||||
R.string.audio_sharing_stop_dialog_title, TEST_DEVICE_NAME1));
|
R.string.audio_sharing_stop_dialog_title, TEST_DEVICE_NAME1));
|
||||||
|
|
||||||
// Show new dialog
|
// Show new dialog
|
||||||
mFragment.show(mParent, ImmutableList.of(), mCachedDevice2, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice2,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
assertThat(dialog).isNotNull();
|
assertThat(dialog).isNotNull();
|
||||||
assertThat(dialog.isShowing()).isTrue();
|
assertThat(dialog.isShowing()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_STOP_AUDIO_SHARING));
|
||||||
|
|
||||||
view = dialog.findViewById(R.id.description_text);
|
view = dialog.findViewById(R.id.description_text);
|
||||||
|
assertThat(view).isNotNull();
|
||||||
assertThat(view.getText().toString())
|
assertThat(view.getText().toString())
|
||||||
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
.isEqualTo(mParent.getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
||||||
title = dialog.findViewById(R.id.title_text);
|
title = dialog.findViewById(R.id.title_text);
|
||||||
|
assertThat(title).isNotNull();
|
||||||
assertThat(title.getText().toString())
|
assertThat(title.getText().toString())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
mParent.getString(
|
mParent.getString(
|
||||||
@@ -218,25 +295,60 @@ public class AudioSharingStopDialogFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_clickCancel_dialogDismiss() {
|
public void onCreateDialog_clickCancel_dialogDismiss() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
mFragment.show(mParent, ImmutableList.of(), mCachedDevice1, () -> {});
|
AudioSharingStopDialogFragment.show(
|
||||||
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
EMPTY_EVENT_LISTENER,
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(android.R.id.button2).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(android.R.id.button2);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider, times(0))
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_STOP_AUDIO_SHARING));
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onCreateDialog_clickShare_callbackTriggered() {
|
public void onCreateDialog_clickShare_callbackTriggered() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
AtomicBoolean isStopBtnClicked = new AtomicBoolean(false);
|
AtomicBoolean isStopBtnClicked = new AtomicBoolean(false);
|
||||||
mFragment.show(
|
AudioSharingStopDialogFragment.show(
|
||||||
mParent, ImmutableList.of(), mCachedDevice1, () -> isStopBtnClicked.set(true));
|
mParent,
|
||||||
|
ImmutableList.of(),
|
||||||
|
mCachedDevice1,
|
||||||
|
() -> isStopBtnClicked.set(true),
|
||||||
|
TEST_EVENT_DATA_LIST);
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
dialog.findViewById(android.R.id.button1).performClick();
|
assertThat(dialog).isNotNull();
|
||||||
|
View btnView = dialog.findViewById(android.R.id.button1);
|
||||||
|
assertThat(btnView).isNotNull();
|
||||||
|
btnView.performClick();
|
||||||
shadowMainLooper().idle();
|
shadowMainLooper().idle();
|
||||||
assertThat(dialog.isShowing()).isFalse();
|
assertThat(dialog.isShowing()).isFalse();
|
||||||
assertThat(isStopBtnClicked.get()).isTrue();
|
assertThat(isStopBtnClicked.get()).isTrue();
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider, times(0))
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_AUTO_DISMISS),
|
||||||
|
eq(SettingsEnums.DIALOG_STOP_AUDIO_SHARING));
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
any(Context.class),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED),
|
||||||
|
eq(TEST_EVENT_DATA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -30,6 +31,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcast;
|
import android.bluetooth.BluetoothLeBroadcast;
|
||||||
@@ -43,12 +45,17 @@ import android.content.IntentFilter;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.util.FeatureFlagUtils;
|
import android.util.FeatureFlagUtils;
|
||||||
|
import android.util.Pair;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
|
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.bluetooth.Utils;
|
import com.android.settings.bluetooth.Utils;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||||
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||||
@@ -65,6 +72,8 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
|||||||
import com.android.settingslib.flags.Flags;
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.truth.Correspondence;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -77,7 +86,9 @@ import org.mockito.junit.MockitoRule;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadow.api.Shadow;
|
import org.robolectric.shadow.api.Shadow;
|
||||||
|
import org.robolectric.shadows.androidx.fragment.FragmentController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -88,6 +99,18 @@ import java.util.concurrent.Executor;
|
|||||||
ShadowThreadUtils.class,
|
ShadowThreadUtils.class,
|
||||||
})
|
})
|
||||||
public class AudioSharingSwitchBarControllerTest {
|
public class AudioSharingSwitchBarControllerTest {
|
||||||
|
private static final String TEST_DEVICE_NAME1 = "test1";
|
||||||
|
private static final String TEST_DEVICE_NAME2 = "test2";
|
||||||
|
private static final int TEST_DEVICE_GROUP_ID1 = 1;
|
||||||
|
private static final int TEST_DEVICE_GROUP_ID2 = 2;
|
||||||
|
private static final Correspondence<Fragment, String> TAG_EQUALS =
|
||||||
|
Correspondence.from(
|
||||||
|
(Fragment fragment, String tag) ->
|
||||||
|
fragment instanceof DialogFragment
|
||||||
|
&& ((DialogFragment) fragment).getTag() != null
|
||||||
|
&& ((DialogFragment) fragment).getTag().equals(tag),
|
||||||
|
"is equal to");
|
||||||
|
|
||||||
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
|
|
||||||
@@ -99,17 +122,19 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
@Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
|
@Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
@Mock private VolumeControlProfile mVolumeControl;
|
@Mock private VolumeControlProfile mVolumeControl;
|
||||||
@Mock private CompoundButton mBtnView;
|
@Mock private CompoundButton mBtnView;
|
||||||
@Mock private CachedBluetoothDevice mCachedDevice;
|
@Mock private CachedBluetoothDevice mCachedDevice1;
|
||||||
@Mock private BluetoothDevice mDevice;
|
@Mock private CachedBluetoothDevice mCachedDevice2;
|
||||||
|
@Mock private BluetoothDevice mDevice1;
|
||||||
|
@Mock private BluetoothDevice mDevice2;
|
||||||
private SettingsMainSwitchBar mSwitchBar;
|
private SettingsMainSwitchBar mSwitchBar;
|
||||||
private AudioSharingSwitchBarController mController;
|
private AudioSharingSwitchBarController mController;
|
||||||
private AudioSharingSwitchBarController.OnAudioSharingStateChangedListener mListener;
|
private FakeFeatureFactory mFeatureFactory;
|
||||||
private Lifecycle mLifecycle;
|
private Lifecycle mLifecycle;
|
||||||
private LifecycleOwner mLifecycleOwner;
|
private LifecycleOwner mLifecycleOwner;
|
||||||
private boolean mOnAudioSharingStateChanged;
|
private boolean mOnAudioSharingStateChanged;
|
||||||
private boolean mOnAudioSharingServiceConnected;
|
private boolean mOnAudioSharingServiceConnected;
|
||||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
||||||
private LocalBluetoothManager mLocalBluetoothManager;
|
private Fragment mParentFragment;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -122,13 +147,20 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
mLifecycleOwner = () -> mLifecycle;
|
mLifecycleOwner = () -> mLifecycle;
|
||||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
|
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
|
||||||
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
LocalBluetoothManager localBluetoothManager = Utils.getLocalBtManager(mContext);
|
||||||
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mBtProfileManager);
|
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
|
when(localBluetoothManager.getProfileManager()).thenReturn(mBtProfileManager);
|
||||||
when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedDevice);
|
when(localBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
|
||||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
when(mDeviceManager.findDevice(mDevice1)).thenReturn(mCachedDevice1);
|
||||||
when(mCachedDevice.getGroupId()).thenReturn(1);
|
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
|
||||||
when(mCachedDevice.getName()).thenReturn("test");
|
when(mCachedDevice1.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID1);
|
||||||
|
when(mCachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME1);
|
||||||
|
when(mCachedDevice1.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(false);
|
||||||
|
when(mDeviceManager.findDevice(mDevice2)).thenReturn(mCachedDevice2);
|
||||||
|
when(mCachedDevice2.getDevice()).thenReturn(mDevice2);
|
||||||
|
when(mCachedDevice2.getGroupId()).thenReturn(TEST_DEVICE_GROUP_ID2);
|
||||||
|
when(mCachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME2);
|
||||||
|
when(mCachedDevice2.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
|
||||||
when(mBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
when(mBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
||||||
when(mBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
|
when(mBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
|
||||||
when(mBtProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControl);
|
when(mBtProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControl);
|
||||||
@@ -153,7 +185,7 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
mSwitchBar.setDisabledByAdmin(mock(RestrictedLockUtils.EnforcedAdmin.class));
|
mSwitchBar.setDisabledByAdmin(mock(RestrictedLockUtils.EnforcedAdmin.class));
|
||||||
mOnAudioSharingStateChanged = false;
|
mOnAudioSharingStateChanged = false;
|
||||||
mOnAudioSharingServiceConnected = false;
|
mOnAudioSharingServiceConnected = false;
|
||||||
mListener =
|
AudioSharingSwitchBarController.OnAudioSharingStateChangedListener listener =
|
||||||
new AudioSharingSwitchBarController.OnAudioSharingStateChangedListener() {
|
new AudioSharingSwitchBarController.OnAudioSharingStateChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAudioSharingStateChanged() {
|
public void onAudioSharingStateChanged() {
|
||||||
@@ -165,7 +197,14 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
mOnAudioSharingServiceConnected = true;
|
mOnAudioSharingServiceConnected = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mController = new AudioSharingSwitchBarController(mContext, mSwitchBar, mListener);
|
mController = new AudioSharingSwitchBarController(mContext, mSwitchBar, listener);
|
||||||
|
mParentFragment = new Fragment();
|
||||||
|
FragmentController.setupFragment(
|
||||||
|
mParentFragment,
|
||||||
|
FragmentActivity.class,
|
||||||
|
0 /* containerViewId */,
|
||||||
|
null /* bundle */);
|
||||||
|
mController.init(mParentFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -356,7 +395,7 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
when(mBtnView.isEnabled()).thenReturn(true);
|
when(mBtnView.isEnabled()).thenReturn(true);
|
||||||
when(mAssistant.getDevicesMatchingConnectionStates(
|
when(mAssistant.getDevicesMatchingConnectionStates(
|
||||||
new int[] {BluetoothProfile.STATE_CONNECTED}))
|
new int[] {BluetoothProfile.STATE_CONNECTED}))
|
||||||
.thenReturn(ImmutableList.of(mDevice));
|
.thenReturn(ImmutableList.of(mDevice1));
|
||||||
doNothing().when(mBroadcast).startPrivateBroadcast();
|
doNothing().when(mBroadcast).startPrivateBroadcast();
|
||||||
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
|
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
|
||||||
verify(mBroadcast).startPrivateBroadcast();
|
verify(mBroadcast).startPrivateBroadcast();
|
||||||
@@ -380,4 +419,50 @@ public class AudioSharingSwitchBarControllerTest {
|
|||||||
mController.onCheckedChanged(mBtnView, /* isChecked= */ false);
|
mController.onCheckedChanged(mBtnView, /* isChecked= */ false);
|
||||||
verify(mBroadcast).stopBroadcast(1);
|
verify(mBroadcast).stopBroadcast(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onPlaybackStarted_showJoinAudioSharingDialog() {
|
||||||
|
FeatureFlagUtils.setEnabled(
|
||||||
|
mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
|
||||||
|
when(mBtnView.isEnabled()).thenReturn(true);
|
||||||
|
when(mAssistant.getDevicesMatchingConnectionStates(
|
||||||
|
new int[] {BluetoothProfile.STATE_CONNECTED}))
|
||||||
|
.thenReturn(ImmutableList.of(mDevice2, mDevice1));
|
||||||
|
doNothing().when(mBroadcast).startPrivateBroadcast();
|
||||||
|
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
|
||||||
|
verify(mBroadcast).startPrivateBroadcast();
|
||||||
|
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
|
||||||
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
|
||||||
|
|
||||||
|
List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
|
||||||
|
assertThat(childFragments)
|
||||||
|
.comparingElementsUsing(TAG_EQUALS)
|
||||||
|
.containsExactly(AudioSharingDialogFragment.tag());
|
||||||
|
|
||||||
|
AudioSharingDialogFragment fragment =
|
||||||
|
(AudioSharingDialogFragment) Iterables.getOnlyElement(childFragments);
|
||||||
|
Pair<Integer, Object>[] eventData = fragment.getEventData();
|
||||||
|
assertThat(eventData)
|
||||||
|
.asList()
|
||||||
|
.containsExactly(
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_SOURCE_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.AUDIO_SHARING_SETTINGS),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_PAGE_ID.ordinal(),
|
||||||
|
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_USER_TRIGGERED.ordinal(), 0),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_DEVICE_COUNT_IN_SHARING
|
||||||
|
.ordinal(),
|
||||||
|
1),
|
||||||
|
Pair.create(
|
||||||
|
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
|
||||||
|
.ordinal(),
|
||||||
|
1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user