1 /* 2 * Copyright (C) 2021 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 17 package android.app; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.annotation.SystemService; 24 import android.annotation.TestApi; 25 import android.annotation.UserHandleAware; 26 import android.content.Context; 27 import android.content.res.Configuration; 28 import android.os.LocaleList; 29 import android.os.RemoteException; 30 31 /** 32 * This class gives access to system locale services. These services allow applications to control 33 * granular locale settings (such as per-app locales). 34 * 35 * <p> Third party applications should treat this as a write-side surface, and continue reading 36 * locales via their in-process {@link LocaleList}s. 37 */ 38 @SystemService(Context.LOCALE_SERVICE) 39 public class LocaleManager { 40 private static final String TAG = "LocaleManager"; 41 42 /** Context required for getting the user for which API calls are made. */ 43 private Context mContext; 44 private ILocaleManager mService; 45 46 /** @hide Instantiated by ContextImpl */ LocaleManager(Context context, ILocaleManager service)47 public LocaleManager(Context context, ILocaleManager service) { 48 mContext = context; 49 mService = service; 50 } 51 52 /** 53 * Sets the UI locales for the calling app. 54 * 55 * <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. 56 * 57 * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially 58 * an Activity lifecycle event) being applied to the calling application. For more information, 59 * see the <a 60 * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on 61 * handling configuration changes</a>. The set locales are persisted; they are backed up if the 62 * user has enabled Backup & Restore. 63 * 64 * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of 65 * any app-specific locales and system locales, with the app-specific locales appearing first. 66 * Language resources are then chosen per usual (as described in the <a 67 * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on 68 * locale resolution</a>). 69 * 70 * @param locales the desired locales for the calling app. 71 */ 72 @UserHandleAware setApplicationLocales(@onNull LocaleList locales)73 public void setApplicationLocales(@NonNull LocaleList locales) { 74 setApplicationLocales(mContext.getPackageName(), locales); 75 } 76 77 /** 78 * Sets the UI locales for a specified app (described by package name). 79 * 80 * <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. 81 * 82 * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially 83 * an Activity lifecycle event) being applied to the specified application. For more 84 * information, see the <a 85 * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on 86 * handling configuration changes</a>. The set locales are persisted; they are backed up if the 87 * user has enabled Backup & Restore. 88 * 89 * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of 90 * any app-specific locales and system locales, with the app-specific locales appearing first. 91 * Language resources are then chosen per usual (as described in the <a 92 * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on 93 * locale resolution</a>). 94 * 95 * @param appPackageName the package name of the app for which to set the locales. 96 * @param locales the desired locales for the specified app. 97 * @hide 98 */ 99 @SystemApi 100 @RequiresPermission(Manifest.permission.CHANGE_CONFIGURATION) 101 @UserHandleAware setApplicationLocales(@onNull String appPackageName, @NonNull LocaleList locales)102 public void setApplicationLocales(@NonNull String appPackageName, @NonNull LocaleList locales) { 103 try { 104 mService.setApplicationLocales(appPackageName, mContext.getUser().getIdentifier(), 105 locales); 106 } catch (RemoteException e) { 107 throw e.rethrowFromSystemServer(); 108 } 109 } 110 111 /** 112 * Returns the UI locales for the calling app. 113 * 114 * <p>Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. 115 */ 116 @UserHandleAware 117 @NonNull getApplicationLocales()118 public LocaleList getApplicationLocales() { 119 return getApplicationLocales(mContext.getPackageName()); 120 } 121 122 /** 123 * Returns the current UI locales for a specified app (described by package name). 124 * 125 * <p>Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. 126 * 127 * <p>This API can be used by an app's installer 128 * (per {@link android.content.pm.InstallSourceInfo#getInstallingPackageName}) to retrieve 129 * the app's locales. 130 * All other cases require {@code android.Manifest.permission#READ_APP_SPECIFIC_LOCALES}. 131 * Apps should generally retrieve their own locales via their in-process LocaleLists, 132 * or by calling {@link #getApplicationLocales()}. 133 * 134 * @param appPackageName the package name of the app for which to retrieve the locales. 135 */ 136 @RequiresPermission(value = Manifest.permission.READ_APP_SPECIFIC_LOCALES, conditional = true) 137 @UserHandleAware 138 @NonNull getApplicationLocales(@onNull String appPackageName)139 public LocaleList getApplicationLocales(@NonNull String appPackageName) { 140 try { 141 return mService.getApplicationLocales(appPackageName, mContext.getUser() 142 .getIdentifier()); 143 } catch (RemoteException e) { 144 throw e.rethrowFromSystemServer(); 145 } 146 } 147 148 /** 149 * Returns the current system locales, ignoring app-specific overrides. 150 * 151 * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in 152 * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this 153 * method helps cater to rare use-cases which might require specifically knowing the system 154 * locale. 155 * 156 * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground 157 * user. 158 */ 159 @NonNull getSystemLocales()160 public LocaleList getSystemLocales() { 161 try { 162 return mService.getSystemLocales(); 163 } catch (RemoteException e) { 164 throw e.rethrowFromSystemServer(); 165 } 166 } 167 168 /** 169 * Sets the current system locales to the provided value. 170 * 171 * @hide 172 */ 173 @TestApi setSystemLocales(@onNull LocaleList locales)174 public void setSystemLocales(@NonNull LocaleList locales) { 175 try { 176 Configuration conf = new Configuration(); 177 conf.setLocales(locales); 178 ActivityManager.getService().updatePersistentConfiguration(conf); 179 } catch (RemoteException e) { 180 throw e.rethrowFromSystemServer(); 181 } 182 } 183 184 } 185