diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index a62f809805..f5afd88f15 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -97,3 +97,10 @@ flag { description: "Enables support for archived apps in Launcher3, such as empty progress bar etc." bug: "210590852" } + +flag { + name: "enable_private_space_install_shortcut" + namespace: "launcher" + description: "Enables long-press shortcut to install a copy of an app to Private space" + bug: "316118005" +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index 784c560b04..7113e495e0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -129,8 +129,10 @@ public class ApiWrapper { public static Intent getAppMarketActivityIntent(Context context, String packageName, UserHandle user) { LauncherApps launcherApps = context.getSystemService(LauncherApps.class); - if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace() - && Flags.privateSpaceAppInstallerButton()) { + if (android.os.Flags.allowPrivateProfile() + && Flags.enablePrivateSpace() + && (Flags.privateSpaceAppInstallerButton() + || Flags.enablePrivateSpaceInstallShortcut())) { StartActivityParams params = new StartActivityParams((PendingIntent) null, 0); params.intentSender = launcherApps.getAppMarketActivityIntent(packageName, user); return ProxyActivityStarter.getLaunchIntent(context, params); diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 71f4faf56c..0d4a7f0e50 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -40,6 +40,7 @@ import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; import static com.android.launcher3.popup.SystemShortcut.APP_INFO; import static com.android.launcher3.popup.SystemShortcut.INSTALL; +import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL; import static com.android.launcher3.popup.SystemShortcut.WIDGETS; import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX; import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX; @@ -95,6 +96,7 @@ import androidx.annotation.RequiresApi; import com.android.app.viewcapture.SettingsAwareViewCapture; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Flags; import com.android.launcher3.HomeTransitionController; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings.Favorites; @@ -415,6 +417,10 @@ public class QuickstepLauncher extends Launcher { shortcuts.addAll(getSplitShortcuts()); shortcuts.add(WIDGETS); shortcuts.add(INSTALL); + + if (Flags.enablePrivateSpaceInstallShortcut()) { + shortcuts.add(PRIVATE_PROFILE_INSTALL); + } return shortcuts.stream(); } diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml new file mode 100644 index 0000000000..7f00f8d6b2 --- /dev/null +++ b/res/drawable/ic_install_to_private.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 956d24daa2..34677f6ae7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -171,6 +171,8 @@ Uninstall App info + + Install in private Install diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index 4ad4c71a55..ad764e3867 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -1315,6 +1315,10 @@ public class ActivityAllAppsContainerView : mViewPager == null ? AdapterHolder.MAIN : mViewPager.getNextPage(); } + public PrivateProfileManager getPrivateProfileManager() { + return mPrivateProfileManager; + } + /** * Adds an update listener to animator that adds springs to the animation. */ diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java index 0261010d8b..6bef7256ff 100644 --- a/src/com/android/launcher3/allapps/UserProfileManager.java +++ b/src/com/android/launcher3/allapps/UserProfileManager.java @@ -94,6 +94,19 @@ public abstract class UserProfileManager { return mCurrentState; } + /** Returns if user profile is enabled. */ + public boolean isEnabled() { + return mCurrentState == STATE_ENABLED; + } + + /** Returns the UserHandle corresponding to the profile type, null in case no matches found. */ + public UserHandle getProfileUser() { + return mUserCache.getUserProfiles().stream() + .filter(getUserMatcher()) + .findAny() + .orElse(null); + } + /** Logs Event to StatsLogManager. */ protected void logEvents(StatsLogManager.EventEnum event) { mStatsLogManager.logger().log(event); diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 6651fa030e..0dc0d0239a 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -701,6 +701,9 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User tapped private space settings button") LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP(1550), + @UiEvent(doc = "User tapped on install to private space system shortcut.") + LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP(1565), + // ADD MORE ; diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index f39f8060ba..8463361eef 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -1,5 +1,6 @@ package com.android.launcher3.popup; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP; @@ -8,6 +9,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.os.Process; +import android.os.UserHandle; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; @@ -20,10 +22,12 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.allapps.PrivateProfileManager; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.uioverrides.ApiWrapper; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; @@ -212,6 +216,69 @@ public abstract class SystemShortcut extend } } + public static final Factory PRIVATE_PROFILE_INSTALL = + (launcher, itemInfo, originalView) -> { + if (itemInfo.getTargetComponent() == null + || !(itemInfo instanceof com.android.launcher3.model.data.AppInfo) + || !itemInfo.getContainerInfo().hasAllAppsContainer() + || !Process.myUserHandle().equals(itemInfo.user)) { + return null; + } + + PrivateProfileManager privateProfileManager = + launcher.getAppsView().getPrivateProfileManager(); + if (privateProfileManager == null || !privateProfileManager.isEnabled()) { + return null; + } + + UserHandle privateProfileUser = privateProfileManager.getProfileUser(); + if (privateProfileUser == null) { + return null; + } + // Do not show shortcut if an app is already installed to the space + ComponentKey targetKey = + new ComponentKey(itemInfo.getTargetComponent(), privateProfileUser); + if (launcher.getAppsView().getAppsStore().getApp(targetKey) != null) { + return null; + } + + // TODO(b/302666597): do not install app if it's in deny list (e.g. settings) + + return new InstallToPrivateProfile( + launcher, itemInfo, originalView, privateProfileUser); + }; + + static class InstallToPrivateProfile extends SystemShortcut { + UserHandle mSpaceUser; + + InstallToPrivateProfile( + Launcher target, ItemInfo itemInfo, View originalView, UserHandle spaceUser) { + // TODO(b/302666597): update icon once available + super( + R.drawable.ic_install_to_private, + R.string.install_private_system_shortcut_label, + target, + itemInfo, + originalView); + mSpaceUser = spaceUser; + } + + @Override + public void onClick(View view) { + Intent intent = + ApiWrapper.getAppMarketActivityIntent( + view.getContext(), + mItemInfo.getTargetComponent().getPackageName(), + mSpaceUser); + mTarget.startActivitySafely(view, intent, mItemInfo); + AbstractFloatingView.closeAllOpenViews(mTarget); + mTarget.getStatsLogManager() + .logger() + .withItemInfo(mItemInfo) + .log(LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP); + } + } + public static final Factory INSTALL = (activity, itemInfo, originalView) -> { boolean supportsWebUI = (itemInfo instanceof WorkspaceItemInfo)