From 23cc38d526f35625d0de6ec22e3a82abdcc2e4e4 Mon Sep 17 00:00:00 2001 From: nsl Date: Mon, 13 Feb 2023 14:02:59 +0000 Subject: [PATCH] Adding an API that provides a map of shortcuts to be replaced. Adding an API in LauncherApps that returns a map of packages to LauncherActivityInfo. All launcher's shortcuts for the packages should point to the override's intent and profile id. This API when building the layout for the first time or after storage clear. This API is hidden as it should not be used outside of the Launcher. Bug: 265299249 Test: b/26951794 Change-Id: I3599e00f666edc61b9177eaec4f95e7e571acd44 --- .../android/app/admin/DevicePolicyCache.java | 13 +++++ .../android/content/pm/ILauncherApps.aidl | 2 + .../content/pm/LauncherActivityInfo.java | 8 +-- .../pm/LauncherActivityInfoInternal.java | 22 ++++++-- .../java/android/content/pm/LauncherApps.java | 37 +++++++++++- .../server/pm/LauncherAppsService.java | 56 ++++++++++++++++++- .../devicepolicy/DevicePolicyCacheImpl.java | 25 +++++++++ .../DevicePolicyManagerService.java | 39 ++++++++++++- 8 files changed, 186 insertions(+), 16 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java index 3957732c56dd1..b6e83c8bc8a1b 100644 --- a/core/java/android/app/admin/DevicePolicyCache.java +++ b/core/java/android/app/admin/DevicePolicyCache.java @@ -19,6 +19,9 @@ import android.annotation.UserIdInt; import com.android.server.LocalServices; +import java.util.ArrayList; +import java.util.List; + /** * Stores a copy of the set of device policies maintained by {@link DevicePolicyManager} that * can be accessed from any place without risking dead locks. @@ -60,6 +63,12 @@ public abstract class DevicePolicyCache { */ public abstract boolean canAdminGrantSensorsPermissions(); + /** + * Returns a list of package names for which all launcher shortcuts should be modified to be + * launched in the managed profile and badged accordingly. + */ + public abstract List getLauncherShortcutOverrides(); + /** * Empty implementation. */ @@ -85,5 +94,9 @@ public abstract class DevicePolicyCache { public boolean canAdminGrantSensorsPermissions() { return false; } + @Override + public List getLauncherShortcutOverrides() { + return new ArrayList<>(); + } } } diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 08cfbf76a0403..96a42e24bc1a5 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -33,6 +33,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.pm.LauncherActivityInfoInternal; import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; @@ -114,4 +115,5 @@ interface ILauncherApps { String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId); + Map getActivityOverrides(String callingPackage, int userId); } diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index 16e720e3794c6..a4d532712cfe2 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -34,7 +34,6 @@ import android.util.DisplayMetrics; */ public class LauncherActivityInfo { private final PackageManager mPm; - private UserHandle mUser; private final LauncherActivityInfoInternal mInternal; /** @@ -43,9 +42,8 @@ public class LauncherActivityInfo { * @param context The context for fetching resources. */ - LauncherActivityInfo(Context context, UserHandle user, LauncherActivityInfoInternal internal) { + LauncherActivityInfo(Context context, LauncherActivityInfoInternal internal) { mPm = context.getPackageManager(); - mUser = user; mInternal = internal; } @@ -70,7 +68,7 @@ public class LauncherActivityInfo { * @return The UserHandle of the profile. */ public UserHandle getUser() { - return mUser; + return mInternal.getUser(); } /** @@ -180,6 +178,6 @@ public class LauncherActivityInfo { public Drawable getBadgedIcon(int density) { Drawable originalIcon = getIcon(density); - return mPm.getUserBadgedIcon(originalIcon, mUser); + return mPm.getUserBadgedIcon(originalIcon, mInternal.getUser()); } } diff --git a/core/java/android/content/pm/LauncherActivityInfoInternal.java b/core/java/android/content/pm/LauncherActivityInfoInternal.java index 46c415df75256..5aac97d784b37 100644 --- a/core/java/android/content/pm/LauncherActivityInfoInternal.java +++ b/core/java/android/content/pm/LauncherActivityInfoInternal.java @@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; /** * @hide @@ -30,23 +31,27 @@ public class LauncherActivityInfoInternal implements Parcelable { @NonNull private ActivityInfo mActivityInfo; @NonNull private ComponentName mComponentName; @NonNull private IncrementalStatesInfo mIncrementalStatesInfo; + @NonNull private UserHandle mUser; /** * @param info ActivityInfo from which to create the LauncherActivityInfo. * @param incrementalStatesInfo The package's states. + * @param user The user the activity info belongs to. */ public LauncherActivityInfoInternal(@NonNull ActivityInfo info, - @NonNull IncrementalStatesInfo incrementalStatesInfo) { + @NonNull IncrementalStatesInfo incrementalStatesInfo, + @NonNull UserHandle user) { mActivityInfo = info; mComponentName = new ComponentName(info.packageName, info.name); mIncrementalStatesInfo = incrementalStatesInfo; + mUser = user; } public LauncherActivityInfoInternal(Parcel source) { - mActivityInfo = source.readParcelable(ActivityInfo.class.getClassLoader(), android.content.pm.ActivityInfo.class); + mActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name); - mIncrementalStatesInfo = source.readParcelable( - IncrementalStatesInfo.class.getClassLoader(), android.content.pm.IncrementalStatesInfo.class); + mIncrementalStatesInfo = source.readTypedObject(IncrementalStatesInfo.CREATOR); + mUser = source.readTypedObject(UserHandle.CREATOR); } public ComponentName getComponentName() { @@ -57,6 +62,10 @@ public class LauncherActivityInfoInternal implements Parcelable { return mActivityInfo; } + public UserHandle getUser() { + return mUser; + } + public IncrementalStatesInfo getIncrementalStatesInfo() { return mIncrementalStatesInfo; } @@ -68,8 +77,9 @@ public class LauncherActivityInfoInternal implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(mActivityInfo, 0); - dest.writeParcelable(mIncrementalStatesInfo, 0); + dest.writeTypedObject(mActivityInfo, flags); + dest.writeTypedObject(mIncrementalStatesInfo, flags); + dest.writeTypedObject(mUser, flags); } public static final @android.annotation.NonNull Creator CREATOR = diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index f8c49744d8349..8989006a7e831 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -64,6 +64,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; @@ -793,12 +794,44 @@ public class LauncherApps { if (ai == null) { return null; } - return new LauncherActivityInfo(mContext, user, ai); + return new LauncherActivityInfo(mContext, ai); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } + /** + * Returns overrides for the activities that should be launched for the shortcuts of certain + * package names. + * + * @return {@link Map} whose keys are package names and whose values are the + * {@link LauncherActivityInfo}s that should be used for those packages' shortcuts. If there are + * no activity overrides, an empty {@link Map} will be returned. + * + * @hide + */ + @NonNull + public Map getActivityOverrides() { + Map activityOverrides = new ArrayMap<>(); + try { + Map activityOverridesInternal = + mService.getActivityOverrides(mContext.getPackageName(), mContext.getUserId()); + for (Map.Entry packageToOverride : + activityOverridesInternal.entrySet()) { + activityOverrides.put( + packageToOverride.getKey(), + new LauncherActivityInfo( + mContext, + packageToOverride.getValue() + ) + ); + } + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + return activityOverrides; + } + /** * Starts a Main activity in the specified profile. * @@ -916,7 +949,7 @@ public class LauncherApps { } ArrayList lais = new ArrayList<>(); for (LauncherActivityInfoInternal internal : internals.getList()) { - LauncherActivityInfo lai = new LauncherActivityInfo(mContext, user, internal); + LauncherActivityInfo lai = new LauncherActivityInfo(mContext, internal); if (DEBUG) { Log.v(TAG, "Returning activity for profile " + user + " : " + lai.getComponentName()); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 9e01c7af0f0bd..84bee50b77b0b 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -39,6 +39,7 @@ import android.app.ActivityOptions; import android.app.AppGlobals; import android.app.IApplicationThread; import android.app.PendingIntent; +import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; import android.app.usage.UsageStatsManagerInternal; import android.content.ActivityNotFoundException; @@ -85,6 +86,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -107,6 +109,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutionException; @@ -623,7 +626,7 @@ public class LauncherAppsService extends SystemService { // package does not exist; should not happen return null; } - return new LauncherActivityInfoInternal(activityInfo, incrementalStatesInfo); + return new LauncherActivityInfoInternal(activityInfo, incrementalStatesInfo, user); } finally { Binder.restoreCallingIdentity(ident); } @@ -676,7 +679,7 @@ public class LauncherAppsService extends SystemService { continue; } results.add(new LauncherActivityInfoInternal(ri.activityInfo, - incrementalStatesInfo)); + incrementalStatesInfo, user)); } return results; } @@ -1077,6 +1080,55 @@ public class LauncherAppsService extends SystemService { callingPackage, injectBinderCallingPid(), injectBinderCallingUid()); } + @Override + @NonNull + public Map getActivityOverrides(String callingPackage, + int userId) { + ensureShortcutPermission(callingPackage); + int callingUid = Binder.getCallingUid(); + final long callerIdentity = Binder.clearCallingIdentity(); + try { + Map shortcutOverridesInfo = new ArrayMap<>(); + UserHandle managedUserHandle = getManagedProfile(userId); + if (managedUserHandle == null) { + return shortcutOverridesInfo; + } + + List packagesToOverride = + DevicePolicyCache.getInstance().getLauncherShortcutOverrides(); + for (String packageName : packagesToOverride) { + Intent intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setPackage(packageName); + + List possibleShortcutOverrides = + queryIntentLauncherActivities( + intent, + callingUid, + managedUserHandle + ); + + if (!possibleShortcutOverrides.isEmpty()) { + shortcutOverridesInfo.put(packageName, possibleShortcutOverrides.get(0)); + } + } + return shortcutOverridesInfo; + } finally { + Binder.restoreCallingIdentity(callerIdentity); + } + } + + + @Nullable + private UserHandle getManagedProfile(int userId) { + for (UserInfo profile : mUm.getProfiles(userId)) { + if (profile.isManagedProfile()) { + return profile.getUserHandle(); + } + } + return null; + } + @Override public boolean startShortcut(String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java index 4351bc1c81ce6..80100a927e82a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java @@ -24,6 +24,8 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -52,6 +54,11 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { @GuardedBy("mLock") private final SparseIntArray mPermissionPolicy = new SparseIntArray(); + @GuardedBy("mLock") + private List mLauncherShortcutOverrides = + new ArrayList<>(); + + /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */ private final AtomicBoolean mCanGrantSensorsPermissions = new AtomicBoolean(false); @@ -122,6 +129,22 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { mCanGrantSensorsPermissions.set(canGrant); } + @Override + public List getLauncherShortcutOverrides() { + synchronized (mLock) { + return new ArrayList<>(mLauncherShortcutOverrides); + } + } + + /** + * Sets a list of packages for which shortcuts should be replaced by their badged version. + */ + public void setLauncherShortcutOverrides(List launcherShortcutOverrides) { + synchronized (mLock) { + mLauncherShortcutOverrides = new ArrayList<>(launcherShortcutOverrides); + } + } + /** Dump content */ public void dump(IndentingPrintWriter pw) { synchronized (mLock) { @@ -131,6 +154,8 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { pw.println("Password quality: " + mPasswordQuality); pw.println("Permission policy: " + mPermissionPolicy); pw.println("Admin can grant sensors permission: " + mCanGrantSensorsPermissions.get()); + pw.print("Shortcuts overrides: "); + pw.println(mLauncherShortcutOverrides); pw.decreaseIndent(); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index bfcb4c7b6bc0f..2357b38e434c4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3518,16 +3518,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userId == UserHandle.USER_SYSTEM ? UserHandle.USER_ALL : userId); updatePermissionPolicyCache(userId); updateAdminCanGrantSensorsPermissionCache(userId); - final List preferentialNetworkServiceConfigs; + boolean isManagedSubscription; + synchronized (getLockObject()) { ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); preferentialNetworkServiceConfigs = owner != null ? owner.mPreferentialNetworkServiceConfigs : List.of(PreferentialNetworkServiceConfig.DEFAULT); + + isManagedSubscription = owner != null && owner.mManagedSubscriptionsPolicy != null + && owner.mManagedSubscriptionsPolicy.getPolicyType() + == ManagedSubscriptionsPolicy.TYPE_ALL_MANAGED_SUBSCRIPTIONS; } updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs); + if (isManagedSubscription) { + String defaultDialerPackageName = getDefaultRoleHolderPackageName( + com.android.internal.R.string.config_defaultDialer); + String defaultSmsPackageName = getDefaultRoleHolderPackageName( + com.android.internal.R.string.config_defaultSms); + updateDialerAndSmsManagedShortcutsOverrideCache(defaultDialerPackageName, + defaultSmsPackageName); + } + startOwnerService(userId, "start-user"); if (isDevicePolicyEngineEnabled()) { mDevicePolicyEngine.handleStartUser(userId); @@ -7610,6 +7624,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (isWorkProfileTelephonyFlagEnabled()) { clearManagedSubscriptionsPolicy(); + clearLauncherShortcutOverrides(); updateTelephonyCrossProfileIntentFilters(parentId, UserHandle.USER_NULL, false); } Slogf.i(LOG_TAG, "Cleaning up device-wide policies done."); @@ -7627,6 +7642,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void clearLauncherShortcutOverrides() { + mPolicyCache.setLauncherShortcutOverrides(new ArrayList<>()); + } + private void updateTelephonyCrossProfileIntentFilters(int parentUserId, int profileUserId, boolean enableWorkTelephony) { try { @@ -22745,12 +22764,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else { Slogf.w(LOG_TAG, "Couldn't install sms app, sms app package is null"); } + + updateDialerAndSmsManagedShortcutsOverrideCache(defaultDialerPackageName, + defaultSmsPackageName); } catch (RemoteException re) { // shouldn't happen Slogf.wtf(LOG_TAG, "Failed to install dialer/sms app", re); } } + private void updateDialerAndSmsManagedShortcutsOverrideCache( + String defaultDialerPackageName, String defaultSmsPackageName) { + + List shortcutOverrides = new ArrayList<>(); + + if (defaultDialerPackageName != null) { + shortcutOverrides.add(defaultDialerPackageName); + } + + if (defaultSmsPackageName != null) { + shortcutOverrides.add(defaultSmsPackageName); + } + mPolicyCache.setLauncherShortcutOverrides(shortcutOverrides); + } + private void registerListenerToAssignSubscriptionsToUser(int userId) { synchronized (mSubscriptionsChangedListenerLock) { if (mSubscriptionsChangedListener != null) {