Merge "[Audiosharing] Log action in audio sharing dialogs" into main
This commit is contained in:
@@ -20,9 +20,11 @@ import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -48,13 +50,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
* @param item The device item clicked.
|
||||
*/
|
||||
void onItemClick(AudioSharingDeviceItem item);
|
||||
|
||||
/** Called when users click the cancel button in the dialog. */
|
||||
void onCancelClick();
|
||||
}
|
||||
|
||||
@Nullable private static DialogEventListener sListener;
|
||||
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||
|
||||
@Override
|
||||
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 deviceItems The connected device items eligible for audio sharing.
|
||||
* @param listener The callback to handle the user action on this dialog.
|
||||
* @param eventData The eventData to log with for dialog onClick events.
|
||||
*/
|
||||
public static void show(
|
||||
@NonNull Fragment host,
|
||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||
@NonNull DialogEventListener listener) {
|
||||
@NonNull DialogEventListener listener,
|
||||
@NonNull Pair<Integer, Object>[] eventData) {
|
||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||
final FragmentManager manager = host.getChildFragmentManager();
|
||||
sListener = listener;
|
||||
sEventData = eventData;
|
||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||
if (dialog != null) {
|
||||
Log.d(TAG, "Dialog is showing, return.");
|
||||
@@ -84,7 +93,19 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
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
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle arguments = requireArguments();
|
||||
List<AudioSharingDeviceItem> deviceItems =
|
||||
@@ -93,12 +114,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||
.setIsCustomBodyEnabled(true);
|
||||
if (deviceItems == null) {
|
||||
Log.d(TAG, "Create dialog error: null deviceItems");
|
||||
return builder.build();
|
||||
}
|
||||
if (deviceItems.isEmpty()) {
|
||||
builder.setTitle(R.string.audio_sharing_share_dialog_title)
|
||||
.setCustomImage(R.drawable.audio_sharing_guidance)
|
||||
.setCustomMessage(R.string.audio_sharing_dialog_connect_device_content)
|
||||
.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) {
|
||||
AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems);
|
||||
builder.setTitle(
|
||||
@@ -111,11 +137,16 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
v -> {
|
||||
if (sListener != null) {
|
||||
sListener.onItemClick(deviceItem);
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
}
|
||||
dismiss();
|
||||
})
|
||||
.setCustomNegativeButton(
|
||||
R.string.audio_sharing_no_thanks_button_label, v -> dismiss());
|
||||
R.string.audio_sharing_no_thanks_button_label, v -> onCancelClick());
|
||||
} else {
|
||||
builder.setTitle(R.string.audio_sharing_share_with_more_dialog_title)
|
||||
.setCustomMessage(R.string.audio_sharing_dialog_share_more_content)
|
||||
@@ -130,8 +161,20 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
|
||||
dismiss();
|
||||
},
|
||||
AudioSharingDeviceAdapter.ActionType.SHARE))
|
||||
.setCustomNegativeButton(com.android.settings.R.string.cancel, v -> dismiss());
|
||||
.setCustomNegativeButton(
|
||||
com.android.settings.R.string.cancel, v -> onCancelClick());
|
||||
}
|
||||
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.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -33,15 +34,21 @@ import androidx.fragment.app.Fragment;
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class AudioSharingDialogHandler {
|
||||
@@ -51,6 +58,7 @@ public class AudioSharingDialogHandler {
|
||||
@Nullable private final LocalBluetoothManager mLocalBtManager;
|
||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private List<BluetoothDevice> mTargetSinks = new ArrayList<>();
|
||||
|
||||
private final BluetoothLeBroadcast.Callback mBroadcastCallback =
|
||||
@@ -119,9 +127,7 @@ public class AudioSharingDialogHandler {
|
||||
new SubSettingLauncher(mContext)
|
||||
.setDestination(AudioSharingDashboardFragment.class.getName())
|
||||
.setSourceMetricsCategory(
|
||||
(mHostFragment != null
|
||||
&& mHostFragment
|
||||
instanceof DashboardFragment)
|
||||
(mHostFragment instanceof DashboardFragment)
|
||||
? ((DashboardFragment) mHostFragment)
|
||||
.getMetricsCategory()
|
||||
: SettingsEnums.PAGE_UNKNOWN)
|
||||
@@ -146,6 +152,7 @@ public class AudioSharingDialogHandler {
|
||||
mLocalBtManager != null
|
||||
? mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile()
|
||||
: null;
|
||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||
}
|
||||
|
||||
/** Register callbacks for dialog handler */
|
||||
@@ -191,6 +198,18 @@ public class AudioSharingDialogHandler {
|
||||
List<AudioSharingDeviceItem> deviceItemsInSharingSession =
|
||||
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
|
||||
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(
|
||||
() -> {
|
||||
closeOpeningDialogsOtherThan(AudioSharingStopDialogFragment.tag());
|
||||
@@ -198,10 +217,8 @@ public class AudioSharingDialogHandler {
|
||||
mHostFragment,
|
||||
deviceItemsInSharingSession,
|
||||
cachedDevice,
|
||||
() -> {
|
||||
cachedDevice.setActive();
|
||||
AudioSharingUtils.stopBroadcasting(mLocalBtManager);
|
||||
});
|
||||
listener,
|
||||
eventData);
|
||||
});
|
||||
} else {
|
||||
if (userTriggered) {
|
||||
@@ -252,6 +269,20 @@ public class AudioSharingDialogHandler {
|
||||
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
|
||||
// connected during a sharing session.
|
||||
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(
|
||||
() -> {
|
||||
closeOpeningDialogsOtherThan(
|
||||
@@ -260,16 +291,29 @@ public class AudioSharingDialogHandler {
|
||||
mHostFragment,
|
||||
deviceItemsInSharingSession,
|
||||
cachedDevice,
|
||||
(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);
|
||||
});
|
||||
listener,
|
||||
eventData);
|
||||
});
|
||||
} else {
|
||||
// Show audio sharing join dialog when the first or second eligible (LE audio)
|
||||
// remote device connected during a sharing session.
|
||||
AudioSharingJoinDialogFragment.DialogEventListener listener =
|
||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||
@Override
|
||||
public void onShareClick() {
|
||||
addSourceForGroup(groupId, groupedDevices);
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
@@ -277,15 +321,8 @@ public class AudioSharingDialogHandler {
|
||||
mHostFragment,
|
||||
deviceItemsInSharingSession,
|
||||
cachedDevice,
|
||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||
@Override
|
||||
public void onShareClick() {
|
||||
addSourceForGroup(groupId, groupedDevices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClick() {}
|
||||
});
|
||||
listener,
|
||||
eventData);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -302,39 +339,43 @@ public class AudioSharingDialogHandler {
|
||||
// Show audio sharing join dialog when the second eligible (LE audio) remote
|
||||
// device connect and no sharing session.
|
||||
if (deviceItems.size() == 1) {
|
||||
AudioSharingJoinDialogFragment.DialogEventListener listener =
|
||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||
@Override
|
||||
public void onShareClick() {
|
||||
mTargetSinks = new ArrayList<>();
|
||||
for (List<CachedBluetoothDevice> devices :
|
||||
groupedDevices.values()) {
|
||||
for (CachedBluetoothDevice device : devices) {
|
||||
mTargetSinks.add(device.getDevice());
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Start broadcast with sinks = " + mTargetSinks.size());
|
||||
if (mBroadcast != null) {
|
||||
mBroadcast.startPrivateBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClick() {
|
||||
if (userTriggered) {
|
||||
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,
|
||||
new AudioSharingJoinDialogFragment.DialogEventListener() {
|
||||
@Override
|
||||
public void onShareClick() {
|
||||
mTargetSinks = new ArrayList<>();
|
||||
for (List<CachedBluetoothDevice> devices :
|
||||
groupedDevices.values()) {
|
||||
for (CachedBluetoothDevice device : devices) {
|
||||
mTargetSinks.add(device.getDevice());
|
||||
}
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"Start broadcast with sinks: "
|
||||
+ mTargetSinks.size());
|
||||
if (mBroadcast != null) {
|
||||
mBroadcast.startPrivateBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClick() {
|
||||
if (userTriggered) {
|
||||
cachedDevice.setActive();
|
||||
}
|
||||
}
|
||||
});
|
||||
mHostFragment, deviceItems, cachedDevice, listener, eventData);
|
||||
});
|
||||
} else if (userTriggered) {
|
||||
cachedDevice.setActive();
|
||||
@@ -346,9 +387,12 @@ public class AudioSharingDialogHandler {
|
||||
if (mHostFragment == null) return;
|
||||
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
|
||||
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());
|
||||
((DialogFragment) fragment).dismiss();
|
||||
logDialogDismissEvent(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,6 +409,7 @@ public class AudioSharingDialogHandler {
|
||||
&& AudioSharingUtils.getGroupId(device) == groupId) {
|
||||
Log.d(TAG, "Remove staled opening dialog for group " + groupId);
|
||||
((DialogFragment) fragment).dismiss();
|
||||
logDialogDismissEvent(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,6 +427,7 @@ public class AudioSharingDialogHandler {
|
||||
"Remove staled opening dialog for device "
|
||||
+ cachedDevice.getDevice().getAnonymizedAddress());
|
||||
((DialogFragment) fragment).dismiss();
|
||||
logDialogDismissEvent(fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,9 +455,9 @@ public class AudioSharingDialogHandler {
|
||||
Log.d(TAG, "Fail to remove source for group " + groupId);
|
||||
return;
|
||||
}
|
||||
groupedDevices.get(groupId).stream()
|
||||
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
|
||||
.map(CachedBluetoothDevice::getDevice)
|
||||
.filter(device -> device != null)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(
|
||||
device -> {
|
||||
for (BluetoothLeBroadcastReceiveState source :
|
||||
@@ -431,9 +477,9 @@ public class AudioSharingDialogHandler {
|
||||
Log.d(TAG, "Fail to add source due to invalid group id, group = " + groupId);
|
||||
return;
|
||||
}
|
||||
groupedDevices.get(groupId).stream()
|
||||
groupedDevices.getOrDefault(groupId, ImmutableList.of()).stream()
|
||||
.map(CachedBluetoothDevice::getDevice)
|
||||
.filter(device -> device != null)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(
|
||||
device ->
|
||||
mAssistant.addSource(
|
||||
@@ -449,4 +495,29 @@ public class AudioSharingDialogHandler {
|
||||
private boolean isBroadcasting() {
|
||||
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.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -55,6 +59,7 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
||||
|
||||
@Nullable private static DialogEventListener sListener;
|
||||
@Nullable private static CachedBluetoothDevice sNewDevice;
|
||||
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -70,12 +75,14 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
||||
* @param deviceItems The existing connected device items in audio sharing session.
|
||||
* @param newDevice The latest connected device triggered 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(
|
||||
@NonNull Fragment host,
|
||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||
@NonNull CachedBluetoothDevice newDevice,
|
||||
@NonNull DialogEventListener listener) {
|
||||
@NonNull DialogEventListener listener,
|
||||
@NonNull Pair<Integer, Object>[] eventData) {
|
||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||
FragmentManager manager = host.getChildFragmentManager();
|
||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||
@@ -91,6 +98,7 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
||||
newGroupId));
|
||||
sListener = listener;
|
||||
sNewDevice = newDevice;
|
||||
sEventData = eventData;
|
||||
return;
|
||||
} else {
|
||||
Log.d(
|
||||
@@ -101,10 +109,22 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
||||
+ "dismiss current dialog.",
|
||||
newGroupId));
|
||||
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;
|
||||
sNewDevice = newDevice;
|
||||
sEventData = eventData;
|
||||
Log.d(TAG, "Show up the dialog.");
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
||||
@@ -125,28 +145,54 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
|
||||
return sNewDevice;
|
||||
}
|
||||
|
||||
/** Test only: get the event data passed to the dialog. */
|
||||
@VisibleForTesting
|
||||
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||
return sEventData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle arguments = requireArguments();
|
||||
List<AudioSharingDeviceItem> deviceItems =
|
||||
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
||||
return AudioSharingDialogFactory.newBuilder(getActivity())
|
||||
.setTitle(R.string.audio_sharing_disconnect_dialog_title)
|
||||
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||
.setIsCustomBodyEnabled(true)
|
||||
.setCustomMessage(R.string.audio_sharing_dialog_disconnect_content)
|
||||
.setCustomDeviceActions(
|
||||
new AudioSharingDeviceAdapter(
|
||||
getContext(),
|
||||
deviceItems,
|
||||
(AudioSharingDeviceItem item) -> {
|
||||
if (sListener != null) {
|
||||
sListener.onItemClick(item);
|
||||
}
|
||||
AudioSharingDialogFactory.DialogBuilder builder =
|
||||
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||
.setTitle(R.string.audio_sharing_disconnect_dialog_title)
|
||||
.setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
|
||||
.setIsCustomBodyEnabled(true)
|
||||
.setCustomMessage(R.string.audio_sharing_dialog_disconnect_content)
|
||||
.setCustomNegativeButton(
|
||||
com.android.settings.R.string.cancel,
|
||||
v -> {
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
dismiss();
|
||||
},
|
||||
AudioSharingDeviceAdapter.ActionType.REMOVE))
|
||||
.setCustomNegativeButton(com.android.settings.R.string.cancel, v -> dismiss())
|
||||
.build();
|
||||
});
|
||||
if (deviceItems == null) {
|
||||
Log.d(TAG, "Create dialog error: null deviceItems");
|
||||
return builder.build();
|
||||
}
|
||||
builder.setCustomDeviceActions(
|
||||
new AudioSharingDeviceAdapter(
|
||||
getContext(),
|
||||
deviceItems,
|
||||
(AudioSharingDeviceItem item) -> {
|
||||
if (sListener != null) {
|
||||
sListener.onItemClick(item);
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
}
|
||||
dismiss();
|
||||
},
|
||||
AudioSharingDeviceAdapter.ActionType.REMOVE));
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@ import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -52,6 +54,7 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
||||
|
||||
@Nullable private static DialogEventListener sListener;
|
||||
@Nullable private static CachedBluetoothDevice sNewDevice;
|
||||
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -69,16 +72,19 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
||||
* @param deviceItems The existing connected device items eligible for audio sharing.
|
||||
* @param newDevice The latest connected device triggered 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(
|
||||
@NonNull Fragment host,
|
||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||
@NonNull CachedBluetoothDevice newDevice,
|
||||
@NonNull DialogEventListener listener) {
|
||||
@NonNull DialogEventListener listener,
|
||||
@NonNull Pair<Integer, Object>[] eventData) {
|
||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||
final FragmentManager manager = host.getChildFragmentManager();
|
||||
sListener = listener;
|
||||
sNewDevice = newDevice;
|
||||
sEventData = eventData;
|
||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||
if (dialog != null) {
|
||||
Log.d(TAG, "Dialog is showing, update the content.");
|
||||
@@ -104,7 +110,14 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
||||
return sNewDevice;
|
||||
}
|
||||
|
||||
/** Test only: get the event data passed to the dialog. */
|
||||
@VisibleForTesting
|
||||
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||
return sEventData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle arguments = requireArguments();
|
||||
List<AudioSharingDeviceItem> deviceItems =
|
||||
@@ -121,6 +134,11 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
||||
v -> {
|
||||
if (sListener != null) {
|
||||
sListener.onShareClick();
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
}
|
||||
dismiss();
|
||||
})
|
||||
@@ -129,11 +147,20 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
|
||||
v -> {
|
||||
if (sListener != null) {
|
||||
sListener.onCancelClick();
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
}
|
||||
dismiss();
|
||||
})
|
||||
.build();
|
||||
updateDialog(deviceItems, newDeviceName, dialog);
|
||||
if (deviceItems == null) {
|
||||
Log.d(TAG, "Fail to create dialog: null deviceItems");
|
||||
} else {
|
||||
updateDialog(deviceItems, newDeviceName, dialog);
|
||||
}
|
||||
dialog.show();
|
||||
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
||||
return dialog;
|
||||
|
||||
@@ -20,16 +20,20 @@ import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@@ -52,6 +56,7 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
|
||||
@Nullable private static DialogEventListener sListener;
|
||||
@Nullable private static CachedBluetoothDevice sCachedDevice;
|
||||
private static Pair<Integer, Object>[] sEventData = new Pair[0];
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -67,12 +72,14 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
* @param deviceItems The existing connected device items in audio sharing session.
|
||||
* @param newDevice The latest connected device triggered 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(
|
||||
@NonNull Fragment host,
|
||||
@NonNull List<AudioSharingDeviceItem> deviceItems,
|
||||
@NonNull CachedBluetoothDevice newDevice,
|
||||
@NonNull DialogEventListener listener) {
|
||||
@NonNull DialogEventListener listener,
|
||||
@NonNull Pair<Integer, Object>[] eventData) {
|
||||
if (!AudioSharingUtils.isFeatureEnabled()) return;
|
||||
final FragmentManager manager = host.getChildFragmentManager();
|
||||
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
|
||||
@@ -88,6 +95,7 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
newGroupId));
|
||||
sListener = listener;
|
||||
sCachedDevice = newDevice;
|
||||
sEventData = eventData;
|
||||
return;
|
||||
} else {
|
||||
Log.d(
|
||||
@@ -98,10 +106,21 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
+ "dismiss current dialog.",
|
||||
newGroupId));
|
||||
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;
|
||||
sCachedDevice = newDevice;
|
||||
sEventData = eventData;
|
||||
Log.d(TAG, "Show up the dialog.");
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putParcelableList(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, deviceItems);
|
||||
@@ -121,23 +140,34 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
return sCachedDevice;
|
||||
}
|
||||
|
||||
/** Test only: get the event data passed to the dialog. */
|
||||
@VisibleForTesting
|
||||
protected @NonNull Pair<Integer, Object>[] getEventData() {
|
||||
return sEventData;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Bundle arguments = requireArguments();
|
||||
List<AudioSharingDeviceItem> deviceItems =
|
||||
arguments.getParcelable(BUNDLE_KEY_DEVICE_TO_DISCONNECT_ITEMS, List.class);
|
||||
String newDeviceName = arguments.getString(BUNDLE_KEY_NEW_DEVICE_NAME);
|
||||
String customMessage =
|
||||
deviceItems.size() == 1
|
||||
? getString(
|
||||
R.string.audio_sharing_stop_dialog_content,
|
||||
Iterables.getOnlyElement(deviceItems).getName())
|
||||
: (deviceItems.size() == 2
|
||||
? getString(
|
||||
R.string.audio_sharing_stop_dialog_with_two_content,
|
||||
deviceItems.get(0).getName(),
|
||||
deviceItems.get(1).getName())
|
||||
: getString(R.string.audio_sharing_stop_dialog_with_more_content));
|
||||
String customMessage = "";
|
||||
if (deviceItems != null) {
|
||||
customMessage =
|
||||
deviceItems.size() == 1
|
||||
? getString(
|
||||
R.string.audio_sharing_stop_dialog_content,
|
||||
Iterables.getOnlyElement(deviceItems).getName())
|
||||
: (deviceItems.size() == 2
|
||||
? getString(
|
||||
R.string.audio_sharing_stop_dialog_with_two_content,
|
||||
deviceItems.get(0).getName(),
|
||||
deviceItems.get(1).getName())
|
||||
: getString(
|
||||
R.string.audio_sharing_stop_dialog_with_more_content));
|
||||
}
|
||||
AlertDialog dialog =
|
||||
AudioSharingDialogFactory.newBuilder(getActivity())
|
||||
.setTitle(
|
||||
@@ -150,10 +180,21 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
|
||||
(dlg, which) -> {
|
||||
if (sListener != null) {
|
||||
sListener.onStopSharingClick();
|
||||
mMetricsFeatureProvider.action(
|
||||
getContext(),
|
||||
SettingsEnums
|
||||
.ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED,
|
||||
sEventData);
|
||||
}
|
||||
})
|
||||
.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();
|
||||
dialog.show();
|
||||
AudioSharingDialogHelper.updateMessageStyle(dialog);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.connecteddevice.audiosharing;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothLeBroadcast;
|
||||
@@ -29,24 +30,27 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
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.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -56,6 +60,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -91,14 +96,15 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||
@Nullable private DashboardFragment mFragment;
|
||||
@Nullable private Fragment mFragment;
|
||||
private final Executor mExecutor;
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private final OnAudioSharingStateChangedListener mListener;
|
||||
private Map<Integer, List<CachedBluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
|
||||
private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>();
|
||||
private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>();
|
||||
@VisibleForTesting IntentFilter mIntentFilter;
|
||||
private AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
|
||||
private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
|
||||
|
||||
@VisibleForTesting
|
||||
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() {
|
||||
@Override
|
||||
public void onBroadcastStarted(int reason, int broadcastId) {
|
||||
@@ -182,7 +189,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
public void onPlaybackStopped(int reason, int broadcastId) {}
|
||||
};
|
||||
|
||||
private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
||||
private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
|
||||
new BluetoothLeBroadcastAssistant.Callback() {
|
||||
@Override
|
||||
public void onSearchStarted(int reason) {}
|
||||
@@ -251,9 +258,9 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
|
||||
@Override
|
||||
public void onReceiveStateChanged(
|
||||
BluetoothDevice sink,
|
||||
@NonNull BluetoothDevice sink,
|
||||
int sourceId,
|
||||
BluetoothLeBroadcastReceiveState state) {}
|
||||
@NonNull BluetoothLeBroadcastReceiveState state) {}
|
||||
};
|
||||
|
||||
AudioSharingSwitchBarController(
|
||||
@@ -273,6 +280,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
? null
|
||||
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -378,7 +386,7 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
*
|
||||
* @param fragment The fragment to host the {@link AudioSharingSwitchBarController} dialog.
|
||||
*/
|
||||
public void init(DashboardFragment fragment) {
|
||||
public void init(@NonNull Fragment fragment) {
|
||||
this.mFragment = fragment;
|
||||
}
|
||||
|
||||
@@ -494,34 +502,58 @@ public class AudioSharingSwitchBarController extends BasePreferenceController
|
||||
}
|
||||
|
||||
private void handleOnBroadcastReady() {
|
||||
AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager);
|
||||
mTargetActiveSinks.clear();
|
||||
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);
|
||||
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING);
|
||||
mTargetActiveSinks.clear();
|
||||
}
|
||||
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();
|
||||
mDeviceItemsForSharing.clear();
|
||||
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(
|
||||
mContext,
|
||||
() -> {
|
||||
// Check nullability to pass NullAway check
|
||||
if (mFragment != null) {
|
||||
AudioSharingDialogFragment.show(
|
||||
mFragment,
|
||||
mDeviceItemsForSharing,
|
||||
item -> {
|
||||
AudioSharingUtils.addSourceToTargetSinks(
|
||||
mGroupedConnectedDevices
|
||||
.getOrDefault(
|
||||
item.getGroupId(), ImmutableList.of())
|
||||
.stream()
|
||||
.map(CachedBluetoothDevice::getDevice)
|
||||
.collect(Collectors.toList()),
|
||||
mBtManager);
|
||||
mGroupedConnectedDevices.clear();
|
||||
mDeviceItemsForSharing.clear();
|
||||
});
|
||||
mFragment, mDeviceItemsForSharing, listener, eventData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
|
||||
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.BluetoothCsipSetCoordinator;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@@ -25,6 +31,7 @@ import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -54,6 +61,14 @@ public class AudioSharingUtils {
|
||||
private static final String TAG = "AudioSharingUtils";
|
||||
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
|
||||
* grouped by CSIP group id.
|
||||
@@ -121,7 +136,7 @@ public class AudioSharingUtils {
|
||||
boolean filterByInSharing) {
|
||||
List<CachedBluetoothDevice> orderedDevices = new ArrayList<>();
|
||||
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
|
||||
@Nullable CachedBluetoothDevice leadDevice = getLeadDevice(devices);
|
||||
CachedBluetoothDevice leadDevice = getLeadDevice(devices);
|
||||
if (leadDevice == null) {
|
||||
Log.d(TAG, "Skip due to no lead device");
|
||||
continue;
|
||||
@@ -206,7 +221,7 @@ public class AudioSharingUtils {
|
||||
return buildOrderedConnectedLeadDevices(
|
||||
localBtManager, groupedConnectedDevices, filterByInSharing)
|
||||
.stream()
|
||||
.map(device -> buildAudioSharingDeviceItem(device))
|
||||
.map(AudioSharingUtils::buildAudioSharingDeviceItem)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -315,8 +330,9 @@ public class AudioSharingUtils {
|
||||
manager.getProfileManager().getLeAudioBroadcastProfile();
|
||||
if (broadcast == null) {
|
||||
Log.d(TAG, "Skip stop broadcasting due to broadcast profile is null");
|
||||
} else {
|
||||
broadcast.stopBroadcast(broadcast.getLatestBroadcastId());
|
||||
}
|
||||
broadcast.stopBroadcast(broadcast.getLatestBroadcastId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,9 +394,32 @@ public class AudioSharingUtils {
|
||||
return false;
|
||||
}
|
||||
VolumeControlProfile vc = profileManager.getVolumeControlProfile();
|
||||
if (vc == null || !vc.isProfileReady()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return vc != null && vc.isProfileReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user