From f42207e1d9b4601280a454ee95c5a46128517cfa Mon Sep 17 00:00:00 2001 From: Manish Singh Date: Wed, 27 Mar 2024 17:23:33 +0000 Subject: [PATCH] Remove all Settings tasks from Recents when PS is locked Bug: 330865434 Test: manual Test: atest PrivateSpaceMaintainerTest Change-Id: I56b12a6ea5bfedd243fd138ef898f8496301199e --- .../privatespace/PrivateSpaceMaintainer.java | 107 +++++++++++++++++- .../PrivateSpaceMaintainerTest.java | 25 ++++ 2 files changed, 126 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java index a0c4cbecaed..e27a1c671e7 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java +++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java @@ -23,20 +23,21 @@ import static android.provider.Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEV import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import android.app.ActivityManager; -import android.app.IActivityManager; import android.app.KeyguardManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.UserInfo; import android.os.Flags; -import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -54,9 +55,12 @@ public class PrivateSpaceMaintainer { private final Context mContext; private final UserManager mUserManager; + private final ActivityManager mActivityManager; @GuardedBy("this") private UserHandle mUserHandle; private final KeyguardManager mKeyguardManager; + /** This variable should be accessed via {@link #getBroadcastReceiver()} only. */ + @Nullable private ProfileAvailabilityBroadcastReceiver mProfileAvailabilityBroadcastReceiver; /** This is the default value for the hide private space entry point settings. */ public static final int HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL = 0; @@ -104,12 +108,13 @@ public class PrivateSpaceMaintainer { return false; } - IActivityManager am = ActivityManager.getService(); + registerBroadcastReceiver(); + try { //TODO(b/313926659): To check and handle failure of startProfile - am.startProfile(mUserHandle.getIdentifier()); - } catch (RemoteException e) { - Log.e(TAG, "Failed to start private profile"); + mActivityManager.startProfile(mUserHandle); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unexpected that " + mUserHandle.getIdentifier() + " is not a profile"); return false; } @@ -134,6 +139,7 @@ public class PrivateSpaceMaintainer { Log.i(TAG, "Deleting Private space with id: " + mUserHandle.getIdentifier()); if (mUserManager.removeUser(mUserHandle)) { Log.i(TAG, "Private space deleted"); + unregisterBroadcastReceiver(); mUserHandle = null; return ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE; @@ -160,6 +166,7 @@ public class PrivateSpaceMaintainer { for (UserInfo user : users) { if (user.isPrivateProfile()) { mUserHandle = user.getUserHandle(); + registerBroadcastReceiver(); return true; } } @@ -213,6 +220,7 @@ public class PrivateSpaceMaintainer { mContext = context.getApplicationContext(); mUserManager = mContext.getSystemService(UserManager.class); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); + mActivityManager = mContext.getSystemService(ActivityManager.class); } @@ -328,4 +336,91 @@ public class PrivateSpaceMaintainer { && android.multiuser.Flags.supportAutolockForPrivateSpace() && android.multiuser.Flags.enablePrivateSpaceFeatures(); } + + /** {@link BroadcastReceiver} which handles the private profile's availability related + * broadcasts. + */ + private final class ProfileAvailabilityBroadcastReceiver extends BroadcastReceiver { + void register() { + Log.d(TAG, "Registering the receiver"); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE); + mContext.registerReceiver(/* receiver= */ this, filter, Context.RECEIVER_NOT_EXPORTED); + } + + void unregister() { + Log.d(TAG, "Unregistering the receiver"); + mContext.unregisterReceiver(/* receiver= */ this); + } + + @Override + public void onReceive(@NonNull Context context, @NonNull Intent intent) { + UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class); + if (!userHandle.equals(getPrivateProfileHandle())) { + Log.d(TAG, "Ignoring intent for non-private profile with user id " + + userHandle.getIdentifier()); + return; + } + + Log.i(TAG, "Removing all Settings tasks."); + removeSettingsAllTasks(); + } + } + + private synchronized void registerBroadcastReceiver() { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { + return; + } + var broadcastReceiver = getBroadcastReceiver(); + if (broadcastReceiver == null) { + return; + } + broadcastReceiver.register(); + } + + private synchronized void unregisterBroadcastReceiver() { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { + return; + } + if (mProfileAvailabilityBroadcastReceiver == null) { + Log.w(TAG, "Requested to unregister when there is no receiver."); + return; + } + mProfileAvailabilityBroadcastReceiver.unregister(); + mProfileAvailabilityBroadcastReceiver = null; + } + + /** Always use this getter to access {@link #mProfileAvailabilityBroadcastReceiver}. */ + @VisibleForTesting + @Nullable synchronized ProfileAvailabilityBroadcastReceiver getBroadcastReceiver() { + if (!android.os.Flags.allowPrivateProfile() + || !android.multiuser.Flags.enablePrivateSpaceFeatures()) { + return null; + } + if (!doesPrivateSpaceExist()) { + Log.e(TAG, "Cannot return a broadcast receiver when private space doesn't exist"); + return null; + } + if (mProfileAvailabilityBroadcastReceiver == null) { + mProfileAvailabilityBroadcastReceiver = new ProfileAvailabilityBroadcastReceiver(); + } + return mProfileAvailabilityBroadcastReceiver; + } + + /** This is purely for testing purpose only, and should not be used elsewhere. */ + @VisibleForTesting + synchronized void resetBroadcastReceiver() { + mProfileAvailabilityBroadcastReceiver = null; + } + + private void removeSettingsAllTasks() { + List appTasks = mActivityManager.getAppTasks(); + for (var appTask : appTasks) { + if (!appTask.getTaskInfo().isVisible()) { + appTask.finishAndRemoveTask(); + } + } + } } diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java index 50f67d3c55b..83a80bafa64 100644 --- a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java +++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java @@ -90,6 +90,7 @@ public class PrivateSpaceMaintainerTest { public void deletePrivateSpace_psDoesNotExist_returnsNoPSError() { PrivateSpaceMaintainer privateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.deletePrivateSpace(); ErrorDeletingPrivateSpace errorDeletingPrivateSpace = privateSpaceMaintainer.deletePrivateSpace(); assertThat(errorDeletingPrivateSpace) @@ -178,6 +179,30 @@ public class PrivateSpaceMaintainerTest { .isEqualTo(HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL); } + @Test + public void createPrivateSpace_psDoesNotExist_registersTheBroadcastReceiver() { + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + PrivateSpaceMaintainer privateSpaceMaintainer = + PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.deletePrivateSpace(); + privateSpaceMaintainer.createPrivateSpace(); + // test that no exception is thrown, which would indicate that the receiver was registered. + mContext.unregisterReceiver(privateSpaceMaintainer.getBroadcastReceiver()); + privateSpaceMaintainer.resetBroadcastReceiver(); + } + + @Test + public void deletePrivateSpace_psExists_unregistersTheBroadcastReceiver() { + mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE, + android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); + PrivateSpaceMaintainer privateSpaceMaintainer = + PrivateSpaceMaintainer.getInstance(mContext); + privateSpaceMaintainer.createPrivateSpace(); + privateSpaceMaintainer.deletePrivateSpace(); + assertThat(privateSpaceMaintainer.getBroadcastReceiver()).isNull(); + } + /** * Tests that {@link PrivateSpaceMaintainer#lockPrivateSpace()} when PS exists and is running * locks the private profile.