From 687adfd8fbaaabd352e7b7c6c7c1fa1d89285ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CAnkita?= Date: Sat, 2 Oct 2021 14:12:09 +0000 Subject: [PATCH] Send broadcasts on app-locale change. Send below broadcasts: 1) explicit intent ACTION_LOCALE_CHANGED to app whose locale changed 2) explicit intent ACTION_APPPLICATION_LOCALE_CHANGED to installer of app 3) implicit ACTION_APPPLICATION_LOCALE_CHANGED to receivers with READ_APP_SPECIFIC_LOCALES permission Bug: 202275007 Test: Manual; install app via adb, set the installer, grant permission to some system app(eg. Settings). See that broadcast is received by all three receivers on app locale change. Change-Id: Ifef25aaf3c1fde0fdf0befc4eb67cfd07186e46c --- .../server/locales/LocaleManagerService.java | 73 ++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java index 0045499ec8aae..f51714225a296 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerService.java +++ b/services/core/java/com/android/server/locales/LocaleManagerService.java @@ -18,11 +18,14 @@ package com.android.server.locales; import static java.util.Objects.requireNonNull; +import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.ILocaleManager; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.LocaleList; @@ -142,7 +145,6 @@ public class LocaleManagerService extends SystemService { } } - private void setApplicationLocalesUnchecked(@NonNull String appPackageName, @UserIdInt int userId, @NonNull LocaleList locales) { if (DEBUG) { @@ -152,9 +154,76 @@ public class LocaleManagerService extends SystemService { final ActivityTaskManagerInternal.PackageConfigurationUpdater updater = mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName, userId); - updater.setLocales(locales).commit(); + boolean isSuccess = updater.setLocales(locales).commit(); + + //We want to send the broadcasts only if config was actually updated on commit. + if (isSuccess) { + notifyAppWhoseLocaleChanged(appPackageName, userId, locales); + notifyInstallerOfAppWhoseLocaleChanged(appPackageName, userId, locales); + notifyRegisteredReceivers(appPackageName, userId, locales); + } } + /** + * Sends an implicit broadcast with action + * {@link android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED} + * to receivers with {@link android.Manifest.permission#READ_APP_SPECIFIC_LOCALES}. + */ + private void notifyRegisteredReceivers(String appPackageName, int userId, + LocaleList locales) { + Intent intent = createBaseIntent(Intent.ACTION_APPLICATION_LOCALE_CHANGED, + appPackageName, locales); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId), + Manifest.permission.READ_APP_SPECIFIC_LOCALES); + } + + /** + * Sends an explicit broadcast with action + * {@link android.content.Intent#ACTION_APPLICATION_LOCALE_CHANGED} to + * the installer (as per {@link android.content.pm.InstallSourceInfo#getInstallingPackageName}) + * of app whose locale has changed. + * + *

Note: This is can be used by installers to deal with cases such as + * language-based APK Splits. + */ + private void notifyInstallerOfAppWhoseLocaleChanged(String appPackageName, int userId, + LocaleList locales) { + try { + String installingPackageName = mContext.getPackageManager() + .getInstallSourceInfo(appPackageName).getInstallingPackageName(); + if (installingPackageName != null) { + Intent intent = createBaseIntent(Intent.ACTION_APPLICATION_LOCALE_CHANGED, + appPackageName, locales); + //Set package name to ensure that only installer of the app receives this intent. + intent.setPackage(installingPackageName); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); + } + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Package not found " + appPackageName); + } + } + + /** + * Sends an explicit broadcast with action {@link android.content.Intent#ACTION_LOCALE_CHANGED} + * to the app whose locale has changed. + */ + private void notifyAppWhoseLocaleChanged(String appPackageName, int userId, + LocaleList locales) { + Intent intent = createBaseIntent(Intent.ACTION_LOCALE_CHANGED, appPackageName, locales); + //Set package name to ensure that only the app whose locale changed receives this intent. + intent.setPackage(appPackageName); + intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); + } + + private static Intent createBaseIntent(String intentAction, String appPackageName, + LocaleList locales) { + return new Intent(intentAction) + .putExtra(Intent.EXTRA_PACKAGE_NAME, appPackageName) + .putExtra(Intent.EXTRA_LOCALE_LIST, locales) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_RECEIVER_FOREGROUND); + } /** * Checks if the package is owned by the calling app or not for the given user id.