summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
author Joshua Trask <joshtrask@google.com> 2023-02-22 18:15:35 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-02-22 18:15:35 +0000
commit25c119f04c375740903779693520a45b506d35fa (patch)
tree5bf6303ba69a5c0cd139dd3165910545300cc832 /java/src
parentbff86f9daa724d016a4dc93a65f88e2eb1043dfe (diff)
parent9c1f0f80ee06bef63ab8a681aae0c1fed60e4d96 (diff)
Merge "Extract component for work-profile availability." into tm-qpr-dev
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java42
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java4
-rw-r--r--java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java12
-rw-r--r--java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java4
-rw-r--r--java/src/com/android/intentresolver/ResolverActivity.java134
-rw-r--r--java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java12
-rw-r--r--java/src/com/android/intentresolver/WorkProfileAvailabilityManager.java166
-rw-r--r--java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java13
8 files changed, 222 insertions, 165 deletions
diff --git a/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
index 17dbb8f2..e3f1b233 100644
--- a/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/AbstractMultiProfilePagerAdapter.java
@@ -40,6 +40,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.function.Supplier;
/**
* Skeletal {@link PagerAdapter} implementation of a work or personal profile page for
@@ -61,22 +62,20 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
private Set<Integer> mLoadedPages;
private final EmptyStateProvider mEmptyStateProvider;
private final UserHandle mWorkProfileUserHandle;
- private final QuietModeManager mQuietModeManager;
+ private final Supplier<Boolean> mWorkProfileQuietModeChecker; // True when work is quiet.
- AbstractMultiProfilePagerAdapter(Context context, int currentPage,
+ AbstractMultiProfilePagerAdapter(
+ Context context,
+ int currentPage,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
UserHandle workProfileUserHandle) {
mContext = Objects.requireNonNull(context);
mCurrentPage = currentPage;
mLoadedPages = new HashSet<>();
mWorkProfileUserHandle = workProfileUserHandle;
mEmptyStateProvider = emptyStateProvider;
- mQuietModeManager = quietModeManager;
- }
-
- private boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
- return mQuietModeManager.isQuietModeEnabled(workProfileUserHandle);
+ mWorkProfileQuietModeChecker = workProfileQuietModeChecker;
}
void setOnProfileSelectedListener(OnProfileSelectedListener listener) {
@@ -433,7 +432,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
int count = listAdapter.getUnfilteredCount();
return (count == 0 && listAdapter.getPlaceholderCount() == 0)
|| (listAdapter.getUserHandle().equals(mWorkProfileUserHandle)
- && isQuietModeEnabled(mWorkProfileUserHandle));
+ && mWorkProfileQuietModeChecker.get());
}
protected static class ProfileDescriptor {
@@ -573,29 +572,4 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
*/
void onSwitchOnWorkSelected();
}
-
- /**
- * Describes an injector to be used for cross profile functionality. Overridable for testing.
- */
- public interface QuietModeManager {
- /**
- * Returns whether the given profile is in quiet mode or not.
- */
- boolean isQuietModeEnabled(UserHandle workProfileUserHandle);
-
- /**
- * Enables or disables quiet mode for a managed profile.
- */
- void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle);
-
- /**
- * Should be called when the work profile enabled broadcast received
- */
- void markWorkProfileEnabledBroadcastReceived();
-
- /**
- * Returns true if enabling of work profile is in progress
- */
- boolean isWaitingToEnableWorkProfile();
- }
}
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 65c72fda..72336e84 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -543,7 +543,7 @@ public class ChooserActivity extends ResolverActivity implements
/* context */ this,
adapter,
createEmptyStateProvider(/* workProfileUserHandle= */ null),
- mQuietModeManager,
+ /* workProfileQuietModeChecker= */ () -> false,
/* workProfileUserHandle= */ null,
mMaxTargetsPerRow);
}
@@ -572,7 +572,7 @@ public class ChooserActivity extends ResolverActivity implements
personalAdapter,
workAdapter,
createEmptyStateProvider(/* workProfileUserHandle= */ getWorkProfileUserHandle()),
- mQuietModeManager,
+ () -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
getWorkProfileUserHandle(),
mMaxTargetsPerRow);
diff --git a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
index 39d1fab0..3e2ea473 100644
--- a/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserMultiProfilePagerAdapter.java
@@ -48,7 +48,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
Context context,
ChooserGridAdapter adapter,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
UserHandle workProfileUserHandle,
int maxTargetsPerRow) {
this(
@@ -56,7 +56,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
new ChooserProfileAdapterBinder(maxTargetsPerRow),
ImmutableList.of(adapter),
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
/* defaultProfile= */ 0,
workProfileUserHandle,
new BottomPaddingOverrideSupplier(context));
@@ -67,7 +67,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
ChooserGridAdapter personalAdapter,
ChooserGridAdapter workAdapter,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
int maxTargetsPerRow) {
@@ -76,7 +76,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
new ChooserProfileAdapterBinder(maxTargetsPerRow),
ImmutableList.of(personalAdapter, workAdapter),
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
new BottomPaddingOverrideSupplier(context));
@@ -87,7 +87,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
ChooserProfileAdapterBinder adapterBinder,
ImmutableList<ChooserGridAdapter> gridAdapters,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) {
@@ -97,7 +97,7 @@ public class ChooserMultiProfilePagerAdapter extends GenericMultiProfilePagerAda
adapterBinder,
gridAdapters,
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
() -> makeProfileView(context),
diff --git a/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
index 9bbdf7c7..7613f35f 100644
--- a/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/GenericMultiProfilePagerAdapter.java
@@ -81,7 +81,7 @@ class GenericMultiProfilePagerAdapter<
AdapterBinder<PageViewT, SinglePageAdapterT> adapterBinder,
ImmutableList<SinglePageAdapterT> adapters,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
Supplier<ViewGroup> pageViewInflater,
@@ -90,7 +90,7 @@ class GenericMultiProfilePagerAdapter<
context,
/* currentPage= */ defaultProfile,
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
workProfileUserHandle);
mListAdapterExtractor = listAdapterExtractor;
diff --git a/java/src/com/android/intentresolver/ResolverActivity.java b/java/src/com/android/intentresolver/ResolverActivity.java
index ff436ed8..faccbc36 100644
--- a/java/src/com/android/intentresolver/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/ResolverActivity.java
@@ -44,7 +44,6 @@ import android.app.VoiceInteractor.PickOptionRequest.Option;
import android.app.VoiceInteractor.Prompt;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -61,7 +60,6 @@ import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.PatternMatcher;
@@ -105,7 +103,6 @@ import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStatePro
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.Profile;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.QuietModeManager;
import com.android.intentresolver.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
import com.android.intentresolver.chooser.DisplayResolveInfo;
import com.android.intentresolver.chooser.TargetInfo;
@@ -191,7 +188,7 @@ public class ResolverActivity extends FragmentActivity implements
@VisibleForTesting
protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter;
- protected QuietModeManager mQuietModeManager;
+ protected WorkProfileAvailabilityManager mWorkProfileAvailability;
// Intent extra for connected audio devices
public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
@@ -219,7 +216,6 @@ public class ResolverActivity extends FragmentActivity implements
protected static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
protected static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
- private BroadcastReceiver mWorkProfileStateReceiver;
private UserHandle mHeaderCreatorUser;
// User handle annotations are lazy-initialized to ensure that they're computed exactly once
@@ -357,8 +353,6 @@ public class ResolverActivity extends FragmentActivity implements
setTheme(appliedThemeResId());
super.onCreate(savedInstanceState);
- mQuietModeManager = createQuietModeManager();
-
// Determine whether we should show that intent is forwarded
// from managed profile to owner or other way around.
setProfileSwitchMessage(intent.getContentUserHint());
@@ -367,6 +361,8 @@ public class ResolverActivity extends FragmentActivity implements
// associated TODO comment to explain why this is structured as a lazy computation.)
AnnotatedUserHandles unusedReferenceToHandles = mLazyAnnotatedUserHandles.get();
+ mWorkProfileAvailability = createWorkProfileAvailabilityManager();
+
mPm = getPackageManager();
mReferrerPackage = getReferrerPackageName();
@@ -593,10 +589,8 @@ public class ResolverActivity extends FragmentActivity implements
finish();
}
}
- if (mWorkPackageMonitor != null) {
- unregisterReceiver(mWorkProfileStateReceiver);
- mWorkPackageMonitor = null;
- }
+ // TODO: should we clean up the work-profile manager before we potentially finish() above?
+ mWorkProfileAvailability.unregisterWorkProfileStateReceiver(this);
}
@Override
@@ -950,7 +944,7 @@ public class ResolverActivity extends FragmentActivity implements
public void onHandlePackagesChanged(ResolverListAdapter listAdapter) {
if (listAdapter == mMultiProfilePagerAdapter.getActiveListAdapter()) {
if (listAdapter.getUserHandle().equals(getWorkProfileUserHandle())
- && mQuietModeManager.isWaitingToEnableWorkProfile()) {
+ && mWorkProfileAvailability.isWaitingToEnableWorkProfile()) {
// We have just turned on the work profile and entered the pass code to start it,
// now we are waiting to receive the ACTION_USER_UNLOCKED broadcast. There is no
// point in reloading the list now, since the work profile user is still
@@ -988,35 +982,19 @@ public class ResolverActivity extends FragmentActivity implements
// @NonFinalForTesting
@VisibleForTesting
- protected QuietModeManager createQuietModeManager() {
- UserManager userManager = getSystemService(UserManager.class);
- return new QuietModeManager() {
-
- private boolean mIsWaitingToEnableWorkProfile = false;
-
- @Override
- public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
- return userManager.isQuietModeEnabled(workProfileUserHandle);
- }
-
- @Override
- public void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle) {
- AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
- userManager.requestQuietModeEnabled(enabled, workProfileUserHandle);
+ protected WorkProfileAvailabilityManager createWorkProfileAvailabilityManager() {
+ final UserHandle workUser = getWorkProfileUserHandle();
+
+ return new WorkProfileAvailabilityManager(
+ getSystemService(UserManager.class),
+ workUser,
+ () -> {
+ if (mMultiProfilePagerAdapter.getCurrentUserHandle().equals(workUser)) {
+ mMultiProfilePagerAdapter.rebuildActiveTab(true);
+ } else {
+ mMultiProfilePagerAdapter.clearInactiveProfileCache();
+ }
});
- mIsWaitingToEnableWorkProfile = true;
- }
-
- @Override
- public void markWorkProfileEnabledBroadcastReceived() {
- mIsWaitingToEnableWorkProfile = false;
- }
-
- @Override
- public boolean isWaitingToEnableWorkProfile() {
- return mIsWaitingToEnableWorkProfile;
- }
- };
}
// TODO: have tests override `getAnnotatedUserHandles()`, and make this method `final`.
@@ -1083,7 +1061,7 @@ public class ResolverActivity extends FragmentActivity implements
final EmptyStateProvider workProfileOffEmptyStateProvider =
new WorkProfilePausedEmptyStateProvider(this, workProfileUserHandle,
- mQuietModeManager,
+ mWorkProfileAvailability,
/* onSwitchOnWorkSelectedListener= */
() -> {
if (mOnSwitchOnWorkSelectedListener != null) {
@@ -1141,12 +1119,11 @@ public class ResolverActivity extends FragmentActivity implements
rList,
filterLastUsed,
/* userHandle */ UserHandle.of(UserHandle.myUserId()));
- QuietModeManager quietModeManager = createQuietModeManager();
return new ResolverMultiProfilePagerAdapter(
/* context */ this,
adapter,
createEmptyStateProvider(/* workProfileUserHandle= */ null),
- quietModeManager,
+ /* workProfileQuietModeChecker= */ () -> false,
/* workProfileUserHandle= */ null);
}
@@ -1197,13 +1174,12 @@ public class ResolverActivity extends FragmentActivity implements
(filterLastUsed && UserHandle.myUserId()
== workProfileUserHandle.getIdentifier()),
/* userHandle */ workProfileUserHandle);
- QuietModeManager quietModeManager = createQuietModeManager();
return new ResolverMultiProfilePagerAdapter(
/* context */ this,
personalAdapter,
workAdapter,
createEmptyStateProvider(getWorkProfileUserHandle()),
- quietModeManager,
+ () -> mWorkProfileAvailability.isQuietModeEnabled(),
selectedProfile,
getWorkProfileUserHandle());
}
@@ -1441,9 +1417,9 @@ public class ResolverActivity extends FragmentActivity implements
}
mRegistered = true;
}
- if (shouldShowTabs() && mQuietModeManager.isWaitingToEnableWorkProfile()) {
- if (mQuietModeManager.isQuietModeEnabled(getWorkProfileUserHandle())) {
- mQuietModeManager.markWorkProfileEnabledBroadcastReceived();
+ if (shouldShowTabs() && mWorkProfileAvailability.isWaitingToEnableWorkProfile()) {
+ if (mWorkProfileAvailability.isQuietModeEnabled()) {
+ mWorkProfileAvailability.markWorkProfileEnabledBroadcastReceived();
}
}
mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
@@ -1456,29 +1432,10 @@ public class ResolverActivity extends FragmentActivity implements
this.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
if (shouldShowTabs()) {
- mWorkProfileStateReceiver = createWorkProfileStateReceiver();
- registerWorkProfileStateReceiver();
-
- mWorkProfileHasBeenEnabled = isWorkProfileEnabled();
+ mWorkProfileAvailability.registerWorkProfileStateReceiver(this);
}
}
- private boolean isWorkProfileEnabled() {
- UserHandle workUserHandle = getWorkProfileUserHandle();
- UserManager userManager = getSystemService(UserManager.class);
-
- return !userManager.isQuietModeEnabled(workUserHandle)
- && userManager.isUserUnlocked(workUserHandle);
- }
-
- private void registerWorkProfileStateReceiver() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- registerReceiverAsUser(mWorkProfileStateReceiver, UserHandle.ALL, filter, null, null);
- }
-
@Override
protected final void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -2248,45 +2205,6 @@ public class ResolverActivity extends FragmentActivity implements
return mMultiProfilePagerAdapter.getInactiveListAdapter().getCount() > 0;
}
- private BroadcastReceiver createWorkProfileStateReceiver() {
- return new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (!TextUtils.equals(action, Intent.ACTION_USER_UNLOCKED)
- && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_AVAILABLE)) {
- return;
- }
-
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-
- if (userId != getWorkProfileUserHandle().getIdentifier()) {
- return;
- }
-
- if (isWorkProfileEnabled()) {
- if (mWorkProfileHasBeenEnabled) {
- return;
- }
-
- mWorkProfileHasBeenEnabled = true;
- mQuietModeManager.markWorkProfileEnabledBroadcastReceived();
- } else {
- // Must be an UNAVAILABLE broadcast, so we watch for the next availability
- mWorkProfileHasBeenEnabled = false;
- }
-
- if (mMultiProfilePagerAdapter.getCurrentUserHandle()
- .equals(getWorkProfileUserHandle())) {
- mMultiProfilePagerAdapter.rebuildActiveTab(true);
- } else {
- mMultiProfilePagerAdapter.clearInactiveProfileCache();
- }
- }
- };
- }
-
public static final class ResolvedComponentInfo {
public final ComponentName name;
private final List<Intent> mIntents = new ArrayList<>();
@@ -2439,4 +2357,4 @@ public class ResolverActivity extends FragmentActivity implements
}
}
}
-} \ No newline at end of file
+}
diff --git a/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
index 65de9409..48e3b62d 100644
--- a/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/ResolverMultiProfilePagerAdapter.java
@@ -43,13 +43,13 @@ public class ResolverMultiProfilePagerAdapter extends
Context context,
ResolverListAdapter adapter,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
UserHandle workProfileUserHandle) {
this(
context,
ImmutableList.of(adapter),
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
/* defaultProfile= */ 0,
workProfileUserHandle,
new BottomPaddingOverrideSupplier());
@@ -59,14 +59,14 @@ public class ResolverMultiProfilePagerAdapter extends
ResolverListAdapter personalAdapter,
ResolverListAdapter workAdapter,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle) {
this(
context,
ImmutableList.of(personalAdapter, workAdapter),
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
new BottomPaddingOverrideSupplier());
@@ -76,7 +76,7 @@ public class ResolverMultiProfilePagerAdapter extends
Context context,
ImmutableList<ResolverListAdapter> listAdapters,
EmptyStateProvider emptyStateProvider,
- QuietModeManager quietModeManager,
+ Supplier<Boolean> workProfileQuietModeChecker,
@Profile int defaultProfile,
UserHandle workProfileUserHandle,
BottomPaddingOverrideSupplier bottomPaddingOverrideSupplier) {
@@ -86,7 +86,7 @@ public class ResolverMultiProfilePagerAdapter extends
(listView, bindAdapter) -> listView.setAdapter(bindAdapter),
listAdapters,
emptyStateProvider,
- quietModeManager,
+ workProfileQuietModeChecker,
defaultProfile,
workProfileUserHandle,
() -> (ViewGroup) LayoutInflater.from(context).inflate(
diff --git a/java/src/com/android/intentresolver/WorkProfileAvailabilityManager.java b/java/src/com/android/intentresolver/WorkProfileAvailabilityManager.java
new file mode 100644
index 00000000..6e51520b
--- /dev/null
+++ b/java/src/com/android/intentresolver/WorkProfileAvailabilityManager.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2023 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 com.android.intentresolver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+
+import androidx.annotation.VisibleForTesting;
+
+/** Monitor for runtime conditions that may disable work profile display. */
+public class WorkProfileAvailabilityManager {
+ private final UserManager mUserManager;
+ private final UserHandle mWorkProfileUserHandle;
+ private final Runnable mOnWorkProfileStateUpdated;
+
+ private BroadcastReceiver mWorkProfileStateReceiver;
+
+ private boolean mIsWaitingToEnableWorkProfile;
+ private boolean mWorkProfileHasBeenEnabled;
+
+ public WorkProfileAvailabilityManager(
+ UserManager userManager,
+ UserHandle workProfileUserHandle,
+ Runnable onWorkProfileStateUpdated) {
+ mUserManager = userManager;
+ mWorkProfileUserHandle = workProfileUserHandle;
+ mWorkProfileHasBeenEnabled = isWorkProfileEnabled();
+ mOnWorkProfileStateUpdated = onWorkProfileStateUpdated;
+ }
+
+ /**
+ * Register a {@link BroadcastReceiver}, if we haven't already, to be notified about work
+ * profile availability changes.
+ *
+ * TODO: this takes the context for testing, because we don't have a context on hand when we
+ * set up this component's default "override" in {@link ChooserActivityOverrideData#reset()}.
+ * The use of these overrides in our testing design is questionable and can hopefully be
+ * improved someday; then this context should be injected in our constructor & held as `final`.
+ *
+ * TODO: consider injecting an optional `Lifecycle` so that this component can automatically
+ * manage its own registration/unregistration. (This would be optional because registration of
+ * the receiver is conditional on having `shouldShowTabs()` in our session.)
+ */
+ public void registerWorkProfileStateReceiver(Context context) {
+ if (mWorkProfileStateReceiver != null) {
+ return;
+ }
+ mWorkProfileStateReceiver = createWorkProfileStateReceiver();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ context.registerReceiverAsUser(
+ mWorkProfileStateReceiver, UserHandle.ALL, filter, null, null);
+ }
+
+ /**
+ * Unregister any {@link BroadcastReceiver} currently waiting for a work-enabled broadcast.
+ *
+ * TODO: this takes the context for testing, because we don't have a context on hand when we
+ * set up this component's default "override" in {@link ChooserActivityOverrideData#reset()}.
+ * The use of these overrides in our testing design is questionable and can hopefully be
+ * improved someday; then this context should be injected in our constructor & held as `final`.
+ */
+ public void unregisterWorkProfileStateReceiver(Context context) {
+ if (mWorkProfileStateReceiver == null) {
+ return;
+ }
+ context.unregisterReceiver(mWorkProfileStateReceiver);
+ mWorkProfileStateReceiver = null;
+ }
+
+ public boolean isQuietModeEnabled() {
+ return mUserManager.isQuietModeEnabled(mWorkProfileUserHandle);
+ }
+
+ // TODO: why do clients only care about the result of `isQuietModeEnabled()`, even though
+ // internally (in `isWorkProfileEnabled()`) we also check this 'unlocked' condition?
+ @VisibleForTesting
+ public boolean isWorkProfileUserUnlocked() {
+ return mUserManager.isUserUnlocked(mWorkProfileUserHandle);
+ }
+
+ /**
+ * Request that quiet mode be enabled (or disabled) for the work profile.
+ * TODO: this is only used to disable quiet mode; should that be hard-coded?
+ */
+ public void requestQuietModeEnabled(boolean enabled) {
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(
+ () -> mUserManager.requestQuietModeEnabled(enabled, mWorkProfileUserHandle));
+ mIsWaitingToEnableWorkProfile = true;
+ }
+
+ /**
+ * Stop waiting for a work-enabled broadcast.
+ * TODO: this seems strangely low-level to include as part of the public API. Maybe some
+ * responsibilities need to be pulled over from the client?
+ */
+ public void markWorkProfileEnabledBroadcastReceived() {
+ mIsWaitingToEnableWorkProfile = false;
+ }
+
+ public boolean isWaitingToEnableWorkProfile() {
+ return mIsWaitingToEnableWorkProfile;
+ }
+
+ private boolean isWorkProfileEnabled() {
+ return (mWorkProfileUserHandle != null)
+ && !isQuietModeEnabled()
+ && isWorkProfileUserUnlocked();
+ }
+
+ private BroadcastReceiver createWorkProfileStateReceiver() {
+ return new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (!TextUtils.equals(action, Intent.ACTION_USER_UNLOCKED)
+ && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
+ && !TextUtils.equals(action, Intent.ACTION_MANAGED_PROFILE_AVAILABLE)) {
+ return;
+ }
+
+ if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
+ != mWorkProfileUserHandle.getIdentifier()) {
+ return;
+ }
+
+ if (isWorkProfileEnabled()) {
+ if (mWorkProfileHasBeenEnabled) {
+ return;
+ }
+ mWorkProfileHasBeenEnabled = true;
+ mIsWaitingToEnableWorkProfile = false;
+ } else {
+ // Must be an UNAVAILABLE broadcast, so we watch for the next availability.
+ // TODO: confirm the above reasoning (& handling of "UNAVAILABLE" in general).
+ mWorkProfileHasBeenEnabled = false;
+ }
+
+ mOnWorkProfileStateUpdated.run();
+ }
+ };
+ }
+}
diff --git a/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java b/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
index b7c89907..0333039b 100644
--- a/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
+++ b/java/src/com/android/intentresolver/WorkProfilePausedEmptyStateProvider.java
@@ -26,11 +26,10 @@ import android.content.Context;
import android.os.UserHandle;
import android.stats.devicepolicy.nano.DevicePolicyEnums;
-import com.android.internal.R;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
import com.android.intentresolver.AbstractMultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.QuietModeManager;
+import com.android.internal.R;
/**
* Chooser/ResolverActivity empty state provider that returns empty state which is shown when
@@ -39,19 +38,19 @@ import com.android.intentresolver.AbstractMultiProfilePagerAdapter.QuietModeMana
public class WorkProfilePausedEmptyStateProvider implements EmptyStateProvider {
private final UserHandle mWorkProfileUserHandle;
- private final QuietModeManager mQuietModeManager;
+ private final WorkProfileAvailabilityManager mWorkProfileAvailability;
private final String mMetricsCategory;
private final OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
private final Context mContext;
public WorkProfilePausedEmptyStateProvider(@NonNull Context context,
@Nullable UserHandle workProfileUserHandle,
- @NonNull QuietModeManager quietModeManager,
+ @NonNull WorkProfileAvailabilityManager workProfileAvailability,
@Nullable OnSwitchOnWorkSelectedListener onSwitchOnWorkSelectedListener,
@NonNull String metricsCategory) {
mContext = context;
mWorkProfileUserHandle = workProfileUserHandle;
- mQuietModeManager = quietModeManager;
+ mWorkProfileAvailability = workProfileAvailability;
mMetricsCategory = metricsCategory;
mOnSwitchOnWorkSelectedListener = onSwitchOnWorkSelectedListener;
}
@@ -60,7 +59,7 @@ public class WorkProfilePausedEmptyStateProvider implements EmptyStateProvider {
@Override
public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
if (!resolverListAdapter.getUserHandle().equals(mWorkProfileUserHandle)
- || !mQuietModeManager.isQuietModeEnabled(mWorkProfileUserHandle)
+ || !mWorkProfileAvailability.isQuietModeEnabled()
|| resolverListAdapter.getCount() == 0) {
return null;
}
@@ -74,7 +73,7 @@ public class WorkProfilePausedEmptyStateProvider implements EmptyStateProvider {
if (mOnSwitchOnWorkSelectedListener != null) {
mOnSwitchOnWorkSelectedListener.onSwitchOnWorkSelected();
}
- mQuietModeManager.requestQuietModeEnabled(false, mWorkProfileUserHandle);
+ mWorkProfileAvailability.requestQuietModeEnabled(false);
}, mMetricsCategory);
}