Snap for 4829593 from a7ae3d31ad6b3bdff8cf9538aecc104928463bbd to pi-release

Change-Id: Ibbfcb6ac357537ea633c0f662b7c5057052db7d8
diff --git a/Android.mk b/Android.mk
index ce05c59..9108a76 100644
--- a/Android.mk
+++ b/Android.mk
@@ -34,6 +34,7 @@
       android-support-car \
       android-support-v7-preference \
       android-support-v14-preference \
+      android-arch-lifecycle-extensions \
       car-list \
       car-settings-lib \
       setup-wizard-lib-gingerbread-compat \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dc9bf61..a92c87b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -60,7 +60,8 @@
     <application
         android:icon="@drawable/ic_launcher_settings"
         android:theme="@style/CarSettingTheme"
-        android:label="@string/settings_label">
+        android:label="@string/settings_label"
+        android:supportsRtl="true">
 
         <activity
             android:name=".common.CarSettingActivity"
diff --git a/res/drawable/ic_language.xml b/res/drawable/ic_language.xml
new file mode 100644
index 0000000..43cdb7e
--- /dev/null
+++ b/res/drawable/ic_language.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/car_primary_icon_size"
+        android:height="@dimen/car_primary_icon_size"
+        android:viewportHeight="48.0"
+        android:viewportWidth="48.0">
+    <path
+        android:fillColor="@color/car_tint"
+        android:pathData="M23.99,4C12.94,4 4,12.95 4,24s8.94,20 19.99,20C35.04,44 44,35.05 44,24S35.04,4 23.99,4zM37.84,16h-5.9c-0.65,-2.5 -1.56,-4.9 -2.76,-7.12 3.68,1.26 6.74,3.81 8.66,7.12zM24,8.07c1.67,2.4 2.97,5.07 3.82,7.93h-7.64c0.85,-2.86 2.15,-5.53 3.82,-7.93zM8.52,28C8.19,26.72 8,25.38 8,24s0.19,-2.72 0.52,-4h6.75c-0.16,1.31 -0.27,2.64 -0.27,4 0,1.36 0.11,2.69 0.28,4L8.52,28zM10.15,32h5.9c0.65,2.5 1.56,4.9 2.76,7.13 -3.68,-1.26 -6.74,-3.82 -8.66,-7.13zM16.05,16h-5.9c1.92,-3.31 4.98,-5.87 8.66,-7.13 -1.2,2.23 -2.11,4.63 -2.76,7.13zM24,39.93c-1.66,-2.4 -2.96,-5.07 -3.82,-7.93h7.64c-0.86,2.86 -2.16,5.53 -3.82,7.93zM28.68,28h-9.36c-0.19,-1.31 -0.32,-2.64 -0.32,-4 0,-1.36 0.13,-2.69 0.32,-4h9.36c0.19,1.31 0.32,2.64 0.32,4 0,1.36 -0.13,2.69 -0.32,4zM29.19,39.12c1.2,-2.23 2.11,-4.62 2.76,-7.12h5.9c-1.93,3.31 -4.99,5.86 -8.66,7.12zM32.72,28c0.16,-1.31 0.28,-2.64 0.28,-4 0,-1.36 -0.11,-2.69 -0.28,-4h6.75c0.33,1.28 0.53,2.62 0.53,4s-0.19,2.72 -0.53,4h-6.75z"/>
+</vector>
diff --git a/res/layout/app_compat_activity.xml b/res/layout/app_compat_activity.xml
index 097937a..2ce17b8 100644
--- a/res/layout/app_compat_activity.xml
+++ b/res/layout/app_compat_activity.xml
@@ -33,6 +33,21 @@
         android:background="@color/car_list_divider"/>
     <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:id="@+id/fragment_container"/>
+        android:layout_height="match_parent">
+        <FrameLayout
+            android:id="@+id/fragment_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+        <!-- set the text clickable to true so that it blocks touch event -->
+        <TextView
+            android:id="@+id/restricted_message"
+            android:gravity="center"
+            android:background="@color/car_grey_1000"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:text="@string/restricted_while_driving"
+            android:clickable="true"
+            android:visibility="gone"
+            android:textAppearance="@style/TextAppearance.Car.Body1.Light" />
+    </FrameLayout>
 </LinearLayout>
diff --git a/res/values/floats.xml b/res/values/floats.xml
index 41b9a92..5db06cb 100644
--- a/res/values/floats.xml
+++ b/res/values/floats.xml
@@ -16,7 +16,7 @@
 
 
 <resources>
-  <!--opacity -->
+  <!-- opacity -->
   <item name="opacity_disabled" format="float" type="dimen">0.5</item>
   <item name="opacity_enabled" format="float" type="dimen">1</item>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 82a2b6b..e0a1a67 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -172,6 +172,9 @@
     <!-- Title for BT error dialogs. -->
     <string name="bluetooth_error_title"></string>
 
+    <!-- Language settings screen heading. [CHAR LIMIT=30] -->
+    <string name="language_settings">Languages</string>
+
     <!-- sound settings --><skip />
     <!-- Sound settings screen heading -->
     <string name="sound_settings">Sound</string>
diff --git a/src/com/android/car/settings/common/BaseFragment.java b/src/com/android/car/settings/common/BaseFragment.java
index 42158a2..bcb615d 100644
--- a/src/com/android/car/settings/common/BaseFragment.java
+++ b/src/com/android/car/settings/common/BaseFragment.java
@@ -63,9 +63,9 @@
         void goBack();
 
         /**
-         * Called when a Fragment expects itself to be blocked.
+         * Shows a message that current feature is not available when driving.
          */
-        void notifyCurrentFragmentRestricted();
+        void showDOBlockingMessage();
     }
 
     /**
@@ -120,13 +120,9 @@
     }
 
     /**
-     * Notifies the fragment with the latest CarUxRestrictions change. Default to quick setting
-     * page when canBeShown() return false, no-op otherwise.
+     * Notifies the fragment with the latest CarUxRestrictions change.
      */
     protected void onUxRestrictionChanged(@NonNull CarUxRestrictions carUxRestrictions) {
-        if (!canBeShown(getCurrentRestrictions())) {
-            getFragmentController().notifyCurrentFragmentRestricted();
-        }
     }
 
     @Override
@@ -164,12 +160,7 @@
     @Override
     public void onStart() {
         super.onStart();
-        CarUxRestrictions carUxRestrictions = getCurrentRestrictions();
-        if (!canBeShown(carUxRestrictions)) {
-            getFragmentController().notifyCurrentFragmentRestricted();
-        } else {
-            onUxRestrictionChanged(carUxRestrictions);
-        }
+        onUxRestrictionChanged(getCurrentRestrictions());
     }
 
     /**
@@ -184,6 +175,13 @@
         titleView.setText(title);
     }
 
+    /**
+     * Allow fragment to intercept back press and customize behavior.
+     */
+    protected void onBackPressed() {
+        getFragmentController().goBack();
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
@@ -201,7 +199,7 @@
         Toolbar toolbar = (Toolbar) actionBar.getCustomView().getParent();
         toolbar.setPadding(0, 0, 0, 0);
         getActivity().findViewById(R.id.action_bar_icon_container).setOnClickListener(
-                v -> getFragmentController().goBack());
+                v -> onBackPressed());
         TextView titleView = getActivity().findViewById(R.id.title);
         titleView.setText(mTitleId);
     }
diff --git a/src/com/android/car/settings/common/CarSettingActivity.java b/src/com/android/car/settings/common/CarSettingActivity.java
index c96e799..3f3e3f8 100644
--- a/src/com/android/car/settings/common/CarSettingActivity.java
+++ b/src/com/android/car/settings/common/CarSettingActivity.java
@@ -15,13 +15,17 @@
  */
 package com.android.car.settings.common;
 
+import android.annotation.Nullable;
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
+import android.view.View;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.Toast;
 
 import com.android.car.settings.R;
 import com.android.car.settings.common.BaseFragment.UXRestrictionsProvider;
@@ -32,8 +36,9 @@
  * previous activity.
  */
 public class CarSettingActivity extends AppCompatActivity implements
-        BaseFragment.FragmentController, UXRestrictionsProvider {
+        BaseFragment.FragmentController, UXRestrictionsProvider, OnBackStackChangedListener{
     private CarUxRestrictionsHelper mUxRestrictionsHelper;
+    private View mRestrictedMessage;
     // Default to minimum restriction.
     private CarUxRestrictions mCarUxRestrictions = new CarUxRestrictions.Builder(
             /* reqOpt= */ true,
@@ -54,17 +59,31 @@
                         BaseFragment currentFragment = getCurrentFragment();
                         if (currentFragment != null) {
                             currentFragment.onUxRestrictionChanged(carUxRestrictions);
+                            updateBlockingView(currentFragment);
                         }
                     });
         }
-
         mUxRestrictionsHelper.start();
+        getSupportFragmentManager().addOnBackStackChangedListener(this);
+        mRestrictedMessage = findViewById(R.id.restricted_message);
+    }
+
+    @Override
+    public void onBackStackChanged() {
+        updateBlockingView(getCurrentFragment());
+    }
+
+    private void updateBlockingView(@Nullable BaseFragment currentFragment) {
+        if (currentFragment == null) {
+            return;
+        }
+        boolean canBeShown = currentFragment.canBeShown(mCarUxRestrictions);
+        mRestrictedMessage.setVisibility(canBeShown ? View.GONE : View.VISIBLE);
     }
 
     @Override
     public void onStart() {
         super.onStart();
-
         if (getCurrentFragment() == null) {
             launchFragment(QuickSettingFragment.newInstance());
         }
@@ -76,12 +95,6 @@
     }
 
     @Override
-    public void notifyCurrentFragmentRestricted() {
-        DOBlockingDialogFragment alertDialog = new DOBlockingDialogFragment();
-        alertDialog.show(getSupportFragmentManager(), DOBlockingDialogFragment.DIALOG_TAG);
-    }
-
-    @Override
     public void onDestroy() {
         super.onDestroy();
         mUxRestrictionsHelper.stop();
@@ -113,6 +126,12 @@
     }
 
     @Override
+    public void showDOBlockingMessage() {
+        Toast.makeText(
+                this, R.string.restricted_while_driving, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
     public void onBackPressed() {
         super.onBackPressed();
         hideKeyboard();
diff --git a/src/com/android/car/settings/home/HomepageFragment.java b/src/com/android/car/settings/home/HomepageFragment.java
index 4550a9a..d7d286b 100644
--- a/src/com/android/car/settings/home/HomepageFragment.java
+++ b/src/com/android/car/settings/home/HomepageFragment.java
@@ -92,7 +92,10 @@
     private final IntentFilter mBtStateChangeFilter =
             new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
 
-    public static HomepageFragment getInstance() {
+    /**
+     * Gets an instance of this class.
+     */
+    public static HomepageFragment newInstance() {
         HomepageFragment homepageFragment = new HomepageFragment();
         Bundle bundle = ListSettingsFragment.getBundle();
         bundle.putInt(EXTRA_TITLE_ID, R.string.settings_label);
diff --git a/src/com/android/car/settings/quicksettings/QuickSettingFragment.java b/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
index bfd67ac..9e177c6 100644
--- a/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
+++ b/src/com/android/car/settings/quicksettings/QuickSettingFragment.java
@@ -20,6 +20,7 @@
 import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -36,15 +37,15 @@
  * Shows a page to access frequently used settings.
  */
 public class QuickSettingFragment extends BaseFragment {
-    private static final float RESTRICTED_ALPHA = 0.5f;
-    private static final float UNRESTRICTED_ALPHA = 1f;
-
     private CarUserManagerHelper  mCarUserManagerHelper;
     private UserIconProvider mUserIconProvider;
     private QuickSettingGridAdapter mGridAdapter;
     private PagedListView mListView;
     private View mFullSettingBtn;
     private View mUserSwitcherBtn;
+    private HomeFragmentLauncher mHomeFragmentLauncher;
+    private float mOpacityDisabled;
+    private float mOpacityEnabled;
 
     /**
      * Returns an instance of this class.
@@ -62,9 +63,12 @@
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+        mHomeFragmentLauncher = new HomeFragmentLauncher();
         getActivity().findViewById(R.id.action_bar_icon_container).setOnClickListener(
                 v -> getActivity().finish());
 
+        mOpacityDisabled = getContext().getResources().getFloat(R.dimen.opacity_disabled);
+        mOpacityEnabled = getContext().getResources().getFloat(R.dimen.opacity_enabled);
         mCarUserManagerHelper = new CarUserManagerHelper(getContext());
         mUserIconProvider = new UserIconProvider(mCarUserManagerHelper);
         mListView = (PagedListView) getActivity().findViewById(R.id.list);
@@ -72,15 +76,12 @@
         mListView.getRecyclerView().setLayoutManager(mGridAdapter.getGridLayoutManager());
 
         mFullSettingBtn = getActivity().findViewById(R.id.full_setting_btn);
-        mFullSettingBtn.setOnClickListener(v -> {
-            getFragmentController().launchFragment(HomepageFragment.getInstance());
-        });
+        mFullSettingBtn.setOnClickListener(mHomeFragmentLauncher);
         mUserSwitcherBtn = getActivity().findViewById(R.id.user_switcher_btn);
         mUserSwitcherBtn.setOnClickListener(v -> {
             getFragmentController().launchFragment(UserSwitcherFragment.newInstance());
         });
 
-        setupAccountButton();
         View exitBtn = getActivity().findViewById(R.id.exit_button);
         exitBtn.setOnClickListener(v -> getFragmentController().goBack());
 
@@ -124,6 +125,24 @@
     }
 
     private void applyRestriction(boolean restricted) {
-        mFullSettingBtn.setAlpha(restricted ? RESTRICTED_ALPHA : UNRESTRICTED_ALPHA);
+        mHomeFragmentLauncher.showDOBlockingMessage(restricted);
+        mFullSettingBtn.setAlpha(restricted ? mOpacityDisabled : mOpacityEnabled);
+    }
+
+    private class HomeFragmentLauncher implements OnClickListener {
+        private boolean mShowDOBlockingMessage;
+
+        private void showDOBlockingMessage(boolean show) {
+            mShowDOBlockingMessage = show;
+        }
+
+        @Override
+        public void onClick(View v) {
+            if (mShowDOBlockingMessage) {
+                getFragmentController().showDOBlockingMessage();
+            } else {
+                getFragmentController().launchFragment(HomepageFragment.newInstance());
+            }
+        }
     }
 }
diff --git a/src/com/android/car/settings/sound/SoundSettingsFragment.java b/src/com/android/car/settings/sound/SoundSettingsFragment.java
index 298e8a6..b1bf654 100644
--- a/src/com/android/car/settings/sound/SoundSettingsFragment.java
+++ b/src/com/android/car/settings/sound/SoundSettingsFragment.java
@@ -98,7 +98,7 @@
 
     private final ICarVolumeCallback mVolumeChangeCallback = new ICarVolumeCallback.Stub() {
         @Override
-        public void onGroupVolumeChanged(int groupId) {
+        public void onGroupVolumeChanged(int groupId, int flags) {
             for (ListItem lineItem : mVolumeLineItems) {
                 VolumeLineItem volumeLineItem = (VolumeLineItem) lineItem;
                 if (volumeLineItem.getVolumeGroupId() == groupId) {
@@ -109,7 +109,7 @@
         }
 
         @Override
-        public void onMasterMuteChanged() {
+        public void onMasterMuteChanged(int flags) {
             // ignored
         }
     };
diff --git a/src/com/android/car/settings/system/LanguagePickerFragment.java b/src/com/android/car/settings/system/LanguagePickerFragment.java
new file mode 100644
index 0000000..2465a18
--- /dev/null
+++ b/src/com/android/car/settings/system/LanguagePickerFragment.java
@@ -0,0 +1,195 @@
+/*
+ * 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.car.settings.system;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.MutableLiveData;
+import android.arch.lifecycle.ViewModel;
+import android.arch.lifecycle.ViewModelProviders;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+
+import androidx.car.widget.ListItemProvider;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.ListItemSettingsFragment;
+import com.android.car.settingslib.language.LanguagePickerUtils;
+import com.android.car.settingslib.language.LocaleListItemProvider;
+import com.android.car.settingslib.language.LocaleSelectionListener;
+import com.android.internal.app.LocalePicker;
+import com.android.internal.app.LocaleStore;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * Fragment for showing the list of languages.
+ */
+public class LanguagePickerFragment extends ListItemSettingsFragment implements
+        LocaleSelectionListener {
+
+    private LocaleListItemProvider mLocaleListItemProvider;
+    private final HashSet<String> mLangTagsToIgnore = new HashSet<>();
+
+    /**
+     * Factory method for creating LanguagePickerFragment.
+     */
+    public static LanguagePickerFragment newInstance() {
+        LanguagePickerFragment LanguagePickerFragment = new LanguagePickerFragment();
+        Bundle bundle = ListItemSettingsFragment.getBundle();
+        bundle.putInt(EXTRA_TITLE_ID, R.string.language_settings);
+        bundle.putInt(EXTRA_ACTION_BAR_LAYOUT, R.layout.action_bar);
+        LanguagePickerFragment.setArguments(bundle);
+        return LanguagePickerFragment;
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        LocaleViewModel viewModel = getLocaleViewModel();
+        viewModel.getLocaleInfos(getContext(), mLangTagsToIgnore).observe(this,
+                localeInfos -> resetLocaleList(localeInfos));
+    }
+
+    @Override
+    public ListItemProvider getItemProvider() {
+        if (mLocaleListItemProvider == null) {
+            mLocaleListItemProvider = new LocaleListItemProvider(
+                    getContext(),
+                    new HashSet<LocaleStore.LocaleInfo>(),
+                    /* localeSelectionListener= */ this,
+                    mLangTagsToIgnore);
+        }
+        return mLocaleListItemProvider;
+    }
+
+    @Override
+    public void onLocaleSelected(LocaleStore.LocaleInfo localeInfo) {
+        if (localeInfo == null || localeInfo.getLocale() == null) {
+            return;
+        }
+
+        Locale locale = localeInfo.getLocale();
+
+        Resources res = getResources();
+        Configuration baseConfig = res.getConfiguration();
+        Configuration config = new Configuration(baseConfig);
+        config.setLocale(locale);
+        res.updateConfiguration(config, null);
+
+        // Apply locale to system.
+        LocalePicker.updateLocale(locale);
+        getFragmentController().goBack();
+    }
+
+    @Override
+    public void onParentWithChildrenLocaleSelected(LocaleStore.LocaleInfo localeInfo) {
+        if (localeInfo != null) {
+            setTitle(localeInfo.getFullNameNative());
+            refreshList();
+        }
+    }
+
+    @Override
+    protected void onBackPressed() {
+        if (isChildLocaleDisplayed()) {
+            setTitle(getString(R.string.language_settings));
+            getLocaleViewModel().reloadLocales(getContext(), mLangTagsToIgnore);
+        } else {
+            super.onBackPressed();
+        }
+    }
+
+    private LocaleViewModel getLocaleViewModel() {
+        return ViewModelProviders.of(this).get(LocaleViewModel.class);
+    }
+
+    private boolean isChildLocaleDisplayed() {
+        return mLocaleListItemProvider != null && mLocaleListItemProvider.isChildLocale();
+    }
+
+    /**
+     * Add a pseudo locale in debug build for testing RTL.
+     *
+     * @param localeInfos the set of {@link LocaleStore.LocaleInfo} to which the locale is added.
+     */
+    private void maybeAddPseudoLocale(Set<LocaleStore.LocaleInfo> localeInfos) {
+        if (Build.IS_USERDEBUG) {
+            // The ar-XB pseudo-locale is RTL.
+            localeInfos.add(LocaleStore.getLocaleInfo(new Locale("ar", "XB")));
+        }
+    }
+
+    private void resetLocaleList(Set<LocaleStore.LocaleInfo> localeInfos) {
+        if (mLocaleListItemProvider != null) {
+            maybeAddPseudoLocale(localeInfos);
+            mLocaleListItemProvider.updateSuggestedLocaleAdapter(
+                    LanguagePickerUtils.createSuggestedLocaleAdapter(
+                            getContext(), localeInfos, /* parent= */ null),
+                    /* isChildLocale= */ false);
+            refreshList();
+        }
+    }
+
+    /**
+     * ViewModel for holding the LocaleInfos.
+     */
+    public static class LocaleViewModel extends ViewModel {
+
+        private MutableLiveData<Set<LocaleStore.LocaleInfo>> mLocaleInfos;
+
+        /**
+         * Returns LiveData holding a set of LocaleInfo.
+         */
+        public LiveData<Set<LocaleStore.LocaleInfo>> getLocaleInfos(Context context,
+                Set<String> ignorables) {
+
+            if (mLocaleInfos == null) {
+                mLocaleInfos = new MutableLiveData<Set<LocaleStore.LocaleInfo>>();
+                reloadLocales(context, ignorables);
+            }
+            return mLocaleInfos;
+        }
+
+        /**
+         * Reload the locales based on the current context.
+         */
+        public void reloadLocales(Context context, Set<String> ignorables) {
+            new AsyncTask<Context, Void, Set<LocaleStore.LocaleInfo>>() {
+                @Override
+                protected Set<LocaleStore.LocaleInfo> doInBackground(Context... contexts) {
+                    return LocaleStore.getLevelLocales(
+                            contexts[0],
+                            ignorables,
+                            /* parent= */ null,
+                            /* translatedOnly= */ true);
+                }
+
+                @Override
+                protected void onPostExecute(Set<LocaleStore.LocaleInfo> localeInfos) {
+                    LocaleViewModel.this.mLocaleInfos.setValue(localeInfos);
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, context);
+        }
+    }
+}
diff --git a/src/com/android/car/settings/system/SystemSettingsFragment.java b/src/com/android/car/settings/system/SystemSettingsFragment.java
index 7b9dcb4..4f39e32 100644
--- a/src/com/android/car/settings/system/SystemSettingsFragment.java
+++ b/src/com/android/car/settings/system/SystemSettingsFragment.java
@@ -17,6 +17,7 @@
 
 package com.android.car.settings.system;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Build;
@@ -29,9 +30,12 @@
 import com.android.car.settings.R;
 import com.android.car.settings.common.ExtraSettingsLoader;
 import com.android.car.settings.common.ListItemSettingsFragment;
+import com.android.car.settingslib.language.LanguagePickerUtils;
+import com.android.internal.app.LocaleHelper;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -71,37 +75,71 @@
 
     private ArrayList<ListItem> getListItems() {
         ArrayList<ListItem> lineItems = new ArrayList<>();
-        Intent settingsIntent = new Intent(ACTION_SYSTEM_UPDATE_SETTINGS);
-        PackageManager packageManager = getContext().getPackageManager();
-        if (settingsIntent.resolveActivity(packageManager) != null) {
-            lineItems.add(new SystemUpdatesListItem(getContext(), settingsIntent));
-        }
-        ExtraSettingsLoader extraSettingLoader = new ExtraSettingsLoader(getContext());
-        Map<String, Collection<ListItem>> extraSettings = extraSettingLoader.load();
-        lineItems.addAll(extraSettings.get(ExtraSettingsLoader.SYSTEM_CATEGORY));
 
-        TextListItem aboutSystemItem = new TextListItem(getContext());
-        aboutSystemItem.setTitle(getContext().getString(R.string.about_settings));
+        lineItems.add(createLanguageListItem());
+        lineItems.addAll(createSystemUpdateListItems());
+        lineItems.add(createAboutSystemListItem());
+        lineItems.add(createLegalInfoListItem());
+
+        return lineItems;
+    }
+
+    private TextListItem createLanguageListItem() {
+        Context context = getContext();
+        TextListItem languageItem = new TextListItem(context);
+        languageItem.setTitle(context.getString(R.string.language_settings));
+        Locale locale = LanguagePickerUtils.getConfiguredLocale();
+        languageItem.setBody(LocaleHelper.getDisplayName(locale, locale, /* sentenceCase= */ true));
+        languageItem.setPrimaryActionIcon(
+                R.drawable.ic_language, /* useLargeIcon= */ false);
+        languageItem.setSupplementalIcon(R.drawable.ic_chevron_right, /* showDivider= */ false);
+        languageItem.setOnClickListener(
+                v -> getFragmentController().launchFragment(LanguagePickerFragment.newInstance()));
+        return languageItem;
+    }
+
+    private Collection<ListItem> createSystemUpdateListItems() {
+        Collection<ListItem> collection = new ArrayList<>();
+        Context context = getContext();
+
+        Intent settingsIntent = new Intent(ACTION_SYSTEM_UPDATE_SETTINGS);
+        PackageManager packageManager = context.getPackageManager();
+        if (settingsIntent.resolveActivity(packageManager) != null) {
+            collection.add(new SystemUpdatesListItem(context, settingsIntent));
+        }
+
+        ExtraSettingsLoader extraSettingLoader = new ExtraSettingsLoader(context);
+        Map<String, Collection<ListItem>> extraSettings = extraSettingLoader.load();
+        collection.addAll(extraSettings.get(ExtraSettingsLoader.SYSTEM_CATEGORY));
+        return collection;
+    }
+
+    private TextListItem createAboutSystemListItem() {
+        Context context = getContext();
+        TextListItem aboutSystemItem = new TextListItem(context);
+        aboutSystemItem.setTitle(context.getString(R.string.about_settings));
         aboutSystemItem.setBody(
-                getContext().getString(R.string.about_summary, Build.VERSION.RELEASE));
+                context.getString(R.string.about_summary, Build.VERSION.RELEASE));
         aboutSystemItem.setPrimaryActionIcon(
                 R.drawable.ic_settings_about, /* useLargeIcon= */ false);
         aboutSystemItem.setSupplementalIcon(R.drawable.ic_chevron_right, /* showDivider= */ false);
         aboutSystemItem.setOnClickListener(
                 v -> getFragmentController().launchFragment(AboutSettingsFragment.getInstance()));
-        lineItems.add(aboutSystemItem);
+        return aboutSystemItem;
+    }
 
-        TextListItem legalInfoItem = new TextListItem(getContext());
-        legalInfoItem.setTitle(getContext().getString(R.string.legal_information));
+    private TextListItem createLegalInfoListItem() {
+        Context context = getContext();
+        TextListItem legalInfoItem = new TextListItem(context);
+        legalInfoItem.setTitle(context.getString(R.string.legal_information));
         legalInfoItem.setPrimaryActionIcon(
                 R.drawable.ic_settings_about, /* useLargeIcon= */ false);
         legalInfoItem.setSupplementalIcon(R.drawable.ic_chevron_right, /* showDivider= */ false);
         legalInfoItem.setOnClickListener(v -> {
             Intent intent = new Intent();
             intent.setAction(ACTION_SETTING_VIEW_LICENSE);
-            getContext().startActivity(intent);
+            context.startActivity(intent);
         });
-        lineItems.add(legalInfoItem);
-        return lineItems;
+        return legalInfoItem;
     }
 }
diff --git a/src/com/android/car/settings/users/UserGridRecyclerView.java b/src/com/android/car/settings/users/UserGridRecyclerView.java
index 56c9c4e..b6d73fa 100644
--- a/src/com/android/car/settings/users/UserGridRecyclerView.java
+++ b/src/com/android/car/settings/users/UserGridRecyclerView.java
@@ -36,7 +36,6 @@
 
 import com.android.car.settings.R;
 import com.android.car.settings.common.BaseFragment;
-import com.android.car.settings.common.DOBlockingDialogFragment;
 import com.android.car.settings.users.ConfirmCreateNewUserDialog.CancelCreateNewUserListener;
 import com.android.car.settings.users.ConfirmCreateNewUserDialog.ConfirmCreateNewUserListener;
 import com.android.internal.util.UserIcons;
@@ -55,13 +54,13 @@
     private Context mContext;
     private BaseFragment mBaseFragment;
     public AddNewUserTask mAddNewUserTask;
-    public boolean mShowAddUserButton;
+    public boolean mEnableAddUserButton;
 
     public UserGridRecyclerView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
         mCarUserManagerHelper = new CarUserManagerHelper(mContext);
-        mShowAddUserButton = true;
+        mEnableAddUserButton = true;
     }
 
     /**
@@ -125,16 +124,16 @@
     /**
      * Show the "Add User" Button
      */
-    public void showAddUser() {
-        mShowAddUserButton = true;
+    public void enableAddUser() {
+        mEnableAddUserButton = true;
         onUsersUpdate();
     }
 
     /**
      * Hide the "Add User" Button
      */
-    public void hideAddUser() {
-        mShowAddUserButton = false;
+    public void disableAddUser() {
+        mEnableAddUserButton = false;
         onUsersUpdate();
     }
 
@@ -165,7 +164,7 @@
     @Override
     public void onUsersUpdate() {
         // If you can show the add user button, there is no restriction
-        mAdapter.setAddUserRestricted(mShowAddUserButton ? false : true);
+        mAdapter.setAddUserRestricted(mEnableAddUserButton ? false : true);
         mAdapter.clearUsers();
         mAdapter.updateUsers(createUserRecords(mCarUserManagerHelper
                 .getAllUsers()));
@@ -261,8 +260,7 @@
                 // If the user wants to add a user, show dialog to confirm adding a user
                 if (userRecord.mIsAddUser) {
                     if (mIsAddUserRestricted) {
-                        // Show a DO dialog as "Add User" is not available
-                        callDOBlockingDialog();
+                        mBaseFragment.getFragmentController().showDOBlockingMessage();
                     } else {
                         // Disable button so it cannot be clicked multiple times
                         mAddUserView = holder.mView;
@@ -285,17 +283,6 @@
         }
 
         /**
-         * Display a DO dialog
-         */
-        public void callDOBlockingDialog() {
-            DOBlockingDialogFragment DODialog = DOBlockingDialogFragment.newInstance(mContext
-                    .getString(R.string.add_user_restricted_while_driving));
-            DODialog.goBackToQuickSettingsMainScreen(false);
-            DODialog.show(mBaseFragment.getFragmentManager(),
-                    DOBlockingDialogFragment.DIALOG_TAG);
-        }
-
-        /**
          * Specify if adding a user should be restricted.
          *
          * @param isAddUserRestricted should adding a user be restricted
diff --git a/src/com/android/car/settings/users/UserSwitcherFragment.java b/src/com/android/car/settings/users/UserSwitcherFragment.java
index e73a8e7..bb84f71 100644
--- a/src/com/android/car/settings/users/UserSwitcherFragment.java
+++ b/src/com/android/car/settings/users/UserSwitcherFragment.java
@@ -79,9 +79,9 @@
     private void applyRestriction(boolean restricted) {
         if (mUserGridView != null) {
             if (restricted) {
-                mUserGridView.hideAddUser();
+                mUserGridView.disableAddUser();
             } else {
-                mUserGridView.showAddUser();
+                mUserGridView.enableAddUser();
             }
         }
     }
diff --git a/tests/robotests/src/com/android/car/settings/security/ConfirmLockPinPasswordFragmentTest.java b/tests/robotests/src/com/android/car/settings/security/ConfirmLockPinPasswordFragmentTest.java
index 293641d..05ba09f 100644
--- a/tests/robotests/src/com/android/car/settings/security/ConfirmLockPinPasswordFragmentTest.java
+++ b/tests/robotests/src/com/android/car/settings/security/ConfirmLockPinPasswordFragmentTest.java
@@ -75,5 +75,8 @@
 
         @Override
         public void goBack() {}
+
+        @Override
+        public void showDOBlockingMessage() {}
     }
 }
diff --git a/tests/robotests/src/com/android/car/settings/testutils/BaseTestActivity.java b/tests/robotests/src/com/android/car/settings/testutils/BaseTestActivity.java
index d3347af..5f5eb15 100644
--- a/tests/robotests/src/com/android/car/settings/testutils/BaseTestActivity.java
+++ b/tests/robotests/src/com/android/car/settings/testutils/BaseTestActivity.java
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public void notifyCurrentFragmentRestricted() {
+    public void showDOBlockingMessage() {
         // no-op
     }