From 676fc201538b1e8b64288488ca83acde4b151e95 Mon Sep 17 00:00:00 2001 From: Anna Zhuravleva Date: Mon, 15 Apr 2024 10:59:39 +0000 Subject: Block taking recents screenshot if private profile available DocsUI shows separate tab when private profile is on. User can move DocUI to the background and then lock private profile. Recents preview screen shows screenshot of the DocUI at the last moment it was in foreground (when the space was unlocked). As a result Recents preview can leak whether private profile exists on device. This change sets setting to show blank screen in the recents when private profile is avaialble. Bug: 329241706 Test: manual, https://b.corp.google.com/issues/329241706#comment3 Change-Id: I05914391db7bd15a88c6043d14265682ffd8437c --- src/com/android/documentsui/BaseActivity.java | 26 ++++++++++++++++++ src/com/android/documentsui/UserManagerState.java | 31 +++++++++++++++++++--- .../documentsui/dirlist/DirectoryFragment.java | 11 +++++--- .../android/documentsui/TestUserManagerState.java | 5 ++++ 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java index 9e38303e1..514e98f23 100644 --- a/src/com/android/documentsui/BaseActivity.java +++ b/src/com/android/documentsui/BaseActivity.java @@ -75,6 +75,7 @@ import com.android.documentsui.roots.ProvidersCache; import com.android.documentsui.sidebar.RootsFragment; import com.android.documentsui.sorting.SortController; import com.android.documentsui.sorting.SortModel; +import com.android.modules.utils.build.SdkLevel; import com.google.android.material.appbar.AppBarLayout; @@ -376,6 +377,7 @@ public abstract class BaseActivity // Base classes must update result in their onCreate. setResult(AppCompatActivity.RESULT_CANCELED); + updateRecentsSetting(); } private NavigationViewManager getNavigationViewManager(Breadcrumb breadcrumb, @@ -1046,4 +1048,28 @@ public abstract class BaseActivity */ void onDirectoryLoaded(@Nullable Uri uri); } + + /** + * Updates the Recents preview settings based on presence of hidden profiles. Used not to leak + * Private profile existence when it was locked after the app was moved to the Recents. + */ + public void updateRecentsSetting() { + if (!SdkLevel.isAtLeastV()) { + return; + } + + if (mUserManagerState == null) { + Log.e(TAG, "Can't update Recents screenshot setting: User manager state is null."); + return; + } + + if (DEBUG) { + Log.d( + TAG, + "Set recents screenshot to " + + (!mUserManagerState.areHiddenInQuietModeProfilesPresent() ? "enabled" + : "disabled")); + } + setRecentsScreenshotEnabled(!mUserManagerState.areHiddenInQuietModeProfilesPresent()); + } } diff --git a/src/com/android/documentsui/UserManagerState.java b/src/com/android/documentsui/UserManagerState.java index eccc6b00c..2c2046cc4 100644 --- a/src/com/android/documentsui/UserManagerState.java +++ b/src/com/android/documentsui/UserManagerState.java @@ -89,8 +89,9 @@ public interface UserManagerState { * received in broadcast * * @param userId {@link UserId} for the profile for which the availability status changed - * @param action {@link Intent}.ACTION_PROFILE_UNAVAILABLE or - * {@link Intent}.ACTION_PROFILE_AVAILABLE + * @param action {@link Intent}.ACTION_PROFILE_UNAVAILABLE and {@link + * Intent}.ACTION_PROFILE_AVAILABLE, {@link Intent}.ACTION_PROFILE_ADDED} and {@link + * Intent}.ACTION_PROFILE_REMOVED} */ void onProfileActionStatusChange(String action, UserId userId); @@ -99,6 +100,9 @@ public interface UserManagerState { */ void setCurrentStateIntent(Intent intent); + /** Returns true if there are hidden profiles */ + boolean areHiddenInQuietModeProfilesPresent(); + /** * Creates an implementation of {@link UserManagerState}. */ @@ -235,11 +239,13 @@ public interface UserManagerState { if (userProperties.getShowInQuietMode() != UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { return; } - if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action)) { + if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action) + || Intent.ACTION_PROFILE_REMOVED.equals(action)) { synchronized (mUserIds) { mUserIds.remove(userId); } - } else if (Intent.ACTION_PROFILE_AVAILABLE.equals(action)) { + } else if (Intent.ACTION_PROFILE_AVAILABLE.equals(action) + || Intent.ACTION_PROFILE_ADDED.equals(action)) { synchronized (mUserIds) { if (!mUserIds.contains(userId)) { mUserIds.add(userId); @@ -280,6 +286,23 @@ public interface UserManagerState { mCurrentStateIntent = intent; } + @Override + public boolean areHiddenInQuietModeProfilesPresent() { + if (!SdkLevel.isAtLeastV()) { + return false; + } + + for (UserId userId : getUserIds()) { + if (mUserManager + .getUserProperties(UserHandle.of(userId.getIdentifier())) + .getShowInQuietMode() + == UserProperties.SHOW_IN_QUIET_MODE_HIDDEN) { + return true; + } + } + return false; + } + private List getUserIdsInternal() { final List result = new ArrayList<>(); diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java index bf54e25fd..430540610 100644 --- a/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -262,8 +262,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On if (userProperties.getShowInQuietMode() == UserProperties.SHOW_IN_QUIET_MODE_PAUSED) { if (Objects.equal(mActivity.getSelectedUser(), userId)) { - // We only need to refresh the layout when the selected user is equal to the - // received profile user. + // We only need to refresh the layout when the selected user is equal to + // the received profile user. onPausedProfileStatusChange(action, userId); } return; @@ -308,6 +308,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On } private void onHiddenProfileStatusChange(String action, UserId userId) { + mActivity.updateRecentsSetting(); if (Intent.ACTION_PROFILE_UNAVAILABLE.equals(action)) { if (mProviderTestRunnable != null) { mHandler.removeCallbacks(mProviderTestRunnable); @@ -404,7 +405,9 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On private boolean isProfileStatusAction(String action) { if (!SdkLevel.isAtLeastV()) return isManagedProfileAction(action); return Intent.ACTION_PROFILE_AVAILABLE.equals(action) - || Intent.ACTION_PROFILE_UNAVAILABLE.equals(action); + || Intent.ACTION_PROFILE_UNAVAILABLE.equals(action) + || Intent.ACTION_PROFILE_ADDED.equals(action) + || Intent.ACTION_PROFILE_REMOVED.equals(action); } private static boolean isManagedProfileAction(String action) { @@ -642,6 +645,8 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On if (SdkLevel.isAtLeastV()) { filter.addAction(Intent.ACTION_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_PROFILE_UNAVAILABLE); + filter.addAction(Intent.ACTION_PROFILE_ADDED); + filter.addAction(Intent.ACTION_PROFILE_REMOVED); } // DocumentsApplication will resend the broadcast locally after roots are updated. // Register to a local broadcast manager to avoid this fragment from updating before diff --git a/tests/common/com/android/documentsui/TestUserManagerState.java b/tests/common/com/android/documentsui/TestUserManagerState.java index 5f41ce3e0..7b2ea8408 100644 --- a/tests/common/com/android/documentsui/TestUserManagerState.java +++ b/tests/common/com/android/documentsui/TestUserManagerState.java @@ -84,4 +84,9 @@ public class TestUserManagerState implements UserManagerState { @Override public void setCurrentStateIntent(Intent intent) { } + + @Override + public boolean areHiddenInQuietModeProfilesPresent() { + return false; + } } -- cgit v1.2.3-59-g8ed1b