From 088bb6a35e3d5b27f1fc7d48893cc689bd7a482c Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Wed, 5 Jul 2023 10:34:53 +0000 Subject: [PATCH] [Language] Do not back to previous page if dialog is displaying. Bug: 288827218 Test: make RunSettingsRoboTests -j128 ROBOTEST_FILTER=LocaleDialogFragmentTest Change-Id: I914b1e1d96aacf5369e5149f34968ef625548525 --- .../localepicker/LocaleDialogFragment.java | 48 ++++++-- .../LocaleDialogFragmentTest.java | 107 ++++++++++++++++++ 2 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java index f54446af063..6c37e380c77 100644 --- a/src/com/android/settings/localepicker/LocaleDialogFragment.java +++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java @@ -16,6 +16,8 @@ package com.android.settings.localepicker; +import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; + import android.app.Activity; import android.app.Dialog; import android.app.settings.SettingsEnums; @@ -23,15 +25,17 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import android.window.OnBackInvokedCallback; +import android.window.OnBackInvokedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.FragmentManager; import com.android.internal.app.LocaleStore; import com.android.settings.R; @@ -53,6 +57,12 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { static final String ARG_SHOW_DIALOG = "arg_show_dialog"; private boolean mShouldKeepDialog; + private AlertDialog mAlertDialog; + private OnBackInvokedDispatcher mBackDispatcher; + + private OnBackInvokedCallback mBackCallback = () -> { + Log.d(TAG, "Do not back to previous page if the dialog is displaying."); + }; public static LocaleDialogFragment newInstance() { return new LocaleDialogFragment(); @@ -108,9 +118,15 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { if (!dialogContent.mNegativeButton.isEmpty()) { builder.setNegativeButton(dialogContent.mNegativeButton, controller); } - AlertDialog alertDialog = builder.create(); - alertDialog.setCanceledOnTouchOutside(false); - return alertDialog; + mAlertDialog = builder.create(); + getOnBackInvokedDispatcher().registerOnBackInvokedCallback(PRIORITY_DEFAULT, mBackCallback); + mAlertDialog.setCanceledOnTouchOutside(false); + mAlertDialog.setOnDismissListener(dialogInterface -> { + mAlertDialog.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback( + mBackCallback); + }); + + return mAlertDialog; } private static void setDialogTitle(View root, String content) { @@ -129,6 +145,25 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { textView.setText(content); } + @VisibleForTesting + public OnBackInvokedCallback getBackInvokedCallback() { + return mBackCallback; + } + + @VisibleForTesting + public void setBackDispatcher(OnBackInvokedDispatcher dispatcher) { + mBackDispatcher = dispatcher; + } + + @VisibleForTesting + public OnBackInvokedDispatcher getOnBackInvokedDispatcher() { + if (mBackDispatcher != null) { + return mBackDispatcher; + } else { + return mAlertDialog.getOnBackInvokedDispatcher(); + } + } + @VisibleForTesting LocaleDialogController getLocaleDialogController(Context context, LocaleDialogFragment dialogFragment, LocaleListEditor parentFragment) { @@ -155,11 +190,6 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { mParent = parentFragment; } - LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment, - LocaleListEditor parent) { - this(dialogFragment.getContext(), dialogFragment, parent); - } - @Override public void onClick(DialogInterface dialog, int which) { if (mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) { diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java new file mode 100644 index 00000000000..57f2b01579b --- /dev/null +++ b/tests/robotests/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.localepicker; + +import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE; +import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE; +import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT; + +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 android.os.Bundle; +import android.window.OnBackInvokedDispatcher; + +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.android.internal.app.LocaleStore; +import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; +import com.android.settings.utils.ActivityControllerWrapper; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.Locale; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowAlertDialogCompat.class}) +public class LocaleDialogFragmentTest { + + @Mock + private OnBackInvokedDispatcher mOnBackInvokedDispatcher; + + private FragmentActivity mActivity; + private LocaleDialogFragment mDialogFragment; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mActivity = (FragmentActivity) ActivityControllerWrapper.setup( + Robolectric.buildActivity(FragmentActivity.class)).get(); + mDialogFragment = LocaleDialogFragment.newInstance(); + LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH); + Bundle args = new Bundle(); + args.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); + args.putSerializable(ARG_TARGET_LOCALE, localeInfo); + mDialogFragment.setArguments(args); + FragmentManager fragmentManager = mActivity.getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.add(mDialogFragment, null); + fragmentTransaction.commit(); + } + + @Test + public void onCreateDialog_onBackInvokedCallbackIsRegistered() { + mDialogFragment.setBackDispatcher(mOnBackInvokedDispatcher); + mDialogFragment.onCreateDialog(null); + + verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback( + eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any()); + } + + @Test + public void onBackInvoked_dialogIsStillDisplaying() { + mDialogFragment.setBackDispatcher(mOnBackInvokedDispatcher); + AlertDialog alertDialog = (AlertDialog) mDialogFragment.onCreateDialog(null); + alertDialog.show(); + assertThat(alertDialog).isNotNull(); + assertThat(alertDialog.isShowing()).isTrue(); + + mOnBackInvokedDispatcher.registerOnBackInvokedCallback( + eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any()); + + mDialogFragment.getBackInvokedCallback().onBackInvoked(); + + assertThat(alertDialog.isShowing()).isTrue(); + + } +}