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.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.SystemService; 25 import android.annotation.TestApi; 26 import android.annotation.UserHandleAware; 27 import android.content.Context; 28 import android.content.res.Configuration; 29 import android.os.LocaleList; 30 import android.os.RemoteException; 31 32 /** 33 * This class gives access to system locale services. These services allow applications to 34 * control granular locale settings (such as per-app locales) or override their list of supported 35 * locales while running. 36 * 37 * <p> Third party applications should treat this as a write-side surface, and continue reading 38 * locales via their in-process {@link LocaleList}s. 39 */ 40 @SystemService(Context.LOCALE_SERVICE) 41 public class LocaleManager { 42 private static final String TAG = "LocaleManager"; 43 44 /** Context required for getting the user for which API calls are made. */ 45 private Context mContext; 46 private ILocaleManager mService; 47 48 /** @hide Instantiated by ContextImpl */ LocaleManager(Context context, ILocaleManager service)49 public LocaleManager(Context context, ILocaleManager service) { 50 mContext = context; 51 mService = service; 52 } 53 54 /** 55 * Sets the UI locales for the calling app. 56 * 57 * <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. 58 * 59 * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially 60 * an Activity lifecycle event) being applied to the calling application. For more information, 61 * see the <a 62 * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on 63 * handling configuration changes</a>. The set locales are persisted; they are backed up if the 64 * user has enabled Backup & Restore. 65 * 66 * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of 67 * any app-specific locales and system locales, with the app-specific locales appearing first. 68 * Language resources are then chosen per usual (as described in the <a 69 * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on 70 * locale resolution</a>). 71 * 72 * @param locales the desired locales for the calling app. 73 */ 74 @UserHandleAware setApplicationLocales(@onNull LocaleList locales)75 public void setApplicationLocales(@NonNull LocaleList locales) { 76 setApplicationLocales(mContext.getPackageName(), locales, false); 77 } 78 79 /** 80 * Sets the UI locales for a specified app (described by package name). 81 * 82 * <p>Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. 83 * 84 * <p><b>Note:</b> Changes to app locales will result in a configuration change (and potentially 85 * an Activity lifecycle event) being applied to the specified application. For more 86 * information, see the <a 87 * href="https://developer.android.com/guide/topics/resources/runtime-changes">section on 88 * handling configuration changes</a>. The set locales are persisted; they are backed up if the 89 * user has enabled Backup & Restore. 90 * 91 * <p><b>Note:</b> Users' locale preferences are passed to applications by creating a union of 92 * any app-specific locales and system locales, with the app-specific locales appearing first. 93 * Language resources are then chosen per usual (as described in the <a 94 * href="https://developer.android.com/guide/topics/resources/multilingual-support">section on 95 * locale resolution</a>). 96 * 97 * @param appPackageName the package name of the app for which to set the locales. 98 * @param locales the desired locales for the specified app. 99 * @hide 100 */ 101 @SystemApi 102 @RequiresPermission(Manifest.permission.CHANGE_CONFIGURATION) 103 @UserHandleAware setApplicationLocales(@onNull String appPackageName, @NonNull LocaleList locales)104 public void setApplicationLocales(@NonNull String appPackageName, @NonNull LocaleList locales) { 105 setApplicationLocales(appPackageName, locales, true); 106 } 107 setApplicationLocales(@onNull String appPackageName, @NonNull LocaleList locales, boolean fromDelegate)108 private void setApplicationLocales(@NonNull String appPackageName, @NonNull LocaleList locales, 109 boolean fromDelegate) { 110 try { 111 mService.setApplicationLocales(appPackageName, mContext.getUserId(), locales, 112 fromDelegate); 113 } catch (RemoteException e) { 114 throw e.rethrowFromSystemServer(); 115 } 116 } 117 118 /** 119 * Returns the UI locales for the calling app. 120 * 121 * <p>Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. 122 */ 123 @UserHandleAware 124 @NonNull getApplicationLocales()125 public LocaleList getApplicationLocales() { 126 return getApplicationLocales(mContext.getPackageName()); 127 } 128 129 /** 130 * Returns the current UI locales for a specified app (described by package name). 131 * 132 * <p>Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. 133 * 134 * <p>This API can be used by an app's installer 135 * (per {@link android.content.pm.InstallSourceInfo#getInstallingPackageName}) to retrieve 136 * the app's locales. 137 * <p>This API can be used by the current input method to retrieve locales of another packages. 138 * All other cases require {@code android.Manifest.permission#READ_APP_SPECIFIC_LOCALES}. 139 * Apps should generally retrieve their own locales via their in-process LocaleLists, 140 * or by calling {@link #getApplicationLocales()}. 141 * 142 * @param appPackageName the package name of the app for which to retrieve the locales. 143 */ 144 @RequiresPermission(value = Manifest.permission.READ_APP_SPECIFIC_LOCALES, conditional = true) 145 @UserHandleAware 146 @NonNull getApplicationLocales(@onNull String appPackageName)147 public LocaleList getApplicationLocales(@NonNull String appPackageName) { 148 try { 149 return mService.getApplicationLocales(appPackageName, mContext.getUserId()); 150 } catch (RemoteException e) { 151 throw e.rethrowFromSystemServer(); 152 } 153 } 154 155 /** 156 * Returns the current system locales, ignoring app-specific overrides. 157 * 158 * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in 159 * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this 160 * method helps cater to rare use-cases which might require specifically knowing the system 161 * locale. 162 * 163 * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground 164 * user. 165 */ 166 @NonNull getSystemLocales()167 public LocaleList getSystemLocales() { 168 try { 169 return mService.getSystemLocales(); 170 } catch (RemoteException e) { 171 throw e.rethrowFromSystemServer(); 172 } 173 } 174 175 /** 176 * Sets the current system locales to the provided value. 177 * 178 * @hide 179 */ 180 @TestApi setSystemLocales(@onNull LocaleList locales)181 public void setSystemLocales(@NonNull LocaleList locales) { 182 try { 183 Configuration conf = new Configuration(); 184 conf.setLocales(locales); 185 ActivityManager.getService().updatePersistentConfiguration(conf); 186 } catch (RemoteException e) { 187 throw e.rethrowFromSystemServer(); 188 } 189 } 190 191 /** 192 * Sets the override LocaleConfig for the calling app. 193 * 194 * <p><b>Note:</b> Only the app itself with the same user can override its own LocaleConfig. 195 * 196 * <p><b>Note:</b> This function takes in a {@link LocaleConfig} which is intended to 197 * override the original config in the application's resources. This LocaleConfig will 198 * become the override config, and stored in a system file for future access. 199 * 200 * <p><b>Note:</b> Using this function, applications can update their list of supported 201 * locales while running, without an update of the application's software. For more 202 * information, see the <a 203 * href="https://developer.android.com/about/versions/14/features#app-languages">section on 204 * dynamic updates for an app's localeConfig</a>. 205 * 206 * <p>Applications can remove the override LocaleConfig with a {@code null} object. 207 * 208 * @param localeConfig the desired {@link LocaleConfig} for the calling app. 209 */ 210 @UserHandleAware setOverrideLocaleConfig(@ullable LocaleConfig localeConfig)211 public void setOverrideLocaleConfig(@Nullable LocaleConfig localeConfig) { 212 try { 213 // The permission android.Manifest.permission#SET_APP_SPECIFIC_LOCALECONFIG is 214 // required to set an override LocaleConfig of another packages 215 mService.setOverrideLocaleConfig(mContext.getPackageName(), mContext.getUserId(), 216 localeConfig); 217 } catch (RemoteException e) { 218 throw e.rethrowFromSystemServer(); 219 } 220 } 221 222 /** 223 * Returns the override LocaleConfig for the calling app. 224 * 225 * @return the override LocaleConfig, or {@code null} if the LocaleConfig isn't overridden. 226 */ 227 @Nullable 228 @UserHandleAware getOverrideLocaleConfig()229 public LocaleConfig getOverrideLocaleConfig() { 230 try { 231 return mService.getOverrideLocaleConfig(mContext.getPackageName(), 232 mContext.getUserId()); 233 } catch (RemoteException e) { 234 throw e.rethrowFromSystemServer(); 235 } 236 } 237 238 } 239