Loading core/java/android/app/activity_manager.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -205,3 +205,14 @@ flag { bug: "395544023" is_fixed_read_only: true } flag { namespace: "backstage_power" name: "optimize_get_apps_and_shortcuts" description: "Get Available Apps and Shortcuts" is_fixed_read_only: true bug: "364133831" metadata { purpose: PURPOSE_BUGFIX } } core/java/android/content/pm/AppLaunchInfo.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.content.pm; import android.content.ComponentName; import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; /** * Holds information about how to launch an app, including its {@link ComponentName} * and the associated {@link Intent}. * * <p>This is a parcelable data class and should be used when passing app launch details * across process boundaries or between system components.</p> * * @hide */ public class AppLaunchInfo implements Parcelable { private final ComponentName mComponentName; private final Intent mLaunchIntent; /** * Constructs a new {@link AppLaunchInfo} instance. * * @param componentName the component to be launched * @param launchIntent the intent used to launch the component */ public AppLaunchInfo(ComponentName componentName, Intent launchIntent) { this.mComponentName = componentName; this.mLaunchIntent = launchIntent; } protected AppLaunchInfo(Parcel in) { mComponentName = in.readParcelable(ComponentName.class.getClassLoader()); mLaunchIntent = in.readParcelable(Intent.class.getClassLoader()); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mComponentName, flags); dest.writeParcelable(mLaunchIntent, flags); } @Override public int describeContents() { return 0; } /** * Parcelable creator used to instantiate {@link AppLaunchInfo} objects from a {@link Parcel}. */ public static final Creator<AppLaunchInfo> CREATOR = new Creator<AppLaunchInfo>() { @Override public AppLaunchInfo createFromParcel(Parcel in) { return new AppLaunchInfo(in); } @Override public AppLaunchInfo[] newArray(int size) { return new AppLaunchInfo[size]; } }; /** * Returns the {@link ComponentName} of the app to be launched. * * @return the target component */ public ComponentName getComponentName() { return mComponentName; } /** * Returns the {@link Intent} that can be used to launch the app. * * @return the launch intent */ public Intent getLaunchIntent() { return mLaunchIntent; } } core/java/android/content/pm/ILauncherApps.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -134,4 +134,8 @@ interface ILauncherApps { /** Saves view capture data to the wm trace directory. */ void saveViewCaptureData(); ParceledListSlice getAvailableShortcuts(String callingPackage, in UserHandle user); ParceledListSlice getActivityLaunchIntentForAllApps(String callingPackage, in UserHandle user); } core/java/android/content/pm/LauncherApps.java +82 −0 Original line number Diff line number Diff line Loading @@ -1058,6 +1058,88 @@ public class LauncherApps { } } /** * Retrieves a map of available applications for a given user. * <p> * This method queries the system service to obtain a list of available applications * for the specified {@link UserHandle}. The returned map contains {@link ComponentName} * as keys and corresponding launch {@link Intent}s as values. * </p> * * <p><b>Permissions Required:</b></p> * <ul> * <li>{@link android.Manifest.permission#INTERACT_ACROSS_USERS}</li> * <li>{@link android.Manifest.permission#MANAGE_USERS}</li> * </ul> * * @param user The {@link UserHandle} representing the user for whom available apps are queried. * @return A map where the keys are {@link ComponentName} instances representing app components, * and the values are {@link Intent} instances used to launch these apps. * @throws SecurityException If the caller lacks the necessary permissions. * @hide * */ public @NonNull Map<ComponentName, Intent> getActivityLaunchIntentForAllApps( @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { ParceledListSlice<AppLaunchInfo> infos = mService.getActivityLaunchIntentForAllApps(mContext.getPackageName(), user); if (infos == null || infos.getList().isEmpty()) { return new HashMap<>(); } List<AppLaunchInfo> appLaunchInfos = infos.getList(); Map<ComponentName, Intent> convertedApps = new HashMap<>(appLaunchInfos.size()); for (AppLaunchInfo info : appLaunchInfos) { if (info.getComponentName() != null) { convertedApps.put(info.getComponentName(), info.getLaunchIntent()); } } return convertedApps; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Retrieves a list of available shortcuts for a given user. * <p> * This method queries the system service to fetch the available {@link ShortcutInfo} * objects associated with the specified {@link UserHandle}. The returned list contains * shortcut information that can be used for launching apps or specific actions. * </p> * * <p><b>Permissions Required:</b></p> * <ul> * <li>{@link android.Manifest.permission#INTERACT_ACROSS_USERS}</li> * <li>{@link android.Manifest.permission#MANAGE_USERS}</li> * </ul> * * @param user The {@link UserHandle} representing the user for whom available shortcuts * are queried. * @return A list of {@link ShortcutInfo} objects representing the available shortcuts * for the specified user. * @throws SecurityException If the caller lacks the necessary permissions. * @hide * */ public @NonNull List<ShortcutInfo> getAvailableShortcuts(@NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { ParceledListSlice<ShortcutInfo> shortcuts = mService.getAvailableShortcuts( mContext.getPackageName(), user); if (shortcuts == null || shortcuts.getList().isEmpty()) { return Collections.EMPTY_LIST; } return shortcuts.getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Starts an activity to show the details of the specified session. * Loading services/core/java/com/android/server/pm/LauncherAppsService.java +114 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.AppLaunchInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ILauncherApps; import android.content.pm.IOnAppsChangedListener; Loading Loading @@ -1895,6 +1896,119 @@ public class LauncherAppsService extends SystemService { user.getIdentifier()); } /** * Returns a list of all available applications. * */ @Override public ParceledListSlice<AppLaunchInfo> getActivityLaunchIntentForAllApps( String callingPackage, UserHandle user) { if (!android.app.Flags.optimizeGetAppsAndShortcuts()) { return new ParceledListSlice<>(new ArrayList<>()); } List<AppLaunchInfo> availableApps = new ArrayList<>(); final int userId = user.getIdentifier(); if (!mUserManagerInternal.isUserUnlocked(userId)) { Log.d(TAG, "Unable to get apps, user " + userId + " not unlocked"); return new ParceledListSlice<>(availableApps); } try { List<LauncherActivityInfoInternal> appInfos = getLauncherActivities(callingPackage, null, user).getList(); if (appInfos == null) { return new ParceledListSlice<>(availableApps); } int numAppInfos = appInfos.size(); for (int i = 0; i < numAppInfos; i++) { LauncherActivityInfoInternal appInfo = appInfos.get(i); try { PendingIntent intent = getActivityLaunchIntent(callingPackage, appInfo.getComponentName(), user); if (intent != null) { Intent targetIntent = mActivityManagerInternal .getIntentForIntentSender(intent.getTarget()); if (targetIntent != null) { Intent sourcedIntent = new Intent(targetIntent); AppLaunchInfo info = new AppLaunchInfo( appInfo.getComponentName(), sourcedIntent); availableApps.add(info); } } } catch (RuntimeException e) { Log.e(TAG, "Error getting launch intent for " + appInfo.getComponentName(), e); } } } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } return new ParceledListSlice<>(availableApps); } /** * Returns a list of all available shortcuts. * */ @Override public ParceledListSlice<ShortcutInfo> getAvailableShortcuts(String callingPackage, UserHandle user) { List<ShortcutInfo> availableShortcuts = new ArrayList<>(); if (!android.app.Flags.optimizeGetAppsAndShortcuts()) { return new ParceledListSlice<>(availableShortcuts); } int userId = user.getIdentifier(); if (!mUserManagerInternal.isUserUnlocked(userId)) { Log.d(TAG, "Unable to get shortcuts, user " + userId + " not unlocked"); return new ParceledListSlice<>(availableShortcuts); } try { List<ShortcutInfo> shortcutInfos = getAllShortcutsForUser(callingPackage, user); if (shortcutInfos == null) { return new ParceledListSlice<>(availableShortcuts); } List<LauncherActivityInfoInternal> appInfos = getLauncherActivities(callingPackage, null, user).getList(); if (appInfos == null) { return new ParceledListSlice<>(availableShortcuts); } int numAppInfos = appInfos.size(); for (int i = 0; i < numAppInfos; i++) { LauncherActivityInfoInternal appInfo = appInfos.get(i); String packageName = appInfo.getComponentName().getPackageName(); for (int j = shortcutInfos.size() - 1; j >= 0; j--) { ShortcutInfo shortcut = shortcutInfos.get(j); if (shortcut.getPackage().equals(packageName)) { availableShortcuts.add(shortcut); } } } } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } return new ParceledListSlice<>(availableShortcuts); } /** * Returns all shortcuts for the given user. */ private List<ShortcutInfo> getAllShortcutsForUser(String callingPackage, UserHandle user) { ShortcutQuery query = new ShortcutQuery(); query.setQueryFlags( ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC); try { return getShortcuts(callingPackage, new ShortcutQueryWrapper(query), user).getList(); } catch (SecurityException | IllegalStateException e) { Log.e(TAG, "Failed to query for shortcuts", e); return null; } catch (Exception e) { throw e; // Rethrow other exceptions } } /** * Returns the main activity launch intent for the given component package. */ Loading Loading
core/java/android/app/activity_manager.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -205,3 +205,14 @@ flag { bug: "395544023" is_fixed_read_only: true } flag { namespace: "backstage_power" name: "optimize_get_apps_and_shortcuts" description: "Get Available Apps and Shortcuts" is_fixed_read_only: true bug: "364133831" metadata { purpose: PURPOSE_BUGFIX } }
core/java/android/content/pm/AppLaunchInfo.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.content.pm; import android.content.ComponentName; import android.content.Intent; import android.os.Parcel; import android.os.Parcelable; /** * Holds information about how to launch an app, including its {@link ComponentName} * and the associated {@link Intent}. * * <p>This is a parcelable data class and should be used when passing app launch details * across process boundaries or between system components.</p> * * @hide */ public class AppLaunchInfo implements Parcelable { private final ComponentName mComponentName; private final Intent mLaunchIntent; /** * Constructs a new {@link AppLaunchInfo} instance. * * @param componentName the component to be launched * @param launchIntent the intent used to launch the component */ public AppLaunchInfo(ComponentName componentName, Intent launchIntent) { this.mComponentName = componentName; this.mLaunchIntent = launchIntent; } protected AppLaunchInfo(Parcel in) { mComponentName = in.readParcelable(ComponentName.class.getClassLoader()); mLaunchIntent = in.readParcelable(Intent.class.getClassLoader()); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(mComponentName, flags); dest.writeParcelable(mLaunchIntent, flags); } @Override public int describeContents() { return 0; } /** * Parcelable creator used to instantiate {@link AppLaunchInfo} objects from a {@link Parcel}. */ public static final Creator<AppLaunchInfo> CREATOR = new Creator<AppLaunchInfo>() { @Override public AppLaunchInfo createFromParcel(Parcel in) { return new AppLaunchInfo(in); } @Override public AppLaunchInfo[] newArray(int size) { return new AppLaunchInfo[size]; } }; /** * Returns the {@link ComponentName} of the app to be launched. * * @return the target component */ public ComponentName getComponentName() { return mComponentName; } /** * Returns the {@link Intent} that can be used to launch the app. * * @return the launch intent */ public Intent getLaunchIntent() { return mLaunchIntent; } }
core/java/android/content/pm/ILauncherApps.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -134,4 +134,8 @@ interface ILauncherApps { /** Saves view capture data to the wm trace directory. */ void saveViewCaptureData(); ParceledListSlice getAvailableShortcuts(String callingPackage, in UserHandle user); ParceledListSlice getActivityLaunchIntentForAllApps(String callingPackage, in UserHandle user); }
core/java/android/content/pm/LauncherApps.java +82 −0 Original line number Diff line number Diff line Loading @@ -1058,6 +1058,88 @@ public class LauncherApps { } } /** * Retrieves a map of available applications for a given user. * <p> * This method queries the system service to obtain a list of available applications * for the specified {@link UserHandle}. The returned map contains {@link ComponentName} * as keys and corresponding launch {@link Intent}s as values. * </p> * * <p><b>Permissions Required:</b></p> * <ul> * <li>{@link android.Manifest.permission#INTERACT_ACROSS_USERS}</li> * <li>{@link android.Manifest.permission#MANAGE_USERS}</li> * </ul> * * @param user The {@link UserHandle} representing the user for whom available apps are queried. * @return A map where the keys are {@link ComponentName} instances representing app components, * and the values are {@link Intent} instances used to launch these apps. * @throws SecurityException If the caller lacks the necessary permissions. * @hide * */ public @NonNull Map<ComponentName, Intent> getActivityLaunchIntentForAllApps( @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { ParceledListSlice<AppLaunchInfo> infos = mService.getActivityLaunchIntentForAllApps(mContext.getPackageName(), user); if (infos == null || infos.getList().isEmpty()) { return new HashMap<>(); } List<AppLaunchInfo> appLaunchInfos = infos.getList(); Map<ComponentName, Intent> convertedApps = new HashMap<>(appLaunchInfos.size()); for (AppLaunchInfo info : appLaunchInfos) { if (info.getComponentName() != null) { convertedApps.put(info.getComponentName(), info.getLaunchIntent()); } } return convertedApps; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Retrieves a list of available shortcuts for a given user. * <p> * This method queries the system service to fetch the available {@link ShortcutInfo} * objects associated with the specified {@link UserHandle}. The returned list contains * shortcut information that can be used for launching apps or specific actions. * </p> * * <p><b>Permissions Required:</b></p> * <ul> * <li>{@link android.Manifest.permission#INTERACT_ACROSS_USERS}</li> * <li>{@link android.Manifest.permission#MANAGE_USERS}</li> * </ul> * * @param user The {@link UserHandle} representing the user for whom available shortcuts * are queried. * @return A list of {@link ShortcutInfo} objects representing the available shortcuts * for the specified user. * @throws SecurityException If the caller lacks the necessary permissions. * @hide * */ public @NonNull List<ShortcutInfo> getAvailableShortcuts(@NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { ParceledListSlice<ShortcutInfo> shortcuts = mService.getAvailableShortcuts( mContext.getPackageName(), user); if (shortcuts == null || shortcuts.getList().isEmpty()) { return Collections.EMPTY_LIST; } return shortcuts.getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Starts an activity to show the details of the specified session. * Loading
services/core/java/com/android/server/pm/LauncherAppsService.java +114 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.AppLaunchInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ILauncherApps; import android.content.pm.IOnAppsChangedListener; Loading Loading @@ -1895,6 +1896,119 @@ public class LauncherAppsService extends SystemService { user.getIdentifier()); } /** * Returns a list of all available applications. * */ @Override public ParceledListSlice<AppLaunchInfo> getActivityLaunchIntentForAllApps( String callingPackage, UserHandle user) { if (!android.app.Flags.optimizeGetAppsAndShortcuts()) { return new ParceledListSlice<>(new ArrayList<>()); } List<AppLaunchInfo> availableApps = new ArrayList<>(); final int userId = user.getIdentifier(); if (!mUserManagerInternal.isUserUnlocked(userId)) { Log.d(TAG, "Unable to get apps, user " + userId + " not unlocked"); return new ParceledListSlice<>(availableApps); } try { List<LauncherActivityInfoInternal> appInfos = getLauncherActivities(callingPackage, null, user).getList(); if (appInfos == null) { return new ParceledListSlice<>(availableApps); } int numAppInfos = appInfos.size(); for (int i = 0; i < numAppInfos; i++) { LauncherActivityInfoInternal appInfo = appInfos.get(i); try { PendingIntent intent = getActivityLaunchIntent(callingPackage, appInfo.getComponentName(), user); if (intent != null) { Intent targetIntent = mActivityManagerInternal .getIntentForIntentSender(intent.getTarget()); if (targetIntent != null) { Intent sourcedIntent = new Intent(targetIntent); AppLaunchInfo info = new AppLaunchInfo( appInfo.getComponentName(), sourcedIntent); availableApps.add(info); } } } catch (RuntimeException e) { Log.e(TAG, "Error getting launch intent for " + appInfo.getComponentName(), e); } } } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } return new ParceledListSlice<>(availableApps); } /** * Returns a list of all available shortcuts. * */ @Override public ParceledListSlice<ShortcutInfo> getAvailableShortcuts(String callingPackage, UserHandle user) { List<ShortcutInfo> availableShortcuts = new ArrayList<>(); if (!android.app.Flags.optimizeGetAppsAndShortcuts()) { return new ParceledListSlice<>(availableShortcuts); } int userId = user.getIdentifier(); if (!mUserManagerInternal.isUserUnlocked(userId)) { Log.d(TAG, "Unable to get shortcuts, user " + userId + " not unlocked"); return new ParceledListSlice<>(availableShortcuts); } try { List<ShortcutInfo> shortcutInfos = getAllShortcutsForUser(callingPackage, user); if (shortcutInfos == null) { return new ParceledListSlice<>(availableShortcuts); } List<LauncherActivityInfoInternal> appInfos = getLauncherActivities(callingPackage, null, user).getList(); if (appInfos == null) { return new ParceledListSlice<>(availableShortcuts); } int numAppInfos = appInfos.size(); for (int i = 0; i < numAppInfos; i++) { LauncherActivityInfoInternal appInfo = appInfos.get(i); String packageName = appInfo.getComponentName().getPackageName(); for (int j = shortcutInfos.size() - 1; j >= 0; j--) { ShortcutInfo shortcut = shortcutInfos.get(j); if (shortcut.getPackage().equals(packageName)) { availableShortcuts.add(shortcut); } } } } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } return new ParceledListSlice<>(availableShortcuts); } /** * Returns all shortcuts for the given user. */ private List<ShortcutInfo> getAllShortcutsForUser(String callingPackage, UserHandle user) { ShortcutQuery query = new ShortcutQuery(); query.setQueryFlags( ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC); try { return getShortcuts(callingPackage, new ShortcutQueryWrapper(query), user).getList(); } catch (SecurityException | IllegalStateException e) { Log.e(TAG, "Failed to query for shortcuts", e); return null; } catch (Exception e) { throw e; // Rethrow other exceptions } } /** * Returns the main activity launch intent for the given component package. */ Loading