diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java index a3a4b8fee72..5c7958a29ca 100644 --- a/src/com/android/settings/localepicker/LocaleDialogFragment.java +++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java @@ -26,11 +26,6 @@ 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.ImageView; -import android.widget.TextView; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedDispatcher; @@ -57,6 +52,7 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { static final String ARG_DIALOG_TYPE = "arg_dialog_type"; static final String ARG_TARGET_LOCALE = "arg_target_locale"; static final String ARG_SHOW_DIALOG = "arg_show_dialog"; + static final String ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED = "arg_show_dialog_for_not_translated"; private boolean mShouldKeepDialog; private OnBackInvokedDispatcher mBackDispatcher; @@ -185,6 +181,7 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { private final int mDialogType; private final LocaleStore.LocaleInfo mLocaleInfo; private final MetricsFeatureProvider mMetricsFeatureProvider; + private final boolean mShowDialogForNotTranslated; private LocaleListEditor mParent; @@ -194,6 +191,7 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { mContext = context; Bundle arguments = dialogFragment.getArguments(); mDialogType = arguments.getInt(ARG_DIALOG_TYPE); + mShowDialogForNotTranslated = arguments.getBoolean(ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED); mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); @@ -215,6 +213,7 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { bundle.putInt(ARG_DIALOG_TYPE, mDialogType); bundle.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, mLocaleInfo); intent.putExtras(bundle); + intent.putExtra(ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED, mShowDialogForNotTranslated); mParent.onActivityResult(mDialogType, result, intent); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, changed); diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java index 907fe7bd722..af8b6681cae 100644 --- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java +++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java @@ -364,12 +364,25 @@ class LocaleDragAndDropAdapter } public void notifyListChanged(LocaleStore.LocaleInfo localeInfo) { - if (!localeInfo.getLocale().equals(mCacheItemList.get(0).getLocale())) { + if (listChanged()) { mFeedItemList = new ArrayList<>(mCacheItemList); notifyDataSetChanged(); } } + private boolean listChanged() { + if (mFeedItemList.size() == mCacheItemList.size()) { + for (int i = 0; i < mFeedItemList.size(); i++) { + if (!mFeedItemList.get(i).getLocale().equals(mCacheItemList.get(i).getLocale())) { + return true; + } + } + return false; + } else { + return true; + } + } + public void setCacheItemList() { mCacheItemList = new ArrayList<>(mFeedItemList); } diff --git a/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java b/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java index a7ebe32b841..df0af6392fd 100644 --- a/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java +++ b/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java @@ -151,7 +151,7 @@ public class LocaleLinearLayoutManager extends LinearLayoutManager { } if (result) { - mLocaleListEditor.showConfirmDialog(false, mAdapter.getFeedItemList().get(0)); + mLocaleListEditor.showConfirmDialog(mAdapter.getFeedItemList().get(0), null); } return result; } diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java index b1f005a79ab..e2da851f8e5 100644 --- a/src/com/android/settings/localepicker/LocaleListEditor.java +++ b/src/com/android/settings/localepicker/LocaleListEditor.java @@ -44,6 +44,7 @@ import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; @@ -235,7 +236,9 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View localeInfo = mAdapter.getFeedItemList().get(0); if (resultCode == Activity.RESULT_OK) { mAdapter.doTheUpdate(); - if (!localeInfo.isTranslated()) { + boolean showNotTranslatedDialog = data.getBooleanExtra( + LocaleDialogFragment.ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED, true); + if (showNotTranslatedDialog && !localeInfo.isTranslated()) { Bundle args = new Bundle(); args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE); @@ -428,13 +431,10 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View // to remove. mRemoveMode = false; mShowingRemoveDialog = false; - LocaleStore.LocaleInfo firstLocale = - mAdapter.getFeedItemList().get(0); + Locale defaultBeforeRemoval = Locale.getDefault(); mAdapter.removeChecked(); - boolean isFirstRemoved = - firstLocale != mAdapter.getFeedItemList().get(0); - showConfirmDialog(isFirstRemoved, isFirstRemoved ? firstLocale - : mAdapter.getFeedItemList().get(0)); + showConfirmDialog(mAdapter.getFeedItemList().get(0), + defaultBeforeRemoval); setRemoveMode(false); dialogHelper.getDialog().dismiss(); }) @@ -520,27 +520,73 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { - showConfirmDialog(false, mAdapter.getFeedItemList().get(0)); + showConfirmDialog(mAdapter.getFeedItemList().get(0), null); } return false; } - public void showConfirmDialog(boolean isFirstRemoved, LocaleStore.LocaleInfo localeInfo) { + protected void showConfirmDialog(LocaleStore.LocaleInfo localeInfo, + @Nullable Locale defaultLocaleBeforeRemoval) { Locale currentSystemLocale = LocalePicker.getLocales().get(0); if (!localeInfo.getLocale().equals(currentSystemLocale)) { - final LocaleDialogFragment localeDialogFragment = - LocaleDialogFragment.newInstance(); - Bundle args = new Bundle(); - args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); - args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, - isFirstRemoved ? LocaleStore.getLocaleInfo(currentSystemLocale) : localeInfo); - localeDialogFragment.setArguments(args); - localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT); + displayDialogFragment(localeInfo, true); } else { - mAdapter.doTheUpdate(); + if (!localeInfo.isTranslated()) { + if (defaultLocaleBeforeRemoval == null) { + showDialogDueToDragAndDrop(); + } else { + showDialogDueToRemoval(defaultLocaleBeforeRemoval); + } + } else { + mAdapter.doTheUpdate(); + } } } + private void showDialogDueToDragAndDrop() { + LocaleStore.LocaleInfo newLocale = mAdapter.getFeedItemList().stream().filter( + i -> i.isTranslated()).findFirst().orElse(null); + if (newLocale == null) { + return; + } + LocaleStore.LocaleInfo oldLocale = null; + final LocaleList localeList = LocalePicker.getLocales(); + for (int i = 0; i < localeList.size(); i++) { + LocaleStore.LocaleInfo temp = LocaleStore.getLocaleInfo(localeList.get(i)); + if (temp.isTranslated()) { + oldLocale = temp; + break; + } + } + if (oldLocale != null && !newLocale.getLocale().equals( + oldLocale.getLocale())) { + displayDialogFragment(newLocale, false); + } + } + + private void showDialogDueToRemoval(Locale preDefault) { + if (preDefault == null) { + return; + } + LocaleStore.LocaleInfo currentDefault = mAdapter.getFeedItemList().stream().filter( + i -> i.isTranslated()).findFirst().orElse(null); + if (currentDefault != null && !preDefault.equals(currentDefault.getLocale())) { + displayDialogFragment(currentDefault, false); + } + } + + private void displayDialogFragment(LocaleStore.LocaleInfo localeInfo, + boolean showDialogForNotTranslated) { + final LocaleDialogFragment localeDialogFragment = LocaleDialogFragment.newInstance(); + Bundle args = new Bundle(); + args.putBoolean(LocaleDialogFragment.ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED, + showDialogForNotTranslated); + args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); + args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo); + localeDialogFragment.setArguments(args); + localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT); + } + // Hide the "Remove" menu if there is only one locale in the list, show it otherwise // This is called when the menu is first created, and then one add / remove locale private void updateVisibilityOfRemoveMenu() { diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java index 4272afe8eba..22d39e37c12 100644 --- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java +++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java @@ -36,7 +36,6 @@ import android.app.Activity; import android.app.Dialog; import android.app.IActivityManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; @@ -100,6 +99,8 @@ public class LocaleListEditorTest { public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private static final String ARG_DIALOG_TYPE = "arg_dialog_type"; + private static final String + ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED = "arg_show_dialog_for_not_translated"; private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default"; private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale"; private static final String TAG_DIALOG_ADD_SYSTEM_LOCALE = "dialog_add_system_locale"; @@ -123,6 +124,10 @@ public class LocaleListEditorTest { @Mock private LocaleStore.LocaleInfo mLocaleInfo; @Mock + private LocaleStore.LocaleInfo mLocaleInfo1; + @Mock + private LocaleStore.LocaleInfo mLocaleInfo2; + @Mock private FragmentManager mFragmentManager; @Mock private FragmentTransaction mFragmentTransaction; @@ -270,7 +275,7 @@ public class LocaleListEditorTest { public void showConfirmDialog_systemLocaleSelected_shouldShowLocaleChangeDialog() throws Exception { //pre-condition - setUpLocaleConditions(); + setUpLocaleConditions(true); final Configuration config = new Configuration(); config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US"))); when(mActivityService.getConfiguration()).thenReturn(config); @@ -299,6 +304,41 @@ public class LocaleListEditorTest { eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT)); } + @Test + public void showConfirmDialog_2ndLocaleSelected_shouldShowLocaleChangeDialog() + throws Exception { + //pre-condition + Locale.setDefault(Locale.forLanguageTag("en-US")); + setUpLocaleConditions2(); + final Configuration config = new Configuration(); + config.setLocales((LocaleList.forLanguageTags("blo-BJ,en-US,zh-TW"))); + when(mActivityService.getConfiguration()).thenReturn(config); + when(mAdapter.getFeedItemList()).thenReturn(mLocaleList); + when(mAdapter.getCheckedCount()).thenReturn(1); + when(mAdapter.getItemCount()).thenReturn(3); + when(mAdapter.isFirstLocaleChecked()).thenReturn(false); + ReflectionHelpers.setField(mLocaleListEditor, "mRemoveMode", true); + ReflectionHelpers.setField(mLocaleListEditor, "mShowingRemoveDialog", true); + + //launch the first dialog + mLocaleListEditor.showRemoveLocaleWarningDialog(); + + final Dialog dialog = ShadowDialog.getLatestDialog(); + + assertThat(dialog).isNotNull(); + + // click the remove button + dialog.findViewById(R.id.button_ok).performClick(); + ShadowLooper.idleMainLooper(); + + assertThat(dialog.isShowing()).isFalse(); + + // check the second dialog is showing + verify(mFragmentTransaction).add(any(LocaleDialogFragment.class), + eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT)); + } + + @Test public void mayAppendUnicodeTags_appendUnicodeTags_success() { LocaleStore.LocaleInfo localeInfo = LocaleStore.fromLocale(Locale.forLanguageTag("en-US")); @@ -315,7 +355,8 @@ public class LocaleListEditorTest { Bundle bundle = new Bundle(); bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); mIntent.putExtras(bundle); - setUpLocaleConditions(); + mIntent.putExtra(ARG_SHOW_DIALOG_FOR_NOT_TRANSLATED, true); + setUpLocaleConditions(false); mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_OK, mIntent); @@ -328,7 +369,7 @@ public class LocaleListEditorTest { Bundle bundle = new Bundle(); bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); mIntent.putExtras(bundle); - setUpLocaleConditions(); + setUpLocaleConditions(true); mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_CANCELED, mIntent); @@ -338,7 +379,7 @@ public class LocaleListEditorTest { @Test public void onTouch_dragDifferentLocaleToTop_showConfirmDialog() throws Exception { MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0); - setUpLocaleConditions(); + setUpLocaleConditions(true); final Configuration config = new Configuration(); config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US"))); when(mActivityService.getConfiguration()).thenReturn(config); @@ -352,7 +393,7 @@ public class LocaleListEditorTest { @Test public void onTouch_dragSameLocaleToTop_updateAdapter() throws Exception { MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0); - setUpLocaleConditions(); + setUpLocaleConditions(true); final Configuration config = new Configuration(); config.setLocales((LocaleList.forLanguageTags("en-US,zh-TW"))); when(mActivityService.getConfiguration()).thenReturn(config); @@ -490,12 +531,26 @@ public class LocaleListEditorTest { verify(mAdapter).setCheckBoxDescription(any(LocaleDragCell.class), any(), anyBoolean()); } - private void setUpLocaleConditions() { + private void setUpLocaleConditions(boolean isTranslated) { ShadowActivityManager.setService(mActivityService); mLocaleList = new ArrayList<>(); mLocaleList.add(mLocaleInfo); when(mLocaleInfo.getFullNameNative()).thenReturn("English"); when(mLocaleInfo.getLocale()).thenReturn(LocaleList.forLanguageTags("en-US").get(0)); + when(mLocaleInfo.isTranslated()).thenReturn(isTranslated); + when(mAdapter.getFeedItemList()).thenReturn(mLocaleList); + } + + private void setUpLocaleConditions2() { + ShadowActivityManager.setService(mActivityService); + mLocaleList = new ArrayList<>(); + mLocaleList.add(mLocaleInfo); + mLocaleList.add(mLocaleInfo1); + mLocaleList.add(mLocaleInfo2); + when(mLocaleInfo.getLocale()).thenReturn(Locale.forLanguageTag("blo-BJ")); + when(mLocaleInfo.isTranslated()).thenReturn(false); + when(mLocaleInfo2.getLocale()).thenReturn(Locale.forLanguageTag("zh-TW")); + when(mLocaleInfo2.isTranslated()).thenReturn(true); when(mAdapter.getFeedItemList()).thenReturn(mLocaleList); } }