Prompting the user to set Pixel/Quickstep as default Home app.
requestQuietMode API throws SecurityException in case its called
from a non-default Launcher app.
To mitigate this, we catch the exception and prompt the user
to set their default launcher to the current app.
Video(Pixel): https://photos.app.goo.gl/ni5X1c6vBbYW2JMJ9
Video(Pixel-aosp): https://photos.app.goo.gl/cYLJpTYW76Jnbonc9
Bug: 320446272
Test: Manual
Flag: NONE Bug fix tweak.
Change-Id: I6afb2ae85cabc038e1503e9c34eebd974c4f7a50
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index 146ff3d..0469636 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -17,24 +17,32 @@
import android.app.ActivityOptions
import android.app.PendingIntent
+import android.app.role.RoleManager
import android.content.Context
+import android.content.IIntentReceiver
+import android.content.IIntentSender
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.content.pm.ShortcutInfo
+import android.os.Bundle
import android.os.Flags.allowPrivateProfile
+import android.os.IBinder
import android.os.UserHandle
import android.os.UserManager
import android.util.ArrayMap
+import android.widget.Toast
import android.window.RemoteTransition
import com.android.launcher3.Flags.enablePrivateSpace
import com.android.launcher3.Flags.enablePrivateSpaceInstallShortcut
import com.android.launcher3.Flags.privateSpaceAppInstallerButton
import com.android.launcher3.Flags.privateSpaceSysAppsSeparation
+import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.proxy.ProxyActivityStarter
import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.Executors
import com.android.launcher3.util.StartActivityParams
import com.android.launcher3.util.UserIconInfo
import com.android.quickstep.util.FadeOutRemoteTransition
@@ -115,8 +123,7 @@
intentSender =
mContext
.getSystemService(LauncherApps::class.java)
- ?.privateSpaceSettingsIntent
- ?: return null
+ ?.privateSpaceSettingsIntent ?: return null
options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
@@ -130,4 +137,50 @@
override fun isNonResizeableActivity(lai: LauncherActivityInfo) =
lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
+
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ override fun assignDefaultHomeRole(context: Context) {
+ val roleManager = context.getSystemService(RoleManager::class.java)
+ if (
+ (roleManager!!.isRoleAvailable(RoleManager.ROLE_HOME) &&
+ !roleManager.isRoleHeld(RoleManager.ROLE_HOME))
+ ) {
+ val roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME)
+ val pendingIntent =
+ PendingIntent(
+ object : IIntentSender.Stub() {
+ override fun send(
+ code: Int,
+ intent: Intent,
+ resolvedType: String?,
+ allowlistToken: IBinder?,
+ finishedReceiver: IIntentReceiver?,
+ requiredPermission: String?,
+ options: Bundle?
+ ) {
+ if (code != -1) {
+ Executors.MAIN_EXECUTOR.execute {
+ Toast.makeText(
+ context,
+ context.getString(
+ R.string.set_default_home_app,
+ context.getString(R.string.derived_app_name)
+ ),
+ Toast.LENGTH_LONG
+ )
+ .show()
+ }
+ }
+ }
+ }
+ )
+ val params = StartActivityParams(pendingIntent, 0)
+ params.intent = roleRequestIntent
+ context.startActivity(ProxyActivityStarter.getLaunchIntent(context, params))
+ }
+ }
}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a9cca6d..d33adc4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -36,6 +36,8 @@
<string name="shortcut_not_available">Shortcut isn\'t available</string>
<!-- User visible name for the launcher/home screen. [CHAR_LIMIT=30] -->
<string name="home_screen">Home</string>
+ <!-- Description for setting the current launcher as the default home app. [CHAR_LIMIT=none]-->
+ <string name="set_default_home_app">Set <xliff:g id="launcher_name" example="Launcher3">%1$s</xliff:g> as default home app in Settings</string>
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2b30dc4..02a2939 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -38,6 +38,7 @@
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_SHORTCUT;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_PICK_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -151,6 +152,7 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
+import android.widget.Toast;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -891,6 +893,17 @@
}
mPendingActivityResult = null;
+ if (requestCode == REQUEST_HOME_ROLE) {
+ if (resultCode != RESULT_OK) {
+ Toast.makeText(
+ this,
+ this.getString(R.string.set_default_home_app,
+ this.getString(R.string.derived_app_name)),
+ Toast.LENGTH_LONG).show();
+ }
+ return;
+ }
+
// Reset the startActivity waiting flag
final PendingRequestArgs requestArgs = mPendingRequestArgs;
setWaitingForResult(null);
diff --git a/src/com/android/launcher3/LauncherConstants.java b/src/com/android/launcher3/LauncherConstants.java
index 1abfeb9..445fb41 100644
--- a/src/com/android/launcher3/LauncherConstants.java
+++ b/src/com/android/launcher3/LauncherConstants.java
@@ -41,6 +41,7 @@
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+ public static final int REQUEST_HOME_ROLE = 14;
static final int REQUEST_CREATE_SHORTCUT = 1;
static final int REQUEST_CREATE_APPWIDGET = 5;
static final int REQUEST_PICK_APPWIDGET = 9;
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 5cacf60..6f021ea 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -281,11 +281,29 @@
@Override
public void setQuietMode(boolean enable) {
- super.setQuietMode(enable);
+ UI_HELPER_EXECUTOR.post(() ->
+ mUserCache.getUserProfiles()
+ .stream()
+ .filter(getUserMatcher())
+ .findFirst()
+ .ifPresent(userHandle -> setQuietModeSafely(enable, userHandle)));
mReadyToAnimate = true;
}
/**
+ * Sets Quiet Mode for Private Profile.
+ * If {@link SecurityException} is thrown, prompts the user to set this launcher as HOME app.
+ */
+ private void setQuietModeSafely(boolean enable, UserHandle userHandle) {
+ try {
+ mUserManager.requestQuietModeEnabled(enable, userHandle);
+ } catch (SecurityException ex) {
+ ApiWrapper.INSTANCE.get(mAllApps.mActivityContext)
+ .assignDefaultHomeRole(mAllApps.mActivityContext);
+ }
+ }
+
+ /**
* Expand the private space after the app list has been added and updated from
* {@link AlphabeticalAppsList#onAppsUpdated()}
*/
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index eb74d20..93b6b29 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -55,12 +55,11 @@
public @interface UserProfileState { }
protected final StatsLogManager mStatsLogManager;
+ protected final UserManager mUserManager;
+ protected final UserCache mUserCache;
+
@UserProfileState
private int mCurrentState;
-
- private final UserManager mUserManager;
- private final UserCache mUserCache;
-
protected UserProfileManager(UserManager userManager,
StatsLogManager statsLogManager,
UserCache userCache) {
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index 6429a43..095518c 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -16,10 +16,12 @@
package com.android.launcher3.util;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import android.app.ActivityOptions;
import android.app.Person;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -33,6 +35,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -136,6 +139,23 @@
return false;
}
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ public void assignDefaultHomeRole(Context context) {
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ assert roleManager != null;
+ if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME)
+ && !roleManager.isRoleHeld(RoleManager.ROLE_HOME)) {
+ Intent roleRequestIntent = roleManager.createRequestRoleIntent(
+ RoleManager.ROLE_HOME);
+ Launcher launcher = Launcher.getLauncher(context);
+ launcher.startActivityForResult(roleRequestIntent, REQUEST_HOME_ROLE);
+ }
+ }
+
@Override
public void close() { }