Merge "[Audiosharing] Fix IllegalStateException at getChildFragmentManager" into main

This commit is contained in:
Yiyi Shen
2024-06-27 10:53:15 +00:00
committed by Android (Google) Code Review
15 changed files with 204 additions and 31 deletions

View File

@@ -19,6 +19,7 @@ package com.android.settings.connecteddevice.audiosharing;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -66,7 +67,13 @@ public class AudioSharingCallAudioDialogFragment extends InstrumentedDialogFragm
@NonNull List<AudioSharingDeviceItem> deviceItems,
@NonNull DialogEventListener listener) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
final FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
sListener = listener;
if (manager.findFragmentByTag(TAG) == null) {
final Bundle bundle = new Bundle();
@@ -79,10 +86,18 @@ public class AudioSharingCallAudioDialogFragment extends InstrumentedDialogFragm
}
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle arguments = requireArguments();
List<AudioSharingDeviceItem> deviceItems =
arguments.getParcelable(BUNDLE_KEY_DEVICE_ITEMS, List.class);
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity())
.setTitle(R.string.audio_sharing_call_audio_title);
if (deviceItems == null) {
Log.d(TAG, "Create dialog error: null deviceItems");
return builder.create();
}
int checkedItem = -1;
for (AudioSharingDeviceItem item : deviceItems) {
int fallbackActiveGroupId = AudioSharingUtils.getFallbackActiveGroupId(getContext());
@@ -92,17 +107,14 @@ public class AudioSharingCallAudioDialogFragment extends InstrumentedDialogFragm
}
String[] choices =
deviceItems.stream().map(AudioSharingDeviceItem::getName).toArray(String[]::new);
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity())
.setTitle(R.string.audio_sharing_call_audio_title)
.setSingleChoiceItems(
choices,
checkedItem,
(dialog, which) -> {
if (sListener != null) {
sListener.onItemClick(deviceItems.get(which));
}
});
builder.setSingleChoiceItems(
choices,
checkedItem,
(dialog, which) -> {
if (sListener != null) {
sListener.onItemClick(deviceItems.get(which));
}
});
return builder.create();
}
}

View File

@@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
@@ -44,7 +45,13 @@ public class AudioSharingConfirmDialogFragment extends InstrumentedDialogFragmen
*/
public static void show(Fragment host) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
Log.d(TAG, "Dialog is showing, return.");
@@ -56,6 +63,7 @@ public class AudioSharingConfirmDialogFragment extends InstrumentedDialogFragmen
}
@Override
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog dialog =
AudioSharingDialogFactory.newBuilder(getActivity())

View File

@@ -77,7 +77,13 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
final FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
sListener = listener;
sEventData = eventData;
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);

View File

@@ -414,7 +414,13 @@ public class AudioSharingDialogHandler {
private void closeOpeningDialogsOtherThan(String tag) {
if (mHostFragment == null) return;
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
List<Fragment> fragments;
try {
fragments = mHostFragment.getChildFragmentManager().getFragments();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to closeOpeningDialogsOtherThan " + tag + ": " + e.getMessage());
return;
}
for (Fragment fragment : fragments) {
if (fragment instanceof DialogFragment
&& fragment.getTag() != null
@@ -430,7 +436,13 @@ public class AudioSharingDialogHandler {
public void closeOpeningDialogsForLeaDevice(@NonNull CachedBluetoothDevice cachedDevice) {
if (mHostFragment == null) return;
int groupId = AudioSharingUtils.getGroupId(cachedDevice);
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
List<Fragment> fragments;
try {
fragments = mHostFragment.getChildFragmentManager().getFragments();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to closeOpeningDialogsForLeaDevice: " + e.getMessage());
return;
}
for (Fragment fragment : fragments) {
CachedBluetoothDevice device = getCachedBluetoothDeviceFromDialog(fragment);
if (device != null
@@ -447,7 +459,13 @@ public class AudioSharingDialogHandler {
public void closeOpeningDialogsForNonLeaDevice(@NonNull CachedBluetoothDevice cachedDevice) {
if (mHostFragment == null) return;
String address = cachedDevice.getAddress();
List<Fragment> fragments = mHostFragment.getChildFragmentManager().getFragments();
List<Fragment> fragments;
try {
fragments = mHostFragment.getChildFragmentManager().getFragments();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to closeOpeningDialogsForNonLeaDevice: " + e.getMessage());
return;
}
for (Fragment fragment : fragments) {
CachedBluetoothDevice device = getCachedBluetoothDeviceFromDialog(fragment);
if (device != null && address != null && address.equals(device.getAddress())) {

View File

@@ -51,12 +51,13 @@ public class AudioSharingDialogHelper {
public static AlertDialog getDialogIfShowing(
@NonNull FragmentManager manager, @NonNull String tag) {
Fragment dialog = manager.findFragmentByTag(tag);
return dialog != null
&& dialog instanceof DialogFragment
&& ((DialogFragment) dialog).getDialog() != null
&& ((DialogFragment) dialog).getDialog().isShowing()
&& ((DialogFragment) dialog).getDialog() instanceof AlertDialog
return dialog instanceof DialogFragment
&& ((DialogFragment) dialog).getDialog() != null
&& ((DialogFragment) dialog).getDialog().isShowing()
&& ((DialogFragment) dialog).getDialog() instanceof AlertDialog
? (AlertDialog) ((DialogFragment) dialog).getDialog()
: null;
}
private AudioSharingDialogHelper() {}
}

View File

@@ -84,7 +84,13 @@ public class AudioSharingDisconnectDialogFragment extends InstrumentedDialogFrag
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
int newGroupId = AudioSharingUtils.getGroupId(newDevice);

View File

@@ -81,7 +81,13 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment {
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
final FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
sListener = listener;
sNewDevice = newDevice;
sEventData = eventData;

View File

@@ -81,7 +81,13 @@ public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
@NonNull DialogEventListener listener,
@NonNull Pair<Integer, Object>[] eventData) {
if (!AudioSharingUtils.isFeatureEnabled()) return;
final FragmentManager manager = host.getChildFragmentManager();
final FragmentManager manager;
try {
manager = host.getChildFragmentManager();
} catch (IllegalStateException e) {
Log.d(TAG, "Fail to show dialog: " + e.getMessage());
return;
}
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
int newGroupId = AudioSharingUtils.getGroupId(newDevice);

View File

@@ -23,6 +23,7 @@ import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.os.Bundle;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.appcompat.app.AlertDialog;
@@ -78,10 +79,6 @@ public class AudioSharingCallAudioDialogFragmentTest {
BluetoothStatusCodes.FEATURE_SUPPORTED);
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mFragment = new AudioSharingCallAudioDialogFragment();
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
}
@After
@@ -91,6 +88,7 @@ public class AudioSharingCallAudioDialogFragmentTest {
@Test
public void getMetricsCategory_correctValue() {
mFragment = new AudioSharingCallAudioDialogFragment();
assertThat(mFragment.getMetricsCategory())
.isEqualTo(SettingsEnums.DIALOG_AUDIO_SHARING_CALL_AUDIO);
}
@@ -98,21 +96,52 @@ public class AudioSharingCallAudioDialogFragmentTest {
@Test
public void onCreateDialog_flagOff_dialogNotExist() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
AudioSharingCallAudioDialogFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mParent = new Fragment();
AudioSharingCallAudioDialogFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_nullDeviceItems_showEmptyDialog() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mFragment = new AudioSharingCallAudioDialogFragment();
mFragment.setArguments(Bundle.EMPTY);
FragmentController.setupFragment(
mFragment, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
AlertDialog dialog = (AlertDialog) mFragment.onCreateDialog(Bundle.EMPTY);
dialog.show();
shadowMainLooper().idle();
assertThat(dialog.isShowing()).isTrue();
assertThat(dialog.getListView()).isNull();
}
@Test
public void onCreateDialog_showCorrectItems() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
ArrayList<AudioSharingDeviceItem> deviceItemList = new ArrayList<>();
deviceItemList.add(TEST_DEVICE_ITEM1);
deviceItemList.add(TEST_DEVICE_ITEM2);
mFragment.show(mParent, deviceItemList, (item) -> {});
AudioSharingCallAudioDialogFragment.show(mParent, deviceItemList, (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
assertThat(dialog.getListView().getCount()).isEqualTo(2);
}
}

View File

@@ -95,6 +95,15 @@ public class AudioSharingConfirmDialogFragmentTest {
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingConfirmDialogFragment.show(new Fragment());
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_flagOn_showDialog() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);

View File

@@ -130,7 +130,16 @@ public class AudioSharingDialogFragmentTest {
AudioSharingDialogFragment.show(
mParent, new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingDialogFragment.show(
new Fragment(), new ArrayList<>(), EMPTY_EVENT_LISTENER, TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}

View File

@@ -647,6 +647,15 @@ public class AudioSharingDialogHandlerTest {
SettingsEnums.DIALOG_START_AUDIO_SHARING);
}
@Test
public void closeOpeningDialogsForLeaDevice_unattachedFragment_doNothing() {
mParentFragment = new Fragment();
mHandler = new AudioSharingDialogHandler(mContext, mParentFragment);
mHandler.closeOpeningDialogsForLeaDevice(mCachedDevice1);
shadowOf(Looper.getMainLooper()).idle();
verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider);
}
@Test
public void closeOpeningDialogsForLeaDevice_closeDisconnectDialog() {
// Show disconnect dialog
@@ -674,6 +683,15 @@ public class AudioSharingDialogHandlerTest {
SettingsEnums.DIALOG_AUDIO_SHARING_SWITCH_DEVICE);
}
@Test
public void closeOpeningDialogsForNonLeaDevice_unattachedFragment_doNothing() {
mParentFragment = new Fragment();
mHandler = new AudioSharingDialogHandler(mContext, mParentFragment);
mHandler.closeOpeningDialogsForNonLeaDevice(mCachedDevice2);
shadowOf(Looper.getMainLooper()).idle();
verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider);
}
@Test
public void closeOpeningDialogsForNonLeaDevice_closeStopDialog() {
// Show stop dialog

View File

@@ -153,6 +153,23 @@ public class AudioSharingDisconnectDialogFragmentTest {
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mDeviceItems = new ArrayList<>();
mDeviceItems.add(TEST_DEVICE_ITEM1);
mDeviceItems.add(TEST_DEVICE_ITEM2);
AudioSharingDisconnectDialogFragment.show(
new Fragment(),
mDeviceItems,
mCachedDevice3,
EMPTY_EVENT_LISTENER,
TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_flagOn_dialogShowBtnForTwoDevices() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);

View File

@@ -163,6 +163,20 @@ public class AudioSharingJoinDialogFragmentTest {
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingJoinDialogFragment.show(
new Fragment(),
new ArrayList<>(),
mCachedDevice2,
EMPTY_EVENT_LISTENER,
TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);

View File

@@ -148,6 +148,20 @@ public class AudioSharingStopDialogFragmentTest {
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_unattachedFragment_dialogNotExist() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingStopDialogFragment.show(
new Fragment(),
ImmutableList.of(TEST_DEVICE_ITEM2),
mCachedDevice1,
EMPTY_EVENT_LISTENER,
TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void onCreateDialog_oneDeviceInSharing_showDialogWithCorrectMessage() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);