diff --git a/res/layout/locale_drag_cell.xml b/res/layout/locale_drag_cell.xml index 7b932f39a02..47bf70a473e 100644 --- a/res/layout/locale_drag_cell.xml +++ b/res/layout/locale_drag_cell.xml @@ -56,6 +56,17 @@ android:layout_toStartOf="@+id/dragHandle" android:layout_below="@id/label"/> + + Languages + + Preferred language order + + + System language + Remove @@ -325,13 +331,13 @@ Preferred Language - App Languages + App languages Set the language for each app - App Language + App language Suggested languages @@ -354,6 +360,18 @@ Only apps that support language selection are shown here. + + Your system, apps, and websites use the first supported language from your preferred languages. + + + To select a language for each app, go to app language settings. + + + Learn more about languages + + + https://support.google.com/android?p=per_language_app_settings + Regional preferences @@ -407,7 +425,7 @@ Keep at least one preferred language - May not be available in some apps + Not available as system language Move up diff --git a/res/xml/languages.xml b/res/xml/languages.xml new file mode 100644 index 00000000000..0f455407645 --- /dev/null +++ b/res/xml/languages.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java index ab9110d01ab..b3c2e3071af 100644 --- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java +++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java @@ -43,7 +43,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; - class LocaleDragAndDropAdapter extends RecyclerView.Adapter { @@ -154,8 +153,10 @@ class LocaleDragAndDropAdapter final LocaleDragCell dragCell = holder.getLocaleDragCell(); final String label = feedItem.getFullNameNative(); final String description = feedItem.getFullNameInUiLanguage(); + dragCell.setLabelAndDescription(label, description); dragCell.setLocalized(feedItem.isTranslated()); + dragCell.setCurrentDefault(feedItem.getLocale().equals(Locale.getDefault())); dragCell.setMiniLabel(mNumberFormatter.format(i + 1)); dragCell.setShowCheckbox(mRemoveMode); dragCell.setShowMiniLabel(!mRemoveMode); diff --git a/src/com/android/settings/localepicker/LocaleDragCell.java b/src/com/android/settings/localepicker/LocaleDragCell.java index ea86189b018..2f4cfefefb1 100644 --- a/src/com/android/settings/localepicker/LocaleDragCell.java +++ b/src/com/android/settings/localepicker/LocaleDragCell.java @@ -33,6 +33,7 @@ class LocaleDragCell extends RelativeLayout { private CheckBox mCheckbox; private TextView mMiniLabel; private TextView mLocalized; + private TextView mCurrentDefault; private ImageView mDragHandle; public LocaleDragCell(Context context, AttributeSet attrs) { @@ -44,6 +45,7 @@ class LocaleDragCell extends RelativeLayout { super.onFinishInflate(); mLabel = (TextView) findViewById(R.id.label); mLocalized = (TextView) findViewById(R.id.l10nWarn); + mCurrentDefault = (TextView) findViewById(R.id.default_locale); mMiniLabel = (TextView) findViewById(R.id.miniLabel); mCheckbox = (CheckBox) findViewById(R.id.checkbox); mDragHandle = (ImageView) findViewById(R.id.dragHandle); @@ -100,6 +102,14 @@ class LocaleDragCell extends RelativeLayout { invalidate(); } + /** + * Indicate current locale is system default. + */ + public void setCurrentDefault(boolean isCurrentDefault) { + mCurrentDefault.setVisibility(isCurrentDefault ? VISIBLE : GONE); + invalidate(); + } + public ImageView getDragHandle() { return mDragHandle; } diff --git a/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java new file mode 100644 index 00000000000..05c740139cc --- /dev/null +++ b/src/com/android/settings/localepicker/LocaleHelperPreferenceController.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 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 androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settingslib.HelpUtils; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.widget.FooterPreference; + +/** + * A controller to update current locale information of application. + */ +public class LocaleHelperPreferenceController extends AbstractPreferenceController { + private static final String TAG = LocaleHelperPreferenceController.class.getSimpleName(); + + private static final String KEY_FOOTER_LANGUAGE_PICKER = "footer_languages_picker"; + + public LocaleHelperPreferenceController(Context context) { + super(context); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public String getPreferenceKey() { + return KEY_FOOTER_LANGUAGE_PICKER; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + FooterPreference footerPreference = screen.findPreference(getPreferenceKey()); + updateFooterPreference(footerPreference); + } + + @VisibleForTesting + void updateFooterPreference(FooterPreference footerPreference) { + if (footerPreference != null) { + footerPreference.setLearnMoreAction(v -> openLocaleLearnMoreLink()); + footerPreference.setLearnMoreText(mContext.getString( + R.string.desc_locale_helper_footer_general)); + } + } + + private void openLocaleLearnMoreLink() { + mContext.startActivity( + HelpUtils.getHelpIntent( + mContext, + mContext.getString(R.string.link_locale_picker_footer_learn_more), + /*backupContext=*/"")); + } +} diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java index 1d6fb47d76a..75ea768e232 100644 --- a/src/com/android/settings/localepicker/LocaleListEditor.java +++ b/src/com/android/settings/localepicker/LocaleListEditor.java @@ -36,6 +36,7 @@ import android.widget.TextView; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceScreen; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.app.LocalePicker; @@ -47,6 +48,7 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.utils.StringUtil; +import com.android.settingslib.widget.LayoutPreference; import java.util.ArrayList; import java.util.List; @@ -65,6 +67,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment { private static final int REQUEST_LOCALE_PICKER = 0; private static final String INDEX_KEY_ADD_LANGUAGE = "add_language"; + private static final String KEY_LANGUAGES_PICKER = "languages_picker"; private LocaleDragAndDropAdapter mAdapter; private Menu mMenu; @@ -73,6 +76,9 @@ public class LocaleListEditor extends RestrictedSettingsFragment { private boolean mShowingRemoveDialog; private boolean mIsUiRestricted; + private LayoutPreference mLocalePickerPreference; + private LocaleHelperPreferenceController mLocaleHelperPreferenceController; + public LocaleListEditor() { super(DISALLOW_CONFIG_LOCALE); } @@ -87,6 +93,14 @@ public class LocaleListEditor extends RestrictedSettingsFragment { super.onCreate(savedInstanceState); setHasOptionsMenu(true); + addPreferencesFromResource(R.xml.languages); + final Activity activity = getActivity(); + activity.setTitle(R.string.language_picker_title); + mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(activity); + final PreferenceScreen screen = getPreferenceScreen(); + mLocalePickerPreference = screen.findPreference(KEY_LANGUAGES_PICKER); + mLocaleHelperPreferenceController.displayPreference(screen); + LocaleStore.fillCache(this.getContext()); final List feedsList = getUserLocaleList(); mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList); @@ -94,11 +108,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstState) { - final View result = super.onCreateView(inflater, container, savedInstState); - final View myLayout = inflater.inflate(R.layout.locale_order_list, (ViewGroup) result); - - configureDragAndDrop(myLayout); - return result; + configureDragAndDrop(mLocalePickerPreference); + return super.onCreateView(inflater, container, savedInstState); } @Override @@ -288,8 +299,8 @@ public class LocaleListEditor extends RestrictedSettingsFragment { return result; } - private void configureDragAndDrop(View view) { - final RecyclerView list = view.findViewById(R.id.dragList); + private void configureDragAndDrop(LayoutPreference layout) { + final RecyclerView list = layout.findViewById(R.id.dragList); final LocaleLinearLayoutManager llm = new LocaleLinearLayoutManager(getContext(), mAdapter); llm.setAutoMeasureEnabled(true); list.setLayoutManager(llm); @@ -298,7 +309,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment { mAdapter.setRecyclerView(list); list.setAdapter(mAdapter); - mAddLanguage = view.findViewById(R.id.add_language); + mAddLanguage = layout.findViewById(R.id.add_language); mAddLanguage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java new file mode 100644 index 00000000000..31b8e794480 --- /dev/null +++ b/tests/unit/src/com/android/settings/localepicker/LocaleHelperPreferenceControllerTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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 static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.Looper; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settingslib.widget.FooterPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class LocaleHelperPreferenceControllerTest { + private Context mContext; + private LocaleHelperPreferenceController mLocaleHelperPreferenceController; + + @Mock + private FooterPreference mMockFooterPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = ApplicationProvider.getApplicationContext(); + mLocaleHelperPreferenceController = new LocaleHelperPreferenceController(mContext); + } + + @Test + public void updateFooterPreference_setFooterPreference_hasClickAction() { + mLocaleHelperPreferenceController.updateFooterPreference(mMockFooterPreference); + verify(mMockFooterPreference).setLearnMoreText(anyString()); + } +}