diff --git a/core/api/current.txt b/core/api/current.txt index 9514447582e9f..7370af382b142 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -5631,6 +5631,11 @@ package android.app { method @Deprecated public android.view.Window startActivity(String, android.content.Intent); } + public class LocaleManager { + method @NonNull public android.os.LocaleList getApplicationLocales(); + method public void setApplicationLocales(@NonNull android.os.LocaleList); + } + public class MediaRouteActionProvider extends android.view.ActionProvider { ctor public MediaRouteActionProvider(android.content.Context); method public android.view.View onCreateActionView(); @@ -10753,6 +10758,7 @@ package android.content { field public static final String KEYGUARD_SERVICE = "keyguard"; field public static final String LAUNCHER_APPS_SERVICE = "launcherapps"; field @UiContext public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater"; + field public static final String LOCALE_SERVICE = "locale"; field public static final String LOCATION_SERVICE = "location"; field public static final String MEDIA_COMMUNICATION_SERVICE = "media_communication"; field public static final String MEDIA_METRICS_SERVICE = "media_metrics"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 258adcf8cd953..27b2b2084f9c0 100755 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -745,6 +745,11 @@ package android.app { field public static final int PIN = 1; // 0x1 } + public class LocaleManager { + method @NonNull @RequiresPermission(android.Manifest.permission.READ_APP_SPECIFIC_LOCALES) public android.os.LocaleList getApplicationLocales(@NonNull String); + method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void setApplicationLocales(@NonNull String, @NonNull android.os.LocaleList); + } + public class Notification implements android.os.Parcelable { field public static final String CATEGORY_CAR_EMERGENCY = "car_emergency"; field public static final String CATEGORY_CAR_INFORMATION = "car_information"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 3267473b805b4..da9fd3ebca641 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -281,6 +281,11 @@ package android.app { method @RequiresPermission(anyOf={android.Manifest.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS, "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"}) public boolean setLock(int, @Nullable byte[], int, @Nullable byte[]); } + public class LocaleManager { + method @Nullable public android.os.LocaleList getSystemLocales(); + method public void setSystemLocales(@NonNull android.os.LocaleList); + } + public class Notification implements android.os.Parcelable { method public boolean shouldShowForegroundImmediately(); } diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java new file mode 100644 index 0000000000000..2aa7c8e60236a --- /dev/null +++ b/core/java/android/app/LocaleManager.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2021 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 android.app; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.annotation.TestApi; +import android.annotation.UserHandleAware; +import android.content.Context; +import android.content.res.Configuration; +import android.os.LocaleList; +import android.os.RemoteException; + +/** + * This class gives access to system locale services. These services allow applications to control + * granular locale settings (such as per-app locales). + * + *

Third party applications should treat this as a write-side surface, and continue reading + * locales via their in-process {@link LocaleList}s. + */ +@SystemService(Context.LOCALE_SERVICE) +public class LocaleManager { + private static final String TAG = "LocaleManager"; + + /** Context required for getting the user for which API calls are made. */ + private Context mContext; + private ILocaleManager mService; + + /** @hide Instantiated by ContextImpl */ + public LocaleManager(Context context, ILocaleManager service) { + mContext = context; + mService = service; + } + + /** + * Sets the UI locales for the calling app. + * + *

Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. + * + * @param locales the desired locales for the calling app. + */ + @UserHandleAware + public void setApplicationLocales(@NonNull LocaleList locales) { + setApplicationLocales(mContext.getPackageName(), locales); + } + + /** + * Sets the UI locales for a specified app (described by package name). + * + *

Pass a {@link LocaleList#getEmptyLocaleList()} to reset to the system locale. + * + * @param appPackageName the package name of the app for which to set the locales. + * @param locales the desired locales for the specified app. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.CHANGE_CONFIGURATION) + @UserHandleAware + public void setApplicationLocales(@NonNull String appPackageName, @NonNull LocaleList locales) { + try { + mService.setApplicationLocales(appPackageName, mContext.getUser().getIdentifier(), + locales); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the UI locales for the calling app. + * + *

Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. + */ + @UserHandleAware + @NonNull + public LocaleList getApplicationLocales() { + return getApplicationLocales(mContext.getPackageName()); + } + + /** + * Returns the current UI locales for a specific app (described by package name). + * + *

Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set. + * + * Note: Non-system apps should read Locale information via their in-process + * LocaleLists. + * + * @param appPackageName the package name of the app for which to retrieve the locales. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_APP_SPECIFIC_LOCALES) + @UserHandleAware + @NonNull + public LocaleList getApplicationLocales(@NonNull String appPackageName) { + try { + return mService.getApplicationLocales(appPackageName, mContext.getUser() + .getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the current system locales to the provided value. + * + * @hide + */ + @TestApi + public void setSystemLocales(@NonNull LocaleList locales) { + try { + Configuration conf = ActivityManager.getService().getConfiguration(); + conf.setLocales(locales); + ActivityManager.getService().updatePersistentConfiguration(conf); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current system locales for the device. + * + * @hide + */ + @TestApi + @Nullable + public LocaleList getSystemLocales() { + try { + return ActivityManager.getService().getConfiguration().getLocales(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + +} diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 4da51c13045b2..1909f3c03da4d 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -40,6 +40,9 @@ per-file *Alarm* = file:/apex/jobscheduler/OWNERS # AppOps per-file *AppOp* = file:/core/java/android/permission/OWNERS +# LocaleManager +per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS + # Multiuser per-file *User* = file:/MULTIUSER_OWNERS diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 6ba185f486c38..fc40179890b66 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1393,6 +1393,14 @@ public final class SystemServiceRegistry { throws ServiceNotFoundException { return new SystemLightsManager(ctx); }}); + registerService(Context.LOCALE_SERVICE, LocaleManager.class, + new CachedServiceFetcher() { + @Override + public LocaleManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + return new LocaleManager(ctx, ILocaleManager.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.LOCALE_SERVICE))); + }}); registerService(Context.INCREMENTAL_SERVICE, IncrementalManager.class, new CachedServiceFetcher() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index fc94fb248189c..665f626030bbc 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5825,7 +5825,6 @@ public abstract class Context { * {@link android.app.LocaleManager}. * * @see #getSystemService(String) - * @hide */ public static final String LOCALE_SERVICE = "locale";