blob: 274acad2b1e4ecd72f4b25bb5b3c1a9975ce8c9b [file] [log] [blame]
-b master501eec92009-07-06 13:53:11 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.settings;
18
Maggieaa080f92018-01-04 15:35:11 -080019import android.os.Process;
Seigo Nonaka0f19cc72017-06-26 16:06:17 -070020import com.android.internal.app.LocalePicker;
21import com.android.internal.annotations.VisibleForTesting;
22
23import android.annotation.NonNull;
Sudheer Shankadc589ac2016-11-10 15:30:17 -080024import android.app.ActivityManager;
Amith Yamasani8823c0a82009-07-07 14:30:17 -070025import android.app.IActivityManager;
Christopher Tate45281862010-03-05 15:46:30 -080026import android.app.backup.IBackupManager;
Christopher Tate6597e342015-02-17 12:15:25 -080027import android.content.ContentResolver;
28import android.content.ContentValues;
-b master501eec92009-07-06 13:53:11 -070029import android.content.Context;
Christopher Tate6597e342015-02-17 12:15:25 -080030import android.content.Intent;
Amith Yamasani8823c0a82009-07-07 14:30:17 -070031import android.content.res.Configuration;
Seigo Nonaka0f19cc72017-06-26 16:06:17 -070032import android.icu.util.ULocale;
Amith Yamasani70c874b2009-07-06 14:53:25 -070033import android.location.LocationManager;
-b master501eec92009-07-06 13:53:11 -070034import android.media.AudioManager;
Amith Yamasani622bf2222013-09-06 13:54:28 -070035import android.media.RingtoneManager;
36import android.net.Uri;
Seigo Nonaka0f19cc72017-06-26 16:06:17 -070037import android.os.LocaleList;
-b master501eec92009-07-06 13:53:11 -070038import android.os.RemoteException;
39import android.os.ServiceManager;
Christopher Tate6597e342015-02-17 12:15:25 -080040import android.os.UserHandle;
Maggie Benthall67944582013-02-22 14:58:27 -050041import android.os.UserManager;
-b master501eec92009-07-06 13:53:11 -070042import android.provider.Settings;
Marvin Paul8fc50722014-12-23 11:46:33 -080043import android.telephony.TelephonyManager;
Amith Yamasani8823c0a82009-07-07 14:30:17 -070044import android.text.TextUtils;
Christopher Tate6597e342015-02-17 12:15:25 -080045import android.util.ArraySet;
-b master501eec92009-07-06 13:53:11 -070046
chenedward70b75b42018-05-10 15:58:44 +080047import java.lang.IllegalArgumentException;
Seigo Nonaka0f19cc72017-06-26 16:06:17 -070048import java.util.ArrayList;
49import java.util.HashMap;
Maggie Benthall67944582013-02-22 14:58:27 -050050import java.util.Locale;
51
-b master501eec92009-07-06 13:53:11 -070052public class SettingsHelper {
Christopher Tate45d17582017-06-26 17:35:26 -070053 private static final String TAG = "SettingsHelper";
Amith Yamasani622bf2222013-09-06 13:54:28 -070054 private static final String SILENT_RINGTONE = "_silent";
Annie Meng95264452018-04-19 17:32:17 +010055 private static final float FLOAT_TOLERANCE = 0.01f;
56
-b master501eec92009-07-06 13:53:11 -070057 private Context mContext;
58 private AudioManager mAudioManager;
Marvin Paul8fc50722014-12-23 11:46:33 -080059 private TelephonyManager mTelephonyManager;
Amith Yamasani70c874b2009-07-06 14:53:25 -070060
Christopher Tate6597e342015-02-17 12:15:25 -080061 /**
62 * A few settings elements are special in that a restore of those values needs to
63 * be post-processed by relevant parts of the OS. A restore of any settings element
64 * mentioned in this table will therefore cause the system to send a broadcast with
65 * the {@link Intent#ACTION_SETTING_RESTORED} action, with extras naming the
66 * affected setting and supplying its pre-restore value for comparison.
67 *
68 * @see Intent#ACTION_SETTING_RESTORED
69 * @see System#SETTINGS_TO_BACKUP
70 * @see Secure#SETTINGS_TO_BACKUP
71 * @see Global#SETTINGS_TO_BACKUP
72 *
73 * {@hide}
74 */
75 private static final ArraySet<String> sBroadcastOnRestore;
76 static {
Yohei Yukawaca780952018-02-07 22:16:32 +090077 sBroadcastOnRestore = new ArraySet<String>(4);
Christopher Tate6597e342015-02-17 12:15:25 -080078 sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
Ruben Brunke24b9a62016-02-16 21:38:24 -080079 sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
Christopher Tate2d4aadc2015-03-16 16:55:14 -070080 sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
Stanley Tng767f05f2017-05-01 21:27:31 -070081 sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
Christopher Tate6597e342015-02-17 12:15:25 -080082 }
83
84 private interface SettingsLookup {
85 public String lookup(ContentResolver resolver, String name, int userHandle);
86 }
87
88 private static SettingsLookup sSystemLookup = new SettingsLookup() {
89 public String lookup(ContentResolver resolver, String name, int userHandle) {
90 return Settings.System.getStringForUser(resolver, name, userHandle);
91 }
92 };
93
94 private static SettingsLookup sSecureLookup = new SettingsLookup() {
95 public String lookup(ContentResolver resolver, String name, int userHandle) {
96 return Settings.Secure.getStringForUser(resolver, name, userHandle);
97 }
98 };
99
100 private static SettingsLookup sGlobalLookup = new SettingsLookup() {
101 public String lookup(ContentResolver resolver, String name, int userHandle) {
102 return Settings.Global.getStringForUser(resolver, name, userHandle);
103 }
104 };
105
-b master501eec92009-07-06 13:53:11 -0700106 public SettingsHelper(Context context) {
107 mContext = context;
108 mAudioManager = (AudioManager) context
109 .getSystemService(Context.AUDIO_SERVICE);
Marvin Paul8fc50722014-12-23 11:46:33 -0800110 mTelephonyManager = (TelephonyManager) context
111 .getSystemService(Context.TELEPHONY_SERVICE);
-b master501eec92009-07-06 13:53:11 -0700112 }
113
Amith Yamasani70c874b2009-07-06 14:53:25 -0700114 /**
115 * Sets the property via a call to the appropriate API, if any, and returns
116 * whether or not the setting should be saved to the database as well.
117 * @param name the name of the setting
118 * @param value the string value of the setting
119 * @return whether to continue with writing the value to the database. In
120 * some cases the data will be written by the call to the appropriate API,
121 * and in some cases the property value needs to be modified before setting.
122 */
Christopher Tate6597e342015-02-17 12:15:25 -0800123 public void restoreValue(Context context, ContentResolver cr, ContentValues contentValues,
Michal Karpinski6135a262017-08-11 10:45:58 +0100124 Uri destination, String name, String value, int restoredFromSdkInt) {
Christopher Tate6597e342015-02-17 12:15:25 -0800125 // Will we need a post-restore broadcast for this element?
126 String oldValue = null;
127 boolean sendBroadcast = false;
128 final SettingsLookup table;
129
130 if (destination.equals(Settings.Secure.CONTENT_URI)) {
131 table = sSecureLookup;
132 } else if (destination.equals(Settings.System.CONTENT_URI)) {
133 table = sSystemLookup;
134 } else { /* must be GLOBAL; this was preflighted by the caller */
135 table = sGlobalLookup;
Amith Yamasani70c874b2009-07-06 14:53:25 -0700136 }
Christopher Tate6597e342015-02-17 12:15:25 -0800137
138 if (sBroadcastOnRestore.contains(name)) {
Xiaohui Chen43765b72015-08-31 10:57:33 -0700139 // TODO: http://b/22388012
140 oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM);
Christopher Tate6597e342015-02-17 12:15:25 -0800141 sendBroadcast = true;
142 }
143
144 try {
Annie Meng931b41b2018-04-05 18:49:52 +0100145 if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800146 setSoundEffects(Integer.parseInt(value) == 1);
147 // fall through to the ordinary write to settings
148 } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
149 setGpsLocation(value);
150 return;
151 } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) {
152 setAutoRestore(Integer.parseInt(value) == 1);
153 } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
154 return;
155 } else if (Settings.System.RINGTONE.equals(name)
chenedwardc47329b2018-05-03 12:13:45 +0800156 || Settings.System.NOTIFICATION_SOUND.equals(name)
157 || Settings.System.ALARM_ALERT.equals(name)) {
Christopher Tate6597e342015-02-17 12:15:25 -0800158 setRingtone(name, value);
159 return;
160 }
161
162 // Default case: write the restored value to settings
163 contentValues.clear();
164 contentValues.put(Settings.NameValueTable.NAME, name);
165 contentValues.put(Settings.NameValueTable.VALUE, value);
166 cr.insert(destination, contentValues);
167 } catch (Exception e) {
168 // If we fail to apply the setting, by definition nothing happened
169 sendBroadcast = false;
170 } finally {
171 // If this was an element of interest, send the "we just restored it"
172 // broadcast with the historical value now that the new value has
173 // been committed and observers kicked off.
174 if (sendBroadcast) {
175 Intent intent = new Intent(Intent.ACTION_SETTING_RESTORED)
176 .setPackage("android").addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
177 .putExtra(Intent.EXTRA_SETTING_NAME, name)
178 .putExtra(Intent.EXTRA_SETTING_NEW_VALUE, value)
Michal Karpinski6135a262017-08-11 10:45:58 +0100179 .putExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE, oldValue)
180 .putExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, restoredFromSdkInt);
Xiaohui Chene4de5a02015-09-22 15:33:31 -0700181 context.sendBroadcastAsUser(intent, UserHandle.SYSTEM, null);
Christopher Tate6597e342015-02-17 12:15:25 -0800182 }
183 }
Amith Yamasani70c874b2009-07-06 14:53:25 -0700184 }
185
Amith Yamasani622bf2222013-09-06 13:54:28 -0700186 public String onBackupValue(String name, String value) {
Marvin Paul8fc50722014-12-23 11:46:33 -0800187 // Special processing for backing up ringtones & notification sounds
Amith Yamasani622bf2222013-09-06 13:54:28 -0700188 if (Settings.System.RINGTONE.equals(name)
chenedwardc47329b2018-05-03 12:13:45 +0800189 || Settings.System.NOTIFICATION_SOUND.equals(name)
190 || Settings.System.ALARM_ALERT.equals(name)) {
Amith Yamasani622bf2222013-09-06 13:54:28 -0700191 if (value == null) {
Marvin Paul8fc50722014-12-23 11:46:33 -0800192 if (Settings.System.RINGTONE.equals(name)) {
193 // For ringtones, we need to distinguish between non-telephony vs telephony
194 if (mTelephonyManager != null && mTelephonyManager.isVoiceCapable()) {
195 // Backup a null ringtone as silent on voice-capable devices
196 return SILENT_RINGTONE;
197 } else {
198 // Skip backup of ringtone on non-telephony devices.
199 return null;
200 }
201 } else {
chenedwardc47329b2018-05-03 12:13:45 +0800202 // Backup a null notification sound or alarm alert as silent
Marvin Paul8fc50722014-12-23 11:46:33 -0800203 return SILENT_RINGTONE;
204 }
Amith Yamasani622bf2222013-09-06 13:54:28 -0700205 } else {
206 return getCanonicalRingtoneValue(value);
207 }
208 }
209 // Return the original value
210 return value;
211 }
212
213 /**
214 * Sets the ringtone of type specified by the name.
215 *
chenedwardc47329b2018-05-03 12:13:45 +0800216 * @param name should be Settings.System.RINGTONE, Settings.System.NOTIFICATION_SOUND
217 * or Settings.System.ALARM_ALERT.
Amith Yamasani622bf2222013-09-06 13:54:28 -0700218 * @param value can be a canonicalized uri or "_silent" to indicate a silent (null) ringtone.
219 */
220 private void setRingtone(String name, String value) {
221 // If it's null, don't change the default
222 if (value == null) return;
chenedwardc47329b2018-05-03 12:13:45 +0800223 final Uri ringtoneUri;
Amith Yamasani622bf2222013-09-06 13:54:28 -0700224 if (SILENT_RINGTONE.equals(value)) {
225 ringtoneUri = null;
226 } else {
227 Uri canonicalUri = Uri.parse(value);
228 ringtoneUri = mContext.getContentResolver().uncanonicalize(canonicalUri);
Amith Yamasani2e804442013-09-11 11:11:19 -0700229 if (ringtoneUri == null) {
230 // Unrecognized or invalid Uri, don't restore
231 return;
232 }
Amith Yamasani622bf2222013-09-06 13:54:28 -0700233 }
chenedwardc47329b2018-05-03 12:13:45 +0800234 final int ringtoneType = getRingtoneType(name);
235
Amith Yamasani622bf2222013-09-06 13:54:28 -0700236 RingtoneManager.setActualDefaultRingtoneUri(mContext, ringtoneType, ringtoneUri);
237 }
238
chenedwardc47329b2018-05-03 12:13:45 +0800239 private int getRingtoneType(String name) {
240 switch (name) {
241 case Settings.System.RINGTONE:
242 return RingtoneManager.TYPE_RINGTONE;
243 case Settings.System.NOTIFICATION_SOUND:
244 return RingtoneManager.TYPE_NOTIFICATION;
245 case Settings.System.ALARM_ALERT:
246 return RingtoneManager.TYPE_ALARM;
247 default:
chenedward70b75b42018-05-10 15:58:44 +0800248 throw new IllegalArgumentException("Incorrect ringtone name: " + name);
chenedwardc47329b2018-05-03 12:13:45 +0800249 }
250 }
251
Amith Yamasani622bf2222013-09-06 13:54:28 -0700252 private String getCanonicalRingtoneValue(String value) {
253 final Uri ringtoneUri = Uri.parse(value);
254 final Uri canonicalUri = mContext.getContentResolver().canonicalize(ringtoneUri);
255 return canonicalUri == null ? null : canonicalUri.toString();
256 }
257
Svetoslav Ganov818d2042012-09-12 21:35:15 -0700258 private boolean isAlreadyConfiguredCriticalAccessibilitySetting(String name) {
Anna Galuszafa7786c2015-12-22 10:53:44 -0800259 // These are the critical accessibility settings that are required for users with
260 // accessibility needs to be able to interact with the device. If these settings are
Svetoslav Ganov818d2042012-09-12 21:35:15 -0700261 // already configured, we will not overwrite them. If they are already set,
Anna Galuszafa7786c2015-12-22 10:53:44 -0800262 // it means that the user has performed a global gesture to enable accessibility or set
263 // these settings in the Accessibility portion of the Setup Wizard, and definitely needs
264 // these features working after the restore.
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800265 switch (name) {
266 case Settings.Secure.ACCESSIBILITY_ENABLED:
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800267 case Settings.Secure.TOUCH_EXPLORATION_ENABLED:
268 case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
269 case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
Annie Meng425c8682018-05-03 16:24:03 +0100270 case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED:
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800271 return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
272 case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES:
273 case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES:
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800274 case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800275 return !TextUtils.isEmpty(Settings.Secure.getString(
276 mContext.getContentResolver(), name));
Annie Meng95264452018-04-19 17:32:17 +0100277 case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE:
278 float defaultScale = mContext.getResources().getFraction(
279 R.fraction.def_accessibility_display_magnification_scale, 1, 1);
280 float currentScale = Settings.Secure.getFloat(
281 mContext.getContentResolver(), name, defaultScale);
282 return Math.abs(currentScale - defaultScale) >= FLOAT_TOLERANCE;
Casey Burkhardt86b867f2015-12-29 18:03:36 -0800283 case Settings.System.FONT_SCALE:
284 return Settings.System.getFloat(mContext.getContentResolver(), name, 1.0f) != 1.0f;
285 default:
286 return false;
Svetoslav Ganov818d2042012-09-12 21:35:15 -0700287 }
Svetoslav Ganov818d2042012-09-12 21:35:15 -0700288 }
289
Christopher Tate03b6d902010-02-26 14:12:03 -0800290 private void setAutoRestore(boolean enabled) {
291 try {
292 IBackupManager bm = IBackupManager.Stub.asInterface(
293 ServiceManager.getService(Context.BACKUP_SERVICE));
294 if (bm != null) {
295 bm.setAutoRestore(enabled);
296 }
297 } catch (RemoteException e) {}
298 }
299
Amith Yamasani70c874b2009-07-06 14:53:25 -0700300 private void setGpsLocation(String value) {
Maggie Benthall67944582013-02-22 14:58:27 -0500301 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Maggie Benthalla12fccf2013-03-14 18:02:12 -0400302 if (um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
Maggie Benthall67944582013-02-22 14:58:27 -0500303 return;
304 }
Amith Yamasani70c874b2009-07-06 14:53:25 -0700305 final String GPS = LocationManager.GPS_PROVIDER;
Maggie Benthalla12fccf2013-03-14 18:02:12 -0400306 boolean enabled =
Maggieaa080f92018-01-04 15:35:11 -0800307 GPS.equals(value) ||
Amith Yamasani70c874b2009-07-06 14:53:25 -0700308 value.startsWith(GPS + ",") ||
309 value.endsWith("," + GPS) ||
310 value.contains("," + GPS + ",");
Maggieaa080f92018-01-04 15:35:11 -0800311 LocationManager lm = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
312 lm.setProviderEnabledForUser(GPS, enabled, Process.myUserHandle());
Amith Yamasani70c874b2009-07-06 14:53:25 -0700313 }
314
315 private void setSoundEffects(boolean enable) {
316 if (enable) {
317 mAudioManager.loadSoundEffects();
318 } else {
319 mAudioManager.unloadSoundEffects();
-b master501eec92009-07-06 13:53:11 -0700320 }
321 }
322
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700323 /* package */ byte[] getLocaleData() {
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700324 Configuration conf = mContext.getResources().getConfiguration();
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700325 return conf.getLocales().toLanguageTags().getBytes();
326 }
327
328 private static Locale toFullLocale(@NonNull Locale locale) {
329 if (locale.getScript().isEmpty() || locale.getCountry().isEmpty()) {
330 return ULocale.addLikelySubtags(ULocale.forLocale(locale)).toLocale();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700331 }
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700332 return locale;
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700333 }
334
335 /**
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700336 * Merging the locale came from backup server and current device locale.
337 *
338 * Merge works with following rules.
339 * - The backup locales are appended to the current locale with keeping order.
340 * e.g. current locale "en-US,zh-CN" and backup locale "ja-JP,ko-KR" are merged to
341 * "en-US,zh-CH,ja-JP,ko-KR".
342 *
343 * - Duplicated locales are dropped.
344 * e.g. current locale "en-US,zh-CN" and backup locale "ja-JP,zh-Hans-CN,en-US" are merged to
345 * "en-US,zh-CN,ja-JP".
346 *
347 * - Unsupported locales are dropped.
348 * e.g. current locale "en-US" and backup locale "ja-JP,zh-CN" but the supported locales
349 * are "en-US,zh-CN", the merged locale list is "en-US,zh-CN".
350 *
351 * - The final result locale list only contains the supported locales.
352 * e.g. current locale "en-US" and backup locale "zh-Hans-CN" and supported locales are
353 * "en-US,zh-CN", the merged locale list is "en-US,zh-CN".
354 *
355 * @param restore The locale list that came from backup server.
356 * @param current The device's locale setting.
357 * @param supportedLocales The list of language tags supported by this device.
358 */
359 @VisibleForTesting
360 public static LocaleList resolveLocales(LocaleList restore, LocaleList current,
361 String[] supportedLocales) {
362 final HashMap<Locale, Locale> allLocales = new HashMap<>(supportedLocales.length);
363 for (String supportedLocaleStr : supportedLocales) {
364 final Locale locale = Locale.forLanguageTag(supportedLocaleStr);
365 allLocales.put(toFullLocale(locale), locale);
366 }
367
368 final ArrayList<Locale> filtered = new ArrayList<>(current.size());
369 for (int i = 0; i < current.size(); i++) {
370 final Locale locale = current.get(i);
371 allLocales.remove(toFullLocale(locale));
372 filtered.add(locale);
373 }
374
375 for (int i = 0; i < restore.size(); i++) {
376 final Locale locale = allLocales.remove(toFullLocale(restore.get(i)));
377 if (locale != null) {
378 filtered.add(locale);
379 }
380 }
381
382 if (filtered.size() == current.size()) {
383 return current; // Nothing added to current locale list.
384 }
385
386 return new LocaleList(filtered.toArray(new Locale[filtered.size()]));
387 }
388
389 /**
390 * Sets the locale specified. Input data is the byte representation of comma separated
391 * multiple BCP-47 language tags. For backwards compatibility, strings of the form
Narayan Kamath11bfc222014-07-30 15:42:25 +0100392 * {@code ll_CC} are also accepted, where {@code ll} is a two letter language
393 * code and {@code CC} is a two letter country code.
394 *
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700395 * @param data the comma separated BCP-47 language tags in bytes.
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700396 */
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700397 /* package */ void setLocaleData(byte[] data, int size) {
398 final Configuration conf = mContext.getResources().getConfiguration();
399
400 // Replace "_" with "-" to deal with older backups.
401 final String localeCodes = new String(data, 0, size).replace('_', '-');
402 final LocaleList localeList = LocaleList.forLanguageTags(localeCodes);
403 if (localeList.isEmpty()) {
Christopher Tate45d17582017-06-26 17:35:26 -0700404 return;
405 }
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700406
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700407 final String[] supportedLocales = LocalePicker.getSupportedLocales(mContext);
408 final LocaleList currentLocales = conf.getLocales();
409
410 final LocaleList merged = resolveLocales(localeList, currentLocales, supportedLocales);
411 if (merged.equals(currentLocales)) {
412 return;
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700413 }
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700414
415 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800416 IActivityManager am = ActivityManager.getService();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700417 Configuration config = am.getConfiguration();
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700418 config.setLocales(merged);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700419 // indicate this isn't some passing default - the user wants this remembered
420 config.userSetLocale = true;
421
Seigo Nonaka0f19cc72017-06-26 16:06:17 -0700422 am.updatePersistentConfiguration(config);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700423 } catch (RemoteException e) {
424 // Intentionally left blank
425 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700426 }
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700427
Amith Yamasanid1582142009-07-08 20:04:55 -0700428 /**
429 * Informs the audio service of changes to the settings so that
430 * they can be re-read and applied.
431 */
432 void applyAudioSettings() {
433 AudioManager am = new AudioManager(mContext);
434 am.reloadAudioSettings();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700435 }
-b master501eec92009-07-06 13:53:11 -0700436}