Create a new region picker page

1. The region which is selected in region picker will also apply to the first locale.
2. When a user change the first locale, the region of the first locale will be updated to the region picker.

Bug: 385047778
Flag: com.android.settings.flags.regional_preferences_api_enabled
Test: check hsv
Change-Id: I001e0910ce9d1601513ed2f52e6ee30d3551859f
This commit is contained in:
danielwbhuang
2024-12-18 01:58:09 +08:00
parent 7b0e140dc5
commit 09b9d052fc
8 changed files with 521 additions and 0 deletions

View File

@@ -365,6 +365,18 @@
<!-- Used in setup wizard Wi-Fi screen. The button label for going to the next screen and submitting. [CHAR LIMIT=20] -->
<string name="next_label">Next</string>
<!-- RegionPicker-->
<!-- Title for region picker preferences. [CHAR LIMIT=50] -->
<string name="region_picker_preference_title">Region</string>
<!-- Title for the region picker activity. [CHAR LIMIT=30]-->
<string name="region_picker_title">Choose a region</string>
<!-- The subtitle of region picker activity. [CHAR LIMIT=NONE] -->
<string name="region_picker_sub_title">The region you choose affects how your device displays time, dates, temperature, and more.</string>
<!-- Category for suggested regions. [CHAR LIMIT=50]-->
<string name="suggested_region_title">Suggested</string>
<!-- Category for all supported regions. [CHAR LIMIT=50]-->
<string name="all_supported_region_title">All regions</string>
<!-- LocalePicker -->
<!-- Title for the locale picker activity. [CHAR LIMIT=30]-->
<string name="language_picker_title">Languages</string>

View File

@@ -51,6 +51,13 @@
android:title="@string/regional_preferences_category_title"
settings:controller="com.android.settings.regionalpreferences.RegionalPreferencesCategoryController">
<Preference
android:key="region_preference"
android:title="@string/region_picker_preference_title"
settings:controller="com.android.settings.regionalpreferences.RegionPreferenceController"
settings:fragment="com.android.settings.regionalpreferences.RegionPickerFragment">
</Preference>
<Preference
android:key="temperature_preference"
android:title="@string/temperature_preferences_title"

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2024 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="key_system_region_picker_page"
android:title="@string/region_picker_title">
<com.android.settingslib.widget.TopIntroPreference
android:key="key_region_picker_sub_title"
android:title="@string/region_picker_sub_title"
android:persistent="false"/>
<PreferenceCategory
android:key="system_region_suggested_category"
android:title="@string/suggested_region_title"/>
<PreferenceCategory
android:key="system_region_all_supported_category"
android:title="@string/all_supported_region_title"/>
</PreferenceScreen>

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2024 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.regionalpreferences;
import android.content.Context;
import android.os.LocaleList;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.Initializer;
import com.android.internal.app.LocaleCollectorBase;
import com.android.internal.app.LocaleHelper;
import com.android.internal.app.LocalePicker;
import com.android.internal.app.LocaleStore;
import com.android.internal.app.LocaleStore.LocaleInfo;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class RegionPickerBaseListPreferenceController extends BasePreferenceController {
private static final String TAG = "RegionPickerBaseListPreferenceController";
private static final String KEY_SUGGESTED = "suggested";
private PreferenceCategory mPreferenceCategory;
private Set<LocaleInfo> mLocaleList;
private ArrayList<LocaleInfo> mLocaleOptions;
public RegionPickerBaseListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
mLocaleList = getLocaleCollectorController(context).getSupportedLocaleList(null,
false, false);
mLocaleOptions = new ArrayList<>();
mLocaleOptions.ensureCapacity(mLocaleList.size());
}
@Override
@Initializer
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceCategory = screen.findPreference(getPreferenceCategoryKey());
updatePreferences();
}
private void updatePreferences() {
if (mPreferenceCategory == null) {
Log.d(TAG, "updatePreferences, mPreferenceCategory is null");
return;
}
List<LocaleStore.LocaleInfo> result;
LocaleStore.LocaleInfo parentLocale = getParentLocale();
if (parentLocale != null) {
mLocaleList = getLocaleCollectorController(mContext).getSupportedLocaleList(
parentLocale, false, true);
}
mLocaleOptions.clear();
mLocaleOptions.ensureCapacity(mLocaleList.size());
result = getPreferenceCategoryKey().contains(KEY_SUGGESTED)
? getSuggestedLocaleList()
: getSupportedLocaleList();
if (getPreferenceCategoryKey().contains(KEY_SUGGESTED)) {
Locale systemLocale = Locale.getDefault();
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(systemLocale);
result.add(localeInfo);
}
result = getSortedLocaleList(result);
setupPreference(result);
}
private void setupPreference(List<LocaleStore.LocaleInfo> localeInfoList) {
localeInfoList.stream().forEach(locale -> {
SelectorWithWidgetPreference pref = new SelectorWithWidgetPreference(mContext);
mPreferenceCategory.addPreference(pref);
pref.setTitle(locale.getFullCountryNameNative());
pref.setKey(locale.toString());
if (locale.getLocale().equals(Locale.getDefault())) {
pref.setChecked(true);
} else {
pref.setChecked(false);
}
pref.setOnClickListener(v -> {
switchRegion(locale);
});
});
mPreferenceCategory.setVisible(mPreferenceCategory.getPreferenceCount() > 0);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
protected abstract String getPreferenceCategoryKey();
protected abstract LocaleCollectorBase getLocaleCollectorController(Context context);
@Nullable protected abstract LocaleStore.LocaleInfo getParentLocale();
protected List<LocaleStore.LocaleInfo> getSuggestedLocaleList() {
if (mLocaleList != null && !mLocaleList.isEmpty()) {
mLocaleOptions.addAll(mLocaleList.stream()
.filter(localeInfo -> localeInfo.isSuggested())
.collect(Collectors.toList()));
} else {
Log.d(TAG, "Can not get suggested locales because the locale list is null or empty.");
}
return mLocaleOptions;
}
protected List<LocaleStore.LocaleInfo> getSupportedLocaleList() {
if (mLocaleList != null && !mLocaleList.isEmpty()) {
mLocaleOptions.addAll(mLocaleList.stream()
.filter(localeInfo -> !localeInfo.isSuggested())
.collect(Collectors.toList()));
} else {
Log.d(TAG, "Can not get supported locales because the locale list is null or empty.");
}
return mLocaleOptions;
}
private List<LocaleStore.LocaleInfo> getSortedLocaleList(
List<LocaleStore.LocaleInfo> localeInfos) {
final Locale sortingLocale = Locale.getDefault();
final LocaleHelper.LocaleInfoComparator comp =
new LocaleHelper.LocaleInfoComparator(sortingLocale, true);
Collections.sort(localeInfos, comp);
return localeInfos;
}
private void switchRegion(LocaleStore.LocaleInfo localeInfo) {
if (localeInfo.getLocale().equals(Locale.getDefault())) {
return;
}
updateRegion(localeInfo.getLocale().toLanguageTag());
updatePreferences();
}
private void updateRegion(String selectedLanguageTag) {
LocaleList localeList = LocaleList.getDefault();
Locale systemLocale = Locale.getDefault();
Set<Character> extensionKeys = systemLocale.getExtensionKeys();
Locale selectedLocale = Locale.forLanguageTag(selectedLanguageTag);
Locale.Builder builder = new Locale.Builder();
builder.setLocale(selectedLocale);
if (!extensionKeys.isEmpty()) {
for (Character extKey : extensionKeys) {
builder.setExtension(extKey, systemLocale.getExtension(extKey));
}
}
Locale newLocale = builder.build();
Locale[] resultLocales = new Locale[localeList.size()];
resultLocales[0] = newLocale;
for (int i = 1; i < localeList.size(); i++) {
resultLocales[i] = localeList.get(i);
}
LocalePicker.updateLocales(new LocaleList(resultLocales));
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2024 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.regionalpreferences;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class RegionPickerFragment extends DashboardFragment{
private static final String TAG = "RegionPickerFragment";
private static final String KEY_PREFERENCE_SYSTEM_REGION_LIST = "system_region_list";
private static final String KEY_PREFERENCE_SYSTEM_REGION_SUGGESTED_LIST =
"system_region_suggested_list";
@Override
public void onCreate(@NonNull Bundle icicle) {
super.onCreate(icicle);
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.system_region_picker;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
return 0;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context);
}
private List<AbstractPreferenceController> buildPreferenceControllers(
@NonNull Context context) {
Locale parentLocale = LocaleStore.getLocaleInfo(Locale.getDefault()).getParent();
LocaleStore.LocaleInfo parentLocaleInfo = LocaleStore.getLocaleInfo(parentLocale);
SystemRegionSuggestedListPreferenceController mSuggestedListPreferenceController =
new SystemRegionSuggestedListPreferenceController(
context, KEY_PREFERENCE_SYSTEM_REGION_SUGGESTED_LIST, parentLocaleInfo);
SystemRegionAllListPreferenceController mSystemRegionAllListPreferenceController =
new SystemRegionAllListPreferenceController(
context, KEY_PREFERENCE_SYSTEM_REGION_LIST, parentLocaleInfo);
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(mSuggestedListPreferenceController);
controllers.add(mSystemRegionAllListPreferenceController);
return controllers;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.system_region_picker) {
@Override
protected boolean isPageSearchEnabled(Context context) {
if (!Flags.regionalPreferencesApiEnabled()) {
return false;
}
return true;
}
};
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2024 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.regionalpreferences;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.internal.app.LocaleStore;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.flags.Flags;
import java.util.Locale;
/** A controller for the entry of region picker page */
public class RegionPreferenceController extends BasePreferenceController {
public RegionPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
}
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
Preference preference = screen.findPreference(getPreferenceKey());
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.getDefault());
preference.setSummary(localeInfo.getFullCountryNameNative());
}
@Override
public int getAvailabilityStatus() {
if (!Flags.regionalPreferencesApiEnabled()) {
return CONDITIONALLY_UNAVAILABLE;
}
return AVAILABLE;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 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.regionalpreferences;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.app.LocaleCollectorBase;
import com.android.internal.app.LocaleStore;
import com.android.internal.app.LocaleStore.LocaleInfo;
import com.android.internal.app.SystemLocaleCollector;
public class SystemRegionAllListPreferenceController extends
RegionPickerBaseListPreferenceController {
private static final String KEY_PREFERENCE_CATEGORY = "system_region_all_supported_category";
private static final String KEY_PREFERENCE_SYSTEM_REGION_LIST =
"system_region_list";
@Nullable private LocaleStore.LocaleInfo mLocaleInfo;
public SystemRegionAllListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
}
public SystemRegionAllListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey, @NonNull LocaleStore.LocaleInfo parentLocale) {
super(context, preferenceKey);
mLocaleInfo = parentLocale;
}
@Override
protected String getPreferenceCategoryKey() {
return KEY_PREFERENCE_CATEGORY;
}
@Override
@NonNull
public String getPreferenceKey() {
return KEY_PREFERENCE_SYSTEM_REGION_LIST;
}
@Override
protected LocaleCollectorBase getLocaleCollectorController(Context context) {
return new SystemLocaleCollector(context, null);
}
@Nullable
@Override
protected LocaleInfo getParentLocale() {
return mLocaleInfo;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2024 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.regionalpreferences;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.app.LocaleCollectorBase;
import com.android.internal.app.LocaleStore;
import com.android.internal.app.LocaleStore.LocaleInfo;
import com.android.internal.app.SystemLocaleCollector;
public class SystemRegionSuggestedListPreferenceController extends
RegionPickerBaseListPreferenceController {
private static final String KEY_PREFERENCE_CATEGORY = "system_region_suggested_category";
private static final String KEY_PREFERENCE_SYSTEM_REGION_SUGGESTED_LIST =
"system_region_suggested_list";
@Nullable private LocaleStore.LocaleInfo mLocaleInfo;
public SystemRegionSuggestedListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
}
public SystemRegionSuggestedListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey, @NonNull LocaleStore.LocaleInfo parentLocale) {
super(context, preferenceKey);
mLocaleInfo = parentLocale;
}
@Override
protected String getPreferenceCategoryKey() {
return KEY_PREFERENCE_CATEGORY;
}
@Override
@NonNull
public String getPreferenceKey() {
return KEY_PREFERENCE_SYSTEM_REGION_SUGGESTED_LIST;
}
@Override
protected LocaleCollectorBase getLocaleCollectorController(Context context) {
return new SystemLocaleCollector(context, null);
}
@Nullable
@Override
protected LocaleInfo getParentLocale() {
return mLocaleInfo;
}
}