diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java index 2dc09bd9ee0..ad9e10f19ed 100644 --- a/src/com/android/settings/localepicker/LocaleDialogFragment.java +++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java @@ -21,8 +21,8 @@ import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; -import android.os.ResultReceiver; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -35,7 +35,6 @@ import androidx.fragment.app.FragmentManager; import com.android.internal.app.LocaleStore; import com.android.settings.R; -import com.android.settings.RestrictedSettingsFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -46,49 +45,19 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class LocaleDialogFragment extends InstrumentedDialogFragment { private static final String TAG = LocaleDialogFragment.class.getSimpleName(); - static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0; - static final int DIALOG_NOT_AVAILABLE_LOCALE = 1; + static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1; + static final int DIALOG_NOT_AVAILABLE_LOCALE = 2; static final String ARG_DIALOG_TYPE = "arg_dialog_type"; static final String ARG_TARGET_LOCALE = "arg_target_locale"; - static final String ARG_RESULT_RECEIVER = "arg_result_receiver"; + static final String ARG_SHOW_DIALOG = "arg_show_dialog"; + + private boolean mShouldKeepDialog; public static LocaleDialogFragment newInstance() { return new LocaleDialogFragment(); } - /** - * Show dialog - */ - public void show( - @NonNull RestrictedSettingsFragment fragment, - int dialogType, - LocaleStore.LocaleInfo localeInfo) { - if (!isAdded()) { - return; - } - show(fragment, dialogType, localeInfo, null); - } - - /** - * Show dialog - */ - public void show( - @NonNull RestrictedSettingsFragment fragment, - int dialogType, - LocaleStore.LocaleInfo localeInfo, - ResultReceiver resultReceiver) { - FragmentManager manager = fragment.getChildFragmentManager(); - Bundle args = new Bundle(); - args.putInt(ARG_DIALOG_TYPE, dialogType); - args.putSerializable(ARG_TARGET_LOCALE, localeInfo); - args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver); - - LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment(); - localeDialogFragment.setArguments(args); - localeDialogFragment.show(manager, TAG); - } - @Override public int getMetricsCategory() { int dialogType = getArguments().getInt(ARG_DIALOG_TYPE); @@ -102,9 +71,29 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { } } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(ARG_SHOW_DIALOG, mShouldKeepDialog); + } + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - LocaleDialogController controller = new LocaleDialogController(this); + if (savedInstanceState != null) { + Bundle arguments = getArguments(); + int type = arguments.getInt(ARG_DIALOG_TYPE); + mShouldKeepDialog = savedInstanceState.getBoolean(ARG_SHOW_DIALOG, false); + // Keep the dialog if user rotates the device, otherwise close the confirm system + // default dialog only when user changes the locale. + if (type == DIALOG_CONFIRM_SYSTEM_DEFAULT && !mShouldKeepDialog) { + dismiss(); + } + } + + mShouldKeepDialog = true; + LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment(); + LocaleDialogController controller = getLocaleDialogController(getContext(), this, + parentFragment); LocaleDialogController.DialogContent dialogContent = controller.getDialogContent(); ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate( R.layout.locale_dialog, null); @@ -140,47 +129,57 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment { textView.setText(content); } - static class LocaleDialogController implements DialogInterface.OnClickListener { + @VisibleForTesting + LocaleDialogController getLocaleDialogController(Context context, + LocaleDialogFragment dialogFragment, LocaleListEditor parentFragment) { + return new LocaleDialogController(context, dialogFragment, parentFragment); + } + + class LocaleDialogController implements DialogInterface.OnClickListener { private final Context mContext; private final int mDialogType; private final LocaleStore.LocaleInfo mLocaleInfo; - private final ResultReceiver mResultReceiver; private final MetricsFeatureProvider mMetricsFeatureProvider; + private LocaleListEditor mParent; + LocaleDialogController( - @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) { + @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment, + LocaleListEditor parentFragment) { mContext = context; Bundle arguments = dialogFragment.getArguments(); mDialogType = arguments.getInt(ARG_DIALOG_TYPE); - mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable( - ARG_TARGET_LOCALE); - mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER); + mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE); mMetricsFeatureProvider = FeatureFactory.getFactory( mContext).getMetricsFeatureProvider(); + mParent = parentFragment; } - LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) { - this(dialogFragment.getContext(), dialogFragment); + LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment, + LocaleListEditor parent) { + this(dialogFragment.getContext(), dialogFragment, parent); } @Override public void onClick(DialogInterface dialog, int which) { - if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) { + if (mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) { + int result = Activity.RESULT_CANCELED; + if (which == DialogInterface.BUTTON_POSITIVE) { + result = Activity.RESULT_OK; + } + Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); - if (which == DialogInterface.BUTTON_POSITIVE) { - mResultReceiver.send(Activity.RESULT_OK, bundle); - } else if (which == DialogInterface.BUTTON_NEGATIVE) { - mResultReceiver.send(Activity.RESULT_CANCELED, bundle); - } + intent.putExtras(bundle); + mParent.onActivityResult(DIALOG_CONFIRM_SYSTEM_DEFAULT, result, intent); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE); } + mShouldKeepDialog = false; } @VisibleForTesting DialogContent getDialogContent() { - DialogContent - dialogContent = new DialogContent(); + DialogContent dialogContent = new DialogContent(); switch (mDialogType) { case DIALOG_CONFIRM_SYSTEM_DEFAULT: dialogContent.mTitle = String.format(mContext.getString( diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java index 2223db06562..edd302645e2 100644 --- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java +++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java @@ -16,14 +16,11 @@ package com.android.settings.localepicker; -import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.os.Bundle; -import android.os.Handler; import android.os.LocaleList; -import android.os.Looper; -import android.os.ResultReceiver; +import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; @@ -52,15 +49,20 @@ class LocaleDragAndDropAdapter private static final String TAG = "LocaleDragAndDropAdapter"; private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales"; + private static final String CFGKEY_DRAG_LOCALE = "dragLocales"; + private static final String CFGKEY_DRAG_LOCALES_TO_POSITION = "dragLocales_end"; + private final Context mContext; + private final ItemTouchHelper mItemTouchHelper; + private List mFeedItemList; private List mCacheItemList; - private final ItemTouchHelper mItemTouchHelper; private RecyclerView mParentView = null; private LocaleListEditor mParent; private boolean mRemoveMode = false; private boolean mDragEnabled = true; private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance(); + private LocaleStore.LocaleInfo mDragLocale; class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener { private final LocaleDragCell mLocaleDragCell; @@ -87,8 +89,7 @@ class LocaleDragAndDropAdapter } } - LocaleDragAndDropAdapter(LocaleListEditor parent, - List feedItemList) { + LocaleDragAndDropAdapter(LocaleListEditor parent, List feedItemList) { mFeedItemList = feedItemList; mParent = parent; mCacheItemList = new ArrayList<>(feedItemList); @@ -202,6 +203,7 @@ class LocaleDragAndDropAdapter final LocaleStore.LocaleInfo saved = mFeedItemList.get(fromPosition); mFeedItemList.remove(fromPosition); mFeedItemList.add(toPosition, saved); + mDragLocale = saved; } else { // TODO: It looks like sometimes the RecycleView tries to swap item -1 // I did not see it in a while, but if it happens, investigate and file a bug. @@ -317,43 +319,20 @@ class LocaleDragAndDropAdapter }); } - public void doTheUpdateWithMovingLocaleItem() { - LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0); - final LocaleDialogFragment fragment = LocaleDialogFragment.newInstance(); - if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) { - fragment.show(mParent, - LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, - localeInfo, - new ResultReceiver(new Handler(Looper.getMainLooper())) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE); - if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) { - if (resultCode == Activity.RESULT_OK) { - doTheUpdate(); - if (!localeInfo.isTranslated()) { - fragment.show(mParent, - LocaleDialogFragment - .DIALOG_NOT_AVAILABLE_LOCALE, - localeInfo); - } - } else { - if (!localeInfo.getLocale() - .equals(mCacheItemList.get(0).getLocale())) { - mFeedItemList = new ArrayList<>(mCacheItemList); - notifyDataSetChanged(); - } - } - mCacheItemList = new ArrayList<>(mFeedItemList); - } - } - }); - } else { - doTheUpdate(); + public void notifyListChanged(LocaleStore.LocaleInfo localeInfo) { + if (!localeInfo.getLocale().equals(mCacheItemList.get(0).getLocale())) { + mFeedItemList = new ArrayList<>(mCacheItemList); + notifyDataSetChanged(); } } + public void setCacheItemList() { + mCacheItemList = new ArrayList<>(mFeedItemList); + } + + public List getFeedItemList() { + return mFeedItemList; + } private void setDragEnabled(boolean enabled) { mDragEnabled = enabled; } @@ -373,6 +352,8 @@ class LocaleDragAndDropAdapter } } outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales); + // Save the dragged locale before rotation + outInstanceState.putSerializable(CFGKEY_DRAG_LOCALE, mDragLocale); } } @@ -381,18 +362,30 @@ class LocaleDragAndDropAdapter * (for instance when the device is rotated) * * @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)} + * @param isDialogShowing A flag indicating whether the dialog is showing or not. */ - public void restoreState(Bundle savedInstanceState) { - if (savedInstanceState != null && mRemoveMode) { - final ArrayList selectedLocales = - savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES); - if (selectedLocales == null || selectedLocales.isEmpty()) { - return; + public void restoreState(Bundle savedInstanceState, boolean isDialogShowing) { + if (savedInstanceState != null) { + if (mRemoveMode) { + final ArrayList selectedLocales = + savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES); + if (selectedLocales == null || selectedLocales.isEmpty()) { + return; + } + for (LocaleStore.LocaleInfo li : mFeedItemList) { + li.setChecked(selectedLocales.contains(li.getId())); + } + notifyItemRangeChanged(0, mFeedItemList.size()); + } else if (isDialogShowing) { + // After rotation, the dragged position will be restored to original. Restore the + // drag locale's original position to the top. + mDragLocale = (LocaleStore.LocaleInfo) savedInstanceState.getSerializable( + CFGKEY_DRAG_LOCALE); + mFeedItemList.removeIf( + localeInfo -> TextUtils.equals(localeInfo.getId(), mDragLocale.getId())); + mFeedItemList.add(0, mDragLocale); + notifyItemRangeChanged(0, mFeedItemList.size()); } - for (LocaleStore.LocaleInfo li : mFeedItemList) { - li.setChecked(selectedLocales.contains(li.getId())); - } - notifyItemRangeChanged(0, mFeedItemList.size()); } } } diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java index 6317f24a304..7ec08f7300e 100644 --- a/src/com/android/settings/localepicker/LocaleListEditor.java +++ b/src/com/android/settings/localepicker/LocaleListEditor.java @@ -18,6 +18,8 @@ package com.android.settings.localepicker; import static android.os.UserManager.DISALLOW_CONFIG_LOCALE; +import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT; + import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; @@ -32,12 +34,14 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.FragmentManager; import androidx.preference.PreferenceScreen; import androidx.recyclerview.widget.RecyclerView; @@ -60,7 +64,7 @@ import java.util.Locale; * Drag-and-drop editor for the user-ordered locale lists. */ @SearchIndexable -public class LocaleListEditor extends RestrictedSettingsFragment { +public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener { protected static final String INTENT_LOCALE_KEY = "localeInfo"; private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode"; @@ -70,6 +74,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment { private static final String INDEX_KEY_ADD_LANGUAGE = "add_language"; private static final String KEY_LANGUAGES_PICKER = "languages_picker"; + 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 LocaleDragAndDropAdapter mAdapter; private Menu mMenu; @@ -80,6 +86,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment { private LayoutPreference mLocalePickerPreference; private LocaleHelperPreferenceController mLocaleHelperPreferenceController; + private FragmentManager mFragmentManager; public LocaleListEditor() { super(DISALLOW_CONFIG_LOCALE); @@ -106,6 +113,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment { LocaleStore.fillCache(this.getContext()); final List feedsList = getUserLocaleList(); mAdapter = new LocaleDragAndDropAdapter(this, feedsList); + mFragmentManager = getChildFragmentManager(); } @Override @@ -141,7 +149,15 @@ public class LocaleListEditor extends RestrictedSettingsFragment { mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false); } setRemoveMode(mRemoveMode); - mAdapter.restoreState(savedInstanceState); + + final LocaleDialogFragment dialogFragment = + (LocaleDialogFragment) mFragmentManager.findFragmentByTag( + TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT); + boolean isDialogShowing = false; + if (dialogFragment != null && dialogFragment.isAdded()) { + isDialogShowing = true; + } + mAdapter.restoreState(savedInstanceState, isDialogShowing); if (mShowingRemoveDialog) { showRemoveLocaleWarningDialog(); @@ -178,17 +194,32 @@ public class LocaleListEditor extends RestrictedSettingsFragment { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { + LocaleStore.LocaleInfo localeInfo; if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK && data != null) { - final LocaleStore.LocaleInfo localeInfo = - (LocaleStore.LocaleInfo) data.getSerializableExtra( - INTENT_LOCALE_KEY); - + localeInfo = (LocaleStore.LocaleInfo) data.getSerializableExtra(INTENT_LOCALE_KEY); String preferencesTags = Settings.System.getString( getContext().getContentResolver(), Settings.System.LOCALE_PREFERENCES); mAdapter.addLocale(mayAppendUnicodeTags(localeInfo, preferencesTags)); updateVisibilityOfRemoveMenu(); + } else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) { + localeInfo = mAdapter.getFeedItemList().get(0); + if (resultCode == Activity.RESULT_OK) { + mAdapter.doTheUpdate(); + if (!localeInfo.isTranslated()) { + Bundle args = new Bundle(); + args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, + LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE); + args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo); + LocaleDialogFragment localeDialogFragment = LocaleDialogFragment.newInstance(); + localeDialogFragment.setArguments(args); + localeDialogFragment.show(mFragmentManager, TAG_DIALOG_NOT_AVAILABLE); + } + } else { + mAdapter.notifyListChanged(localeInfo); + } + mAdapter.setCacheItemList(); } super.onActivityResult(requestCode, resultCode, data); } @@ -332,6 +363,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment { list.setNestedScrollingEnabled(false); mAdapter.setRecyclerView(list); list.setAdapter(mAdapter); + list.setOnTouchListener(this); mAddLanguage = layout.findViewById(R.id.add_language); mAddLanguage.setOnClickListener(new View.OnClickListener() { @@ -348,6 +380,26 @@ public class LocaleListEditor extends RestrictedSettingsFragment { }); } + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + LocaleStore.LocaleInfo localeInfo = mAdapter.getFeedItemList().get(0); + if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) { + 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, localeInfo); + localeDialogFragment.setArguments(args); + localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT); + } else { + mAdapter.doTheUpdate(); + } + } + return false; + } + // 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/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java index 5d469bf7f10..4a5f28b8855 100644 --- a/src/com/android/settings/localepicker/LocaleRecyclerView.java +++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java @@ -34,15 +34,4 @@ class LocaleRecyclerView extends RecyclerView { public LocaleRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } - - @Override - public boolean onTouchEvent(MotionEvent e) { - if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) { - LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter(); - if (adapter != null) { - adapter.doTheUpdateWithMovingLocaleItem(); - } - } - return super.onTouchEvent(e); - } } diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java index 111ee5a7571..16d51beca64 100644 --- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java +++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java @@ -18,19 +18,32 @@ package com.android.settings.localepicker; 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.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; +import android.app.IActivityManager; import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.LocaleList; +import android.view.MotionEvent; import android.view.View; import android.widget.TextView; 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.R; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowActivityManager; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import org.junit.After; @@ -45,22 +58,42 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowAlertDialogCompat.class) +@Config(shadows = {ShadowAlertDialogCompat.class, ShadowActivityManager.class}) public class LocaleListEditorTest { + private static final String ARG_DIALOG_TYPE = "arg_dialog_type"; + 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 int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1; + private static final int REQUEST_CONFIRM_SYSTEM_DEFAULT = 1; + private LocaleListEditor mLocaleListEditor; private Context mContext; private FragmentActivity mActivity; + private List mLocaleList; + private Intent mIntent = new Intent(); @Mock private LocaleDragAndDropAdapter mAdapter; + @Mock + private LocaleStore.LocaleInfo mLocaleInfo; + @Mock + private FragmentManager mFragmentManager; + @Mock + private FragmentTransaction mFragmentTransaction; + @Mock + private View mView; + @Mock + private IActivityManager mActivityService; @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mLocaleListEditor = spy(new LocaleListEditor()); @@ -74,6 +107,8 @@ public class LocaleListEditorTest { ReflectionHelpers.setField(mLocaleListEditor, "mUserManager", RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE)); ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter); + ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager); + when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction); FakeFeatureFactory.setupForTest(); } @@ -174,4 +209,65 @@ public class LocaleListEditorTest { assertThat(result.getLocale().getUnicodeLocaleType("fw")).isEqualTo("wed"); assertThat(result.getLocale().getUnicodeLocaleType("mu")).isEqualTo("celsius"); } + + @Test + public void onActivityResult_ResultCodeIsOk_showNotAvailableDialog() { + Bundle bundle = new Bundle(); + bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); + mIntent.putExtras(bundle); + setUpLocaleConditions(); + mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_OK, + mIntent); + + verify(mFragmentTransaction).add(any(LocaleDialogFragment.class), + eq(TAG_DIALOG_NOT_AVAILABLE)); + } + + @Test + public void onActivityResult_ResultCodeIsCancel_notifyAdapterListChanged() { + Bundle bundle = new Bundle(); + bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT); + mIntent.putExtras(bundle); + setUpLocaleConditions(); + mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_CANCELED, + mIntent); + + verify(mAdapter).notifyListChanged(mLocaleInfo); + } + + @Test + public void onTouch_dragDifferentLocaleToTop_showConfirmDialog() throws Exception { + MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0); + setUpLocaleConditions(); + final Configuration config = new Configuration(); + config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US"))); + when(mActivityService.getConfiguration()).thenReturn(config); + when(mAdapter.getFeedItemList()).thenReturn(mLocaleList); + mLocaleListEditor.onTouch(mView, event); + + verify(mFragmentTransaction).add(any(LocaleDialogFragment.class), + eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT)); + } + + @Test + public void onTouch_dragSameLocaleToTop_updateAdapter() throws Exception { + MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0); + setUpLocaleConditions(); + final Configuration config = new Configuration(); + config.setLocales((LocaleList.forLanguageTags("en-US,zh-TW"))); + when(mActivityService.getConfiguration()).thenReturn(config); + when(mAdapter.getFeedItemList()).thenReturn(mLocaleList); + mLocaleListEditor.onTouch(mView, event); + + verify(mAdapter).doTheUpdate(); + } + + private void setUpLocaleConditions() { + 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(mAdapter.getFeedItemList()).thenReturn(mLocaleList); + } } diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java index b0998c023a6..824954da52d 100644 --- a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java +++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java @@ -17,8 +17,8 @@ package com.android.settings.localepicker; import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE; -import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER; import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE; +import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -27,12 +27,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; -import android.content.DialogInterface; import android.os.Bundle; -import android.os.ResultReceiver; import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; @@ -55,6 +52,7 @@ public class LocaleDialogFragmentTest { public final MockitoRule mockito = MockitoJUnit.rule(); private Context mContext; + private LocaleListEditor mLocaleListEditor; private LocaleDialogFragment mDialogFragment; private FakeFeatureFactory mFeatureFactory; @@ -62,30 +60,30 @@ public class LocaleDialogFragmentTest { public void setUp() throws Exception { mContext = ApplicationProvider.getApplicationContext(); mDialogFragment = new LocaleDialogFragment(); + mLocaleListEditor = spy(new LocaleListEditor()); mFeatureFactory = FakeFeatureFactory.setupForTest(); } - private void setArgument( - int type, ResultReceiver receiver) { + private void setArgument(int type) { LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH); Bundle args = new Bundle(); args.putInt(ARG_DIALOG_TYPE, type); args.putSerializable(ARG_TARGET_LOCALE, localeInfo); - args.putParcelable(ARG_RESULT_RECEIVER, receiver); mDialogFragment.setArguments(args); } @Test public void getDialogContent_confirmSystemDefault_has2ButtonText() { - setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null); + setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT); LocaleDialogFragment.LocaleDialogController controller = - new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment); + mDialogFragment.getLocaleDialogController(mContext, mDialogFragment, + mLocaleListEditor); LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent = controller.getDialogContent(); assertEquals(ResourcesUtils.getResourcesString( - mContext, "button_label_confirmation_of_system_locale_change"), + mContext, "button_label_confirmation_of_system_locale_change"), dialogContent.mPositiveButton); assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"), dialogContent.mNegativeButton); @@ -93,9 +91,10 @@ public class LocaleDialogFragmentTest { @Test public void getDialogContent_unavailableLocale_has1ButtonText() { - setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null); + setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE); LocaleDialogFragment.LocaleDialogController controller = - new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment); + mDialogFragment.getLocaleDialogController(mContext, mDialogFragment, + mLocaleListEditor); LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent = controller.getDialogContent(); @@ -105,38 +104,9 @@ public class LocaleDialogFragmentTest { assertTrue(dialogContent.mNegativeButton.isEmpty()); } - @Test - public void onClick_clickPositiveButton_sendOK() { - ResultReceiver resultReceiver = spy(new ResultReceiver(null)); - setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver); - LocaleDialogFragment.LocaleDialogController controller = - new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment); - - controller.onClick(null, DialogInterface.BUTTON_POSITIVE); - - verify(resultReceiver).send(eq(Activity.RESULT_OK), any()); - verify(mFeatureFactory.metricsFeatureProvider).action( - mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, true); - } - - @Test - public void onClick_clickNegativeButton_sendCancel() { - ResultReceiver resultReceiver = spy(new ResultReceiver(null)); - setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver); - LocaleDialogFragment.LocaleDialogController controller = - new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment); - - controller.onClick(null, DialogInterface.BUTTON_NEGATIVE); - - verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any()); - verify(mFeatureFactory.metricsFeatureProvider).action( - mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, false); - } - @Test public void getMetricsCategory_systemLocaleChange() { - setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null); - + setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT); int result = mDialogFragment.getMetricsCategory(); assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result); @@ -144,8 +114,7 @@ public class LocaleDialogFragmentTest { @Test public void getMetricsCategory_unavailableLocale() { - setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null); - + setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE); int result = mDialogFragment.getMetricsCategory(); assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);