Remove LocalePickerWithRegion class in Settings.
This class is too complex, we can't afford maintaining this long term.
We need a new Activity that wraps the framework version of LocalePickerWithRegion.
Bug: 111373939
Test: manual test & make RunSettingsRoboTests -j56
Change-Id: I93c719246b84350d2eee4e8ce1ffd97cd168925b
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d3acd13..303dea1 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -574,6 +574,12 @@
android:value="true" />
</activity>
+ <activity android:name=".localepicker.LocalePickerWithRegionActivity"
+ android:excludeFromRecents="true"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:exported="false">
+ </activity>
+
<activity
android:name=".Settings$LanguageAndInputSettingsActivity"
android:label="@string/language_settings"
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 87c19dd..cbcb1eb 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -18,8 +18,10 @@
import static android.os.UserManager.DISALLOW_CONFIG_LOCALE;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
import android.os.LocaleList;
import android.view.LayoutInflater;
@@ -40,18 +42,18 @@
import java.util.List;
import java.util.Locale;
-import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
/**
* Drag-and-drop editor for the user-ordered locale lists.
*/
-public class LocaleListEditor extends RestrictedSettingsFragment
- implements LocalePickerWithRegion.LocaleSelectedListener {
+public class LocaleListEditor extends RestrictedSettingsFragment {
+ protected static final String INTENT_LOCALE_KEY = "localeInfo";
private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
private static final String CFGKEY_REMOVE_DIALOG = "showingLocaleRemoveDialog";
private static final int MENU_ID_REMOVE = Menu.FIRST + 1;
+ private static final int REQUEST_LOCALE_PICKER = 0;
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -150,6 +152,19 @@
return super.onOptionsItemSelected(menuItem);
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK
+ && data != null) {
+ final LocaleStore.LocaleInfo locale =
+ (LocaleStore.LocaleInfo) data.getSerializableExtra(
+ INTENT_LOCALE_KEY);
+ mAdapter.addLocale(locale);
+ updateVisibilityOfRemoveMenu();
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
private void setRemoveMode(boolean mRemoveMode) {
this.mRemoveMode = mRemoveMode;
mAdapter.setRemoveMode(mRemoveMode);
@@ -267,24 +282,13 @@
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
- getContext(), LocaleListEditor.this, false /* translate only */);
- getFragmentManager()
- .beginTransaction()
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
- .replace(getId(), selector)
- .addToBackStack("localeListEditor")
- .commit();
+ final Intent intent = new Intent(getActivity(),
+ LocalePickerWithRegionActivity.class);
+ startActivityForResult(intent, REQUEST_LOCALE_PICKER);
}
});
}
- @Override
- public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
- mAdapter.addLocale(locale);
- updateVisibilityOfRemoveMenu();
- }
-
// 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/LocalePickerWithRegion.java b/src/com/android/settings/localepicker/LocalePickerWithRegion.java
deleted file mode 100644
index e8a91bc..0000000
--- a/src/com/android/settings/localepicker/LocalePickerWithRegion.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.content.Context;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.text.TextUtils;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.SearchView;
-
-import com.android.internal.R;
-import com.android.internal.app.LocaleHelper;
-import com.android.internal.app.LocalePicker;
-import com.android.internal.app.LocaleStore;
-import com.android.internal.app.SuggestedLocaleAdapter;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.fragment.app.ListFragment;
-
-/**
- * A two-step locale picker. It shows a language, then a country.
- *
- * <p>It shows suggestions at the top, then the rest of the locales.
- * Allows the user to search for locales using both their native name and their name in the
- * default locale.</p>
- */
-public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
- private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
-
- private SuggestedLocaleAdapter mAdapter;
- private LocaleSelectedListener mListener;
- private Set<LocaleStore.LocaleInfo> mLocaleList;
- private LocaleStore.LocaleInfo mParentLocale;
- private boolean mTranslatedOnly = false;
- private SearchView mSearchView = null;
- private CharSequence mPreviousSearch = null;
- private boolean mPreviousSearchHadFocus = false;
- private int mFirstVisiblePosition = 0;
- private int mTopDistance = 0;
-
- /**
- * Other classes can register to be notified when a locale was selected.
- *
- * <p>This is the mechanism to "return" the result of the selection.</p>
- */
- public interface LocaleSelectedListener {
- /**
- * The classes that want to retrieve the locale picked should implement this method.
- * @param locale the locale picked.
- */
- void onLocaleSelected(LocaleStore.LocaleInfo locale);
- }
-
- private static LocalePickerWithRegion createCountryPicker(Context context,
- LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
- boolean translatedOnly) {
- LocalePickerWithRegion
- localePicker = new LocalePickerWithRegion();
- boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
- translatedOnly);
- return shouldShowTheList ? localePicker : null;
- }
-
- public static LocalePickerWithRegion createLanguagePicker(Context context,
- LocaleSelectedListener listener, boolean translatedOnly) {
- LocalePickerWithRegion
- localePicker = new LocalePickerWithRegion();
- localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
- return localePicker;
- }
-
- /**
- * Sets the listener and initializes the locale list.
- *
- * <p>Returns true if we need to show the list, false if not.</p>
- *
- * <p>Can return false because of an error, trying to show a list of countries,
- * but no parent locale was provided.</p>
- *
- * <p>It can also return false if the caller tries to show the list in country mode and
- * there is only one country available (i.e. Japanese => Japan).
- * In this case we don't even show the list, we call the listener with that locale,
- * "pretending" it was selected, and return false.</p>
- */
- private boolean setListener(Context context, LocaleSelectedListener listener,
- LocaleStore.LocaleInfo parent, boolean translatedOnly) {
- this.mParentLocale = parent;
- this.mListener = listener;
- this.mTranslatedOnly = translatedOnly;
- setRetainInstance(true);
-
- final HashSet<String> langTagsToIgnore = new HashSet<>();
- if (!translatedOnly) {
- final LocaleList userLocales = LocalePicker.getLocales();
- final String[] langTags = userLocales.toLanguageTags().split(",");
- Collections.addAll(langTagsToIgnore, langTags);
- }
-
- if (parent != null) {
- mLocaleList = LocaleStore.getLevelLocales(context,
- langTagsToIgnore, parent, translatedOnly);
- if (mLocaleList.size() <= 1) {
- if (listener != null && (mLocaleList.size() == 1)) {
- listener.onLocaleSelected(mLocaleList.iterator().next());
- }
- return false;
- }
- } else {
- mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
- null /* no parent */, translatedOnly);
- }
-
- return true;
- }
-
- private void returnToParentFrame() {
- getFragmentManager().popBackStack(PARENT_FRAGMENT_NAME,
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
-
- if (mLocaleList == null) {
- // The fragment was killed and restored by the FragmentManager.
- // At this point we have no data, no listener. Just return, to prevend a NPE.
- // Fixes b/28748150. Created b/29400003 for a cleaner solution.
- returnToParentFrame();
- return;
- }
-
- final boolean countryMode = mParentLocale != null;
- final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
- mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
- final LocaleHelper.LocaleInfoComparator comp =
- new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
- mAdapter.sort(comp);
- setListAdapter(mAdapter);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- int id = menuItem.getItemId();
- switch (id) {
- case android.R.id.home:
- getFragmentManager().popBackStack();
- return true;
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (mParentLocale != null) {
- getActivity().setTitle(mParentLocale.getFullNameNative());
- } else {
- getActivity().setTitle(R.string.language_selection_title);
- }
-
- getListView().requestFocus();
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- // Save search status
- if (mSearchView != null) {
- mPreviousSearchHadFocus = mSearchView.hasFocus();
- mPreviousSearch = mSearchView.getQuery();
- } else {
- mPreviousSearchHadFocus = false;
- mPreviousSearch = null;
- }
-
- // Save scroll position
- final ListView list = getListView();
- final View firstChild = list.getChildAt(0);
- mFirstVisiblePosition = list.getFirstVisiblePosition();
- mTopDistance = (firstChild == null) ? 0 : (firstChild.getTop() - list.getPaddingTop());
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- final LocaleStore.LocaleInfo locale =
- (LocaleStore.LocaleInfo) getListAdapter().getItem(position);
-
- if (locale.getParent() != null) {
- if (mListener != null) {
- mListener.onLocaleSelected(locale);
- }
- returnToParentFrame();
- } else {
- LocalePickerWithRegion
- selector = LocalePickerWithRegion.createCountryPicker(
- getContext(), mListener, locale, mTranslatedOnly /* translate only */);
- if (selector != null) {
- getFragmentManager().beginTransaction()
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
- .replace(getId(), selector).addToBackStack(null)
- .commit();
- } else {
- returnToParentFrame();
- }
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if (mParentLocale == null) {
- inflater.inflate(R.menu.language_selection_list, menu);
-
- final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
- mSearchView = (SearchView) searchMenuItem.getActionView();
-
- mSearchView.setQueryHint(getText(R.string.search_language_hint));
- mSearchView.setOnQueryTextListener(this);
-
- // Restore previous search status
- if (!TextUtils.isEmpty(mPreviousSearch)) {
- searchMenuItem.expandActionView();
- mSearchView.setIconified(false);
- mSearchView.setActivated(true);
- if (mPreviousSearchHadFocus) {
- mSearchView.requestFocus();
- }
- mSearchView.setQuery(mPreviousSearch, true /* submit */);
- } else {
- mSearchView.setQuery(null, false /* submit */);
- }
-
- // Restore previous scroll position
- getListView().setSelectionFromTop(mFirstVisiblePosition, mTopDistance);
- }
- }
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- if (mAdapter != null) {
- mAdapter.getFilter().filter(newText);
- }
- return false;
- }
-}
diff --git a/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java
new file mode 100644
index 0000000..6ddcf23
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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 android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import com.android.internal.app.LocalePickerWithRegion;
+import com.android.internal.app.LocaleStore;
+
+public class LocalePickerWithRegionActivity extends Activity
+ implements LocalePickerWithRegion.LocaleSelectedListener {
+
+ private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
+ this, LocalePickerWithRegionActivity.this, false /* translate only */);
+ getFragmentManager()
+ .beginTransaction()
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .replace(android.R.id.content, selector)
+ .addToBackStack(PARENT_FRAGMENT_NAME)
+ .commit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ handleBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
+ final Intent intent = new Intent();
+ intent.putExtra(LocaleListEditor.INTENT_LOCALE_KEY, locale);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ handleBackPressed();
+ }
+
+ private void handleBackPressed() {
+ if (getFragmentManager().getBackStackEntryCount() > 1) {
+ super.onBackPressed();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+}
+
diff --git a/tests/robotests/assets/grandfather_not_implementing_instrumentable b/tests/robotests/assets/grandfather_not_implementing_instrumentable
index 27ab65c..2c8ae5d 100644
--- a/tests/robotests/assets/grandfather_not_implementing_instrumentable
+++ b/tests/robotests/assets/grandfather_not_implementing_instrumentable
@@ -5,5 +5,4 @@
com.android.settings.password.ChooseLockPattern$SaveAndFinishWorker
com.android.settings.RestrictedListPreference$RestrictedListPreferenceDialogFragment
com.android.settings.password.ConfirmDeviceCredentialBaseFragment$LastTryDialog
-com.android.settings.password.CredentialCheckResultTracker
-com.android.settings.localepicker.LocalePickerWithRegion
+com.android.settings.password.CredentialCheckResultTracker
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java b/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java
new file mode 100644
index 0000000..bad3dbd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java
@@ -0,0 +1,51 @@
+package com.android.settings.localepicker;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.app.Activity;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.Shadows;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.shadows.ShadowActivity;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class LocalePickerWithRegionActivityTest {
+
+ private LocalePickerWithRegionActivity mActivity;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final ActivityController<LocalePickerWithRegionActivity> mActivityController =
+ Robolectric.buildActivity(LocalePickerWithRegionActivity.class);
+ mActivity = spy(mActivityController.get());
+ }
+
+ @Test
+ public void onLocaleSelected_resultShouldBeOK() {
+ final ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+ mActivity.onLocaleSelected(mock(LocaleStore.LocaleInfo.class));
+
+ assertEquals(Activity.RESULT_OK, shadowActivity.getResultCode());
+ }
+
+ @Test
+ public void onLocaleSelected_localeInfoShouldBeSentBack() {
+ final ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+ mActivity.onLocaleSelected(mock(LocaleStore.LocaleInfo.class));
+
+ assertNotNull(shadowActivity.getResultIntent().getSerializableExtra(
+ LocaleListEditor.INTENT_LOCALE_KEY));
+ }
+}