Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09b9d052 authored by danielwbhuang's avatar danielwbhuang
Browse files

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
parent 7b0e140d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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>
+7 −0
Original line number Diff line number Diff line
@@ -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"
+35 −0
Original line number Diff line number Diff line
<?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>
+183 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}
+93 −0
Original line number Diff line number Diff line
/*
 * 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;
                }
            };
}
Loading