Merge "[Language] Do not back to previous page if dialog is displaying." into udc-qpr-dev
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
index f54446a..6c37e38 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.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 @@
     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 @@
         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) {
@@ -130,6 +146,25 @@
     }
 
     @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) {
         return new LocaleDialogController(context, dialogFragment, parentFragment);
@@ -155,11 +190,6 @@
             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 0000000..57f2b01
--- /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();
+
+    }
+}