mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-17 17:48:20 +00:00
Merge "Adding suport for Private Space QsTile fulfillment." into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
7b1858cbf2
@@ -260,7 +260,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
|
||||
if (Flags.enablePrivateSpace()) {
|
||||
mPrivateSpaceHeaderViewController =
|
||||
new PrivateSpaceHeaderViewController(mPrivateProfileManager);
|
||||
new PrivateSpaceHeaderViewController(this, mPrivateProfileManager);
|
||||
}
|
||||
|
||||
mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
|
||||
@@ -980,6 +980,11 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
return mWorkManager;
|
||||
}
|
||||
|
||||
/** Returns whether Private Profile has been setup. */
|
||||
public boolean hasPrivateProfile() {
|
||||
return mHasPrivateApps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceProfileChanged(DeviceProfile dp) {
|
||||
for (AdapterHolder holder : mAH) {
|
||||
|
||||
@@ -325,10 +325,6 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
|
||||
mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems);
|
||||
position++;
|
||||
addAppsWithSections(mPrivateApps, position);
|
||||
if (mActivityContext.getAppsView() != null) {
|
||||
mActivityContext.getAppsView().getActiveRecyclerView()
|
||||
.scrollToBottomWithMotion();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
|
||||
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
|
||||
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
|
||||
|
||||
@@ -34,7 +35,6 @@ import android.os.UserManager;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.BuildConfig;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
@@ -59,11 +59,11 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER;
|
||||
private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key";
|
||||
private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
|
||||
private static final int ANIMATION_DURATION = 2000;
|
||||
private final ActivityAllAppsContainerView<?> mAllApps;
|
||||
private final Predicate<UserHandle> mPrivateProfileMatcher;
|
||||
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
|
||||
private boolean mPrivateSpaceSettingsAvailable;
|
||||
private Runnable mUnlockRunnable;
|
||||
|
||||
public PrivateProfileManager(UserManager userManager,
|
||||
ActivityAllAppsContainerView<?> allApps,
|
||||
@@ -115,9 +115,17 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
|
||||
}
|
||||
|
||||
/** Disables quiet mode for Private Space User Profile. */
|
||||
public void unlockPrivateProfile() {
|
||||
/**
|
||||
* Disables quiet mode for Private Space User Profile.
|
||||
* The runnable passed will be executed in the {@link #reset()} method,
|
||||
* when Launcher receives update about profile availability.
|
||||
* The runnable passed is only executed once, and reset after execution.
|
||||
* In case the method is called again, before the previously set runnable was executed,
|
||||
* the runnable will be updated.
|
||||
*/
|
||||
public void unlockPrivateProfile(Runnable runnable) {
|
||||
enableQuietMode(false);
|
||||
mUnlockRunnable = runnable;
|
||||
}
|
||||
|
||||
/** Enables quiet mode for Private Space User Profile. */
|
||||
@@ -133,11 +141,15 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
|
||||
/** Resets the current state of Private Profile, w.r.t. to Launcher. */
|
||||
public void reset() {
|
||||
int previousState = getCurrentState();
|
||||
boolean isEnabled = !mAllApps.getAppsStore()
|
||||
.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
|
||||
int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
|
||||
setCurrentState(updatedState);
|
||||
resetPrivateSpaceDecorator(updatedState);
|
||||
if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
|
||||
applyUnlockRunnable();
|
||||
}
|
||||
}
|
||||
|
||||
/** Opens the Private Space Settings Entry Point. */
|
||||
@@ -182,13 +194,6 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
}
|
||||
// Add Private Space Decorator to the Recycler view.
|
||||
mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
|
||||
if (Flags.privateSpaceAnimation() && mAllApps.getActiveRecyclerView()
|
||||
== mainAdapterHolder.mRecyclerView) {
|
||||
RecyclerViewAnimationController recyclerViewAnimationController =
|
||||
new RecyclerViewAnimationController(mAllApps);
|
||||
recyclerViewAnimationController.animateToState(true /* expand */,
|
||||
ANIMATION_DURATION, () -> {});
|
||||
}
|
||||
} else {
|
||||
// Remove Private Space Decorator from the Recycler view.
|
||||
if (mPrivateAppsSectionDecorator != null) {
|
||||
@@ -202,6 +207,18 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
setQuietMode(enable);
|
||||
}
|
||||
|
||||
void applyUnlockRunnable() {
|
||||
if (mUnlockRunnable != null) {
|
||||
// reset the runnable to prevent re-execution.
|
||||
MAIN_EXECUTOR.post(mUnlockRunnable);
|
||||
mUnlockRunnable = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
|
||||
return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<UserHandle> getUserMatcher() {
|
||||
return mPrivateProfileMatcher;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
|
||||
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
|
||||
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
|
||||
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
|
||||
@@ -28,6 +29,7 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
|
||||
|
||||
@@ -36,9 +38,13 @@ import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
|
||||
* {@link UserProfileState}
|
||||
*/
|
||||
public class PrivateSpaceHeaderViewController {
|
||||
private static final int ANIMATION_DURATION = 2000;
|
||||
private final ActivityAllAppsContainerView mAllApps;
|
||||
private final PrivateProfileManager mPrivateProfileManager;
|
||||
|
||||
public PrivateSpaceHeaderViewController(PrivateProfileManager privateProfileManager) {
|
||||
public PrivateSpaceHeaderViewController(ActivityAllAppsContainerView allApps,
|
||||
PrivateProfileManager privateProfileManager) {
|
||||
this.mAllApps = allApps;
|
||||
this.mPrivateProfileManager = privateProfileManager;
|
||||
}
|
||||
|
||||
@@ -77,7 +83,8 @@ public class PrivateSpaceHeaderViewController {
|
||||
quietModeButton.setOnClickListener(
|
||||
view -> {
|
||||
mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
|
||||
mPrivateProfileManager.unlockPrivateProfile();
|
||||
mPrivateProfileManager.unlockPrivateProfile((this::
|
||||
onPrivateProfileUnlocked));
|
||||
});
|
||||
}
|
||||
default -> quietModeButton.setVisibility(View.GONE);
|
||||
@@ -106,6 +113,21 @@ public class PrivateSpaceHeaderViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private void onPrivateProfileUnlocked() {
|
||||
// If we are on main adapter view, we apply the PS Container expansion animation and
|
||||
// then scroll down to load the entire container, making animation visible.
|
||||
ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder =
|
||||
(ActivityAllAppsContainerView<?>.AdapterHolder) mAllApps.mAH.get(MAIN);
|
||||
if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
|
||||
&& mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
|
||||
RecyclerViewAnimationController recyclerViewAnimationController =
|
||||
new RecyclerViewAnimationController(mAllApps);
|
||||
recyclerViewAnimationController.animateToState(true /* expand */,
|
||||
ANIMATION_DURATION, () -> {});
|
||||
mAllApps.getActiveRecyclerView().scrollToBottomWithMotion();
|
||||
}
|
||||
}
|
||||
|
||||
PrivateProfileManager getPrivateProfileManager() {
|
||||
return mPrivateProfileManager;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
@@ -89,7 +88,6 @@ public abstract class UserProfileManager {
|
||||
}
|
||||
|
||||
/** Returns current state for the profile type. */
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
|
||||
public int getCurrentState() {
|
||||
return mCurrentState;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PRO
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
@@ -81,6 +82,8 @@ public class PrivateProfileManagerTest {
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
private boolean mRunnableCalled = false;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -110,7 +113,7 @@ public class PrivateProfileManagerTest {
|
||||
public void unlockPrivateProfile_requestsQuietModeAsFalse() throws Exception {
|
||||
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(true);
|
||||
|
||||
mPrivateProfileManager.unlockPrivateProfile();
|
||||
mPrivateProfileManager.unlockPrivateProfile(() -> {});
|
||||
|
||||
awaitTasksCompleted();
|
||||
Mockito.verify(mUserManager).requestQuietModeEnabled(false, PRIVATE_HANDLE);
|
||||
@@ -132,6 +135,23 @@ public class PrivateProfileManagerTest {
|
||||
assertEquals(STATE_DISABLED, privateProfileManager.getCurrentState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transitioningToUnlocked_resetCallsPendingRunnable() throws Exception {
|
||||
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
|
||||
doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
|
||||
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
|
||||
.thenReturn(false);
|
||||
when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
|
||||
mRunnableCalled = false;
|
||||
|
||||
privateProfileManager.unlockPrivateProfile(this::testRunnable);
|
||||
privateProfileManager.reset();
|
||||
|
||||
awaitTasksCompleted();
|
||||
Mockito.verify(privateProfileManager).applyUnlockRunnable();
|
||||
assertTrue(mRunnableCalled);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void openPrivateSpaceSettings_triggersSecurityAndPrivacyIntent() {
|
||||
Intent expectedIntent = new Intent(SAFETY_CENTER_INTENT);
|
||||
@@ -150,4 +170,8 @@ public class PrivateProfileManagerTest {
|
||||
private static void awaitTasksCompleted() throws Exception {
|
||||
UI_HELPER_EXECUTOR.submit(() -> null).get();
|
||||
}
|
||||
|
||||
private void testRunnable() {
|
||||
mRunnableCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,13 +64,16 @@ public class PrivateSpaceHeaderViewControllerTest {
|
||||
private RelativeLayout mPsHeaderLayout;
|
||||
@Mock
|
||||
private PrivateProfileManager mPrivateProfileManager;
|
||||
@Mock
|
||||
private ActivityAllAppsContainerView mAllApps;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = new ActivityContextWrapper(getApplicationContext());
|
||||
mLayoutInflater = LayoutInflater.from(getApplicationContext());
|
||||
mPsHeaderViewController = new PrivateSpaceHeaderViewController(mPrivateProfileManager);
|
||||
mPsHeaderViewController = new PrivateSpaceHeaderViewController(mAllApps,
|
||||
mPrivateProfileManager);
|
||||
mPsHeaderLayout = (RelativeLayout) mLayoutInflater.inflate(R.layout.private_space_header,
|
||||
null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user