Loading core/java/android/content/pm/IPackageManager.aidl +29 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,35 @@ interface IPackageManager { void setHomeActivity(in ComponentName className, int userId); /** * Overrides the label and icon of the component specified by the component name. The component * must belong to the calling app. * * These changes will be reset on the next boot and whenever the package is updated. * * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed * to call this. * * @param componentName The component name to override the label/icon of. * @param nonLocalizedLabel The label to be displayed. * @param icon The icon to be displayed. * @param userId The user id. */ void overrideLabelAndIcon(in ComponentName componentName, String nonLocalizedLabel, int icon, int userId); /** * Restores the label and icon of the activity specified by the component name if either has * been overridden. The component must belong to the calling app. * * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed * to call this. * * @param componentName The component name. * @param userId The user id. */ void restoreLabelAndIcon(in ComponentName componentName, int userId); /** * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}. */ Loading core/java/android/content/pm/PackageUserState.java +71 −0 Original line number Diff line number Diff line Loading @@ -27,18 +27,24 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.pm.parsing.component.ParsedMainComponent; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -84,6 +90,9 @@ public class PackageUserState { private ArrayMap<String, String[]> sharedLibraryOverlayPaths; // Lib name to overlay paths private String[] cachedOverlayPaths; @Nullable private ArrayMap<ComponentName, Pair<String, Integer>> componentLabelIconOverrideMap; @UnsupportedAppUsage public PackageUserState() { installed = true; Loading Loading @@ -123,6 +132,9 @@ public class PackageUserState { sharedLibraryOverlayPaths = new ArrayMap<>(o.sharedLibraryOverlayPaths); } harmfulAppWarning = o.harmfulAppWarning; if (o.componentLabelIconOverrideMap != null) { this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap); } } public String[] getOverlayPaths() { Loading @@ -146,6 +158,65 @@ public class PackageUserState { cachedOverlayPaths = null; } /** * Overrides the non-localized label and icon of a component. * * @return true if the label or icon was changed. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean overrideLabelAndIcon(@NonNull ComponentName component, @Nullable String nonLocalizedLabel, @Nullable Integer icon) { String existingLabel = null; Integer existingIcon = null; if (componentLabelIconOverrideMap != null) { Pair<String, Integer> pair = componentLabelIconOverrideMap.get(component); if (pair != null) { existingLabel = pair.first; existingIcon = pair.second; } } boolean changed = !TextUtils.equals(existingLabel, nonLocalizedLabel) || !Objects.equals(existingIcon, icon); if (changed) { if (nonLocalizedLabel == null && icon == null) { componentLabelIconOverrideMap.remove(component); if (componentLabelIconOverrideMap.isEmpty()) { componentLabelIconOverrideMap = null; } } else { if (componentLabelIconOverrideMap == null) { componentLabelIconOverrideMap = new ArrayMap<>(1); } componentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon)); } } return changed; } /** * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName, * String, Integer)}. * * This is done when the package is updated as the components and resource IDs may have changed. */ public void resetOverrideComponentLabelIcon() { componentLabelIconOverrideMap = null; } @Nullable public Pair<String, Integer> getOverrideLabelIconForComponent(ComponentName componentName) { if (ArrayUtils.isEmpty(componentLabelIconOverrideMap)) { return null; } return componentLabelIconOverrideMap.get(componentName); } /** * Test if this package is installed. */ Loading core/res/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1910,6 +1910,9 @@ <!-- The name of the package that will hold the system gallery role. --> <string name="config_systemGallery" translatable="false">com.android.gallery</string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false"></string> <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> <bool name="config_bluetooth_default_profiles">true</bool> Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3961,4 +3961,6 @@ <!-- Set to true to make assistant show in front of the dream/screensaver. --> <java-symbol type="bool" name="config_assistantOnTopOfDream"/> <java-symbol type="string" name="config_overrideComponentUiPackage" /> </resources> services/core/java/com/android/server/pm/ComponentResolver.java +29 −4 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; import com.android.server.pm.parsing.PackageInfoUtils; Loading Loading @@ -207,33 +208,57 @@ public class ComponentResolver { } /** Returns the given activity */ ParsedActivity getActivity(ComponentName component) { @Nullable @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public ParsedActivity getActivity(@NonNull ComponentName component) { synchronized (mLock) { return mActivities.mActivities.get(component); } } /** Returns the given provider */ ParsedProvider getProvider(ComponentName component) { @Nullable ParsedProvider getProvider(@NonNull ComponentName component) { synchronized (mLock) { return mProviders.mProviders.get(component); } } /** Returns the given receiver */ ParsedActivity getReceiver(ComponentName component) { @Nullable ParsedActivity getReceiver(@NonNull ComponentName component) { synchronized (mLock) { return mReceivers.mActivities.get(component); } } /** Returns the given service */ ParsedService getService(ComponentName component) { @Nullable ParsedService getService(@NonNull ComponentName component) { synchronized (mLock) { return mServices.mServices.get(component); } } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean componentExists(@NonNull ComponentName componentName) { synchronized (mLock) { ParsedMainComponent component = mActivities.mActivities.get(componentName); if (component != null) { return true; } component = mReceivers.mActivities.get(componentName); if (component != null) { return true; } component = mServices.mServices.get(componentName); if (component != null) { return true; } return mProviders.mProviders.get(componentName) != null; } } @Nullable List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int userId) { Loading Loading
core/java/android/content/pm/IPackageManager.aidl +29 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,35 @@ interface IPackageManager { void setHomeActivity(in ComponentName className, int userId); /** * Overrides the label and icon of the component specified by the component name. The component * must belong to the calling app. * * These changes will be reset on the next boot and whenever the package is updated. * * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed * to call this. * * @param componentName The component name to override the label/icon of. * @param nonLocalizedLabel The label to be displayed. * @param icon The icon to be displayed. * @param userId The user id. */ void overrideLabelAndIcon(in ComponentName componentName, String nonLocalizedLabel, int icon, int userId); /** * Restores the label and icon of the activity specified by the component name if either has * been overridden. The component must belong to the calling app. * * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed * to call this. * * @param componentName The component name. * @param userId The user id. */ void restoreLabelAndIcon(in ComponentName componentName, int userId); /** * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}. */ Loading
core/java/android/content/pm/PackageUserState.java +71 −0 Original line number Diff line number Diff line Loading @@ -27,18 +27,24 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.pm.parsing.component.ParsedMainComponent; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -84,6 +90,9 @@ public class PackageUserState { private ArrayMap<String, String[]> sharedLibraryOverlayPaths; // Lib name to overlay paths private String[] cachedOverlayPaths; @Nullable private ArrayMap<ComponentName, Pair<String, Integer>> componentLabelIconOverrideMap; @UnsupportedAppUsage public PackageUserState() { installed = true; Loading Loading @@ -123,6 +132,9 @@ public class PackageUserState { sharedLibraryOverlayPaths = new ArrayMap<>(o.sharedLibraryOverlayPaths); } harmfulAppWarning = o.harmfulAppWarning; if (o.componentLabelIconOverrideMap != null) { this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap); } } public String[] getOverlayPaths() { Loading @@ -146,6 +158,65 @@ public class PackageUserState { cachedOverlayPaths = null; } /** * Overrides the non-localized label and icon of a component. * * @return true if the label or icon was changed. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean overrideLabelAndIcon(@NonNull ComponentName component, @Nullable String nonLocalizedLabel, @Nullable Integer icon) { String existingLabel = null; Integer existingIcon = null; if (componentLabelIconOverrideMap != null) { Pair<String, Integer> pair = componentLabelIconOverrideMap.get(component); if (pair != null) { existingLabel = pair.first; existingIcon = pair.second; } } boolean changed = !TextUtils.equals(existingLabel, nonLocalizedLabel) || !Objects.equals(existingIcon, icon); if (changed) { if (nonLocalizedLabel == null && icon == null) { componentLabelIconOverrideMap.remove(component); if (componentLabelIconOverrideMap.isEmpty()) { componentLabelIconOverrideMap = null; } } else { if (componentLabelIconOverrideMap == null) { componentLabelIconOverrideMap = new ArrayMap<>(1); } componentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon)); } } return changed; } /** * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName, * String, Integer)}. * * This is done when the package is updated as the components and resource IDs may have changed. */ public void resetOverrideComponentLabelIcon() { componentLabelIconOverrideMap = null; } @Nullable public Pair<String, Integer> getOverrideLabelIconForComponent(ComponentName componentName) { if (ArrayUtils.isEmpty(componentLabelIconOverrideMap)) { return null; } return componentLabelIconOverrideMap.get(componentName); } /** * Test if this package is installed. */ Loading
core/res/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1910,6 +1910,9 @@ <!-- The name of the package that will hold the system gallery role. --> <string name="config_systemGallery" translatable="false">com.android.gallery</string> <!-- The name of the package that will be allowed to change its components' label/icon. --> <string name="config_overrideComponentUiPackage" translatable="false"></string> <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> <bool name="config_bluetooth_default_profiles">true</bool> Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3961,4 +3961,6 @@ <!-- Set to true to make assistant show in front of the dream/screensaver. --> <java-symbol type="bool" name="config_assistantOnTopOfDream"/> <java-symbol type="string" name="config_overrideComponentUiPackage" /> </resources>
services/core/java/com/android/server/pm/ComponentResolver.java +29 −4 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; import com.android.server.pm.parsing.PackageInfoUtils; Loading Loading @@ -207,33 +208,57 @@ public class ComponentResolver { } /** Returns the given activity */ ParsedActivity getActivity(ComponentName component) { @Nullable @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public ParsedActivity getActivity(@NonNull ComponentName component) { synchronized (mLock) { return mActivities.mActivities.get(component); } } /** Returns the given provider */ ParsedProvider getProvider(ComponentName component) { @Nullable ParsedProvider getProvider(@NonNull ComponentName component) { synchronized (mLock) { return mProviders.mProviders.get(component); } } /** Returns the given receiver */ ParsedActivity getReceiver(ComponentName component) { @Nullable ParsedActivity getReceiver(@NonNull ComponentName component) { synchronized (mLock) { return mReceivers.mActivities.get(component); } } /** Returns the given service */ ParsedService getService(ComponentName component) { @Nullable ParsedService getService(@NonNull ComponentName component) { synchronized (mLock) { return mServices.mServices.get(component); } } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean componentExists(@NonNull ComponentName componentName) { synchronized (mLock) { ParsedMainComponent component = mActivities.mActivities.get(componentName); if (component != null) { return true; } component = mReceivers.mActivities.get(componentName); if (component != null) { return true; } component = mServices.mServices.get(componentName); if (component != null) { return true; } return mProviders.mProviders.get(componentName) != null; } } @Nullable List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags, int userId) { Loading