mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-03 01:16:49 +00:00
Move adding views logic to privateProfileManager
- Have the animation happen according to the state of private space. - Have the transition happen only once by setting the current transition to null at the end of transition and by ensuring where the transitions are allowed. - Removing controller class. - The onClick controls the enablement of the profile. On reset (when getting the transition) is what controls the animation during expand. tldr- In the collapse case: execute() is called -> animation happens -> addPsHeader tldr- Expand case: post() is called -> addPsHeader -> animation happens. Collapse: onClick() -> AACV.onAppsUpdated() that resets & apply/RUNS runnable because EXECUTE -> AAList.onAppsUpdated() (which is called at the same time animating happens which we should cancel and do at end callback) -> AAList.onAppsUpdated() gets called again Expand: onCLick() -> AACV.onAppsUpdated() that resets & apply runnable -> AAList.onAppsUpdated() (no animation running) -> AAList.onAppsUpdated() (no animation running) -> addPrivateSpaceHeader -> then unlockAction() runnable because its posted at this point bug: 326206132 bug: 330444548 bug: 299294792 Test: manually locally and presubmit: https://screenshot.googleplex.com/9wavvwKQ8hY6oUw & https://screenshot.googleplex.com/BiqmidLFjPwS28j video: https://drive.google.com/file/d/1XGhmTncdUFtJj188_l7alGyyNz_fhXNw/view?usp=sharing Scrolling fix before: https://drive.google.com/file/d/1XykDm4UELoCvcwZdj8ZlJ6TszptB8W0W/view?usp=sharing scrolling fix after when not a lot of apps: https://drive.google.com/file/d/1Y4VY1eX7WE8ShSLXRrT56ieBdAuJo_zn/view?usp=sharing scrolling fix after with a lot of apps: https://drive.google.com/file/d/1Y58c-Z9xnU1GILp0Ih-oLORXYkMB-jWn/view?usp=sharing Flag: ACONFIG com.android.launcher3.Flags.private_space_animation Change-Id: I8d03ae60e2c9fe0ec145c4b0a2e9604b9e6e9017
This commit is contained in:
@@ -16,26 +16,54 @@
|
||||
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
|
||||
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.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
|
||||
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
|
||||
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
|
||||
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
|
||||
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;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.app.animation.Interpolators;
|
||||
import com.android.launcher3.BuildConfig;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.AnimatedPropertySetter;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
@@ -45,6 +73,8 @@ import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SettingsCache;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -57,14 +87,17 @@ import java.util.function.Predicate;
|
||||
* logic in the Personal tab.
|
||||
*/
|
||||
public class PrivateProfileManager extends UserProfileManager {
|
||||
|
||||
private static final int EXPAND_COLLAPSE_DURATION = 800;
|
||||
private static final int SETTINGS_OPACITY_DURATION = 160;
|
||||
private final ActivityAllAppsContainerView<?> mAllApps;
|
||||
private final Predicate<UserHandle> mPrivateProfileMatcher;
|
||||
private Set<String> mPreInstalledSystemPackages = new HashSet<>();
|
||||
private Intent mAppInstallerIntent = new Intent();
|
||||
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
|
||||
private boolean mPrivateSpaceSettingsAvailable;
|
||||
private Runnable mUnlockRunnable;
|
||||
private boolean mIsAnimationRunning;
|
||||
private int mHeaderHeight;
|
||||
private boolean mAnimate;
|
||||
|
||||
public PrivateProfileManager(UserManager userManager,
|
||||
ActivityAllAppsContainerView<?> allApps,
|
||||
@@ -118,20 +151,19 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* When called from search, a runnable is set and executed in the {@link #reset()} method, when
|
||||
* Launcher receives update about profile availability.
|
||||
* The runnable 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;
|
||||
public void unlockPrivateProfile() {
|
||||
setQuietMode(false);
|
||||
}
|
||||
|
||||
/** Enables quiet mode for Private Space User Profile. */
|
||||
public void lockPrivateProfile() {
|
||||
enableQuietMode(true);
|
||||
void lockPrivateProfile() {
|
||||
setQuietMode(true);
|
||||
}
|
||||
|
||||
/** Whether private profile should be hidden on Launcher. */
|
||||
@@ -149,7 +181,9 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
setCurrentState(updatedState);
|
||||
resetPrivateSpaceDecorator(updatedState);
|
||||
if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
|
||||
applyUnlockRunnable();
|
||||
postUnlock();
|
||||
} else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
|
||||
executeLock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,23 +269,45 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Posts quiet mode enable/disable call for private profile. */
|
||||
private void enableQuietMode(boolean enable) {
|
||||
setQuietMode(enable);
|
||||
@Override
|
||||
public void setQuietMode(boolean enable) {
|
||||
super.setQuietMode(enable);
|
||||
mAnimate = true;
|
||||
}
|
||||
|
||||
void applyUnlockRunnable() {
|
||||
if (mUnlockRunnable != null) {
|
||||
// reset the runnable to prevent re-execution.
|
||||
MAIN_EXECUTOR.post(mUnlockRunnable);
|
||||
mUnlockRunnable = null;
|
||||
/**
|
||||
* Expand the private space after the app list has been added and updated from
|
||||
* {@link AlphabeticalAppsList#onAppsUpdated()}
|
||||
*/
|
||||
void postUnlock() {
|
||||
if (mAllApps.isSearching()) {
|
||||
MAIN_EXECUTOR.post(this::exitSearchAndExpand);
|
||||
} else {
|
||||
MAIN_EXECUTOR.post(this::expandPrivateSpace);
|
||||
}
|
||||
}
|
||||
|
||||
/** Collapses the private space before the app list has been updated. */
|
||||
void executeLock() {
|
||||
MAIN_EXECUTOR.execute(this::collapsePrivateSpace);
|
||||
}
|
||||
|
||||
void setAnimationRunning(boolean isAnimationRunning) {
|
||||
mIsAnimationRunning = isAnimationRunning;
|
||||
}
|
||||
|
||||
boolean getAnimationRunning() {
|
||||
return mIsAnimationRunning;
|
||||
}
|
||||
|
||||
private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
|
||||
return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
|
||||
}
|
||||
|
||||
private boolean transitioningFromUnlockedToLocked(int previousState, int updatedState) {
|
||||
return previousState == STATE_ENABLED && updatedState == STATE_DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<UserHandle> getUserMatcher() {
|
||||
return mPrivateProfileMatcher;
|
||||
@@ -266,4 +322,349 @@ public class PrivateProfileManager extends UserProfileManager {
|
||||
&& (appInfo.componentName == null
|
||||
|| !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName())));
|
||||
}
|
||||
|
||||
/** Add Private Space Header view elements based upon {@link UserProfileState} */
|
||||
public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
|
||||
// Set the transition duration for the settings and lock button to animate.
|
||||
ViewGroup settingAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
|
||||
if (mAnimate) {
|
||||
enableLayoutTransition(settingAndLockGroup);
|
||||
} else {
|
||||
// Ensure any unwanted animations to not happen.
|
||||
settingAndLockGroup.setLayoutTransition(null);
|
||||
}
|
||||
|
||||
//Add quietMode image and action for lock/unlock button
|
||||
ViewGroup lockButton =
|
||||
parent.findViewById(R.id.ps_lock_unlock_button);
|
||||
assert lockButton != null;
|
||||
addLockButton(lockButton);
|
||||
|
||||
//Trigger lock/unlock action from header.
|
||||
addHeaderOnClickListener(parent);
|
||||
|
||||
//Add image and action for private space settings button
|
||||
ImageButton settingsButton = parent.findViewById(R.id.ps_settings_button);
|
||||
assert settingsButton != null;
|
||||
addPrivateSpaceSettingsButton(settingsButton);
|
||||
|
||||
//Add image for private space transitioning view
|
||||
ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
|
||||
assert transitionView != null;
|
||||
addTransitionImage(transitionView);
|
||||
mHeaderHeight = parent.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the quietModeButton and attach onClickListener for the header to animate different
|
||||
* states when clicked.
|
||||
*/
|
||||
private void addLockButton(ViewGroup lockButton) {
|
||||
TextView lockText = lockButton.findViewById(R.id.lock_text);
|
||||
switch (getCurrentState()) {
|
||||
case STATE_ENABLED -> {
|
||||
lockText.setVisibility(VISIBLE);
|
||||
lockButton.setVisibility(VISIBLE);
|
||||
lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
|
||||
}
|
||||
case STATE_DISABLED -> {
|
||||
lockText.setVisibility(GONE);
|
||||
lockButton.setVisibility(VISIBLE);
|
||||
lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
|
||||
}
|
||||
default -> lockButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void addHeaderOnClickListener(RelativeLayout header) {
|
||||
if (getCurrentState() == STATE_DISABLED) {
|
||||
header.setOnClickListener(view -> lockingAction(/* lock */ false));
|
||||
} else {
|
||||
header.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the enablement of the profile when header or button is clicked. */
|
||||
private void lockingAction(boolean lock) {
|
||||
logEvents(lock ? LAUNCHER_PRIVATE_SPACE_LOCK_TAP : LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
|
||||
if (lock) {
|
||||
lockPrivateProfile();
|
||||
} else {
|
||||
unlockPrivateProfile();
|
||||
}
|
||||
}
|
||||
|
||||
private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
|
||||
if (getCurrentState() == STATE_ENABLED
|
||||
&& isPrivateSpaceSettingsAvailable()) {
|
||||
settingsButton.setVisibility(VISIBLE);
|
||||
settingsButton.setAlpha(1f);
|
||||
settingsButton.setOnClickListener(
|
||||
view -> {
|
||||
logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
|
||||
openPrivateSpaceSettings();
|
||||
});
|
||||
} else {
|
||||
settingsButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTransitionImage(ImageView transitionImage) {
|
||||
if (getCurrentState() == STATE_TRANSITION) {
|
||||
transitionImage.setVisibility(VISIBLE);
|
||||
} else {
|
||||
transitionImage.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds the private space header to scroll to and set the private space icons to GONE. */
|
||||
private void collapse() {
|
||||
AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
|
||||
List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
|
||||
allAppsRecyclerView.getApps().getAdapterItems();
|
||||
for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
|
||||
BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
|
||||
// Scroll to the private space header.
|
||||
if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
|
||||
// Note: SmoothScroller is meant to be used once.
|
||||
RecyclerView.SmoothScroller smoothScroller =
|
||||
new LinearSmoothScroller(mAllApps.getContext()) {
|
||||
@Override protected int getVerticalSnapPreference() {
|
||||
return LinearSmoothScroller.SNAP_TO_END;
|
||||
}
|
||||
};
|
||||
smoothScroller.setTargetPosition(i);
|
||||
RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.startSmoothScroll(smoothScroller);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Make the private space apps gone to "collapse".
|
||||
if (currentItem.decorationInfo != null) {
|
||||
RecyclerView.ViewHolder viewHolder =
|
||||
allAppsRecyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (viewHolder != null) {
|
||||
viewHolder.itemView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upon expanding, only scroll to the item position in the adapter that allows the header to be
|
||||
* visible.
|
||||
*/
|
||||
public int scrollForViewToBeVisibleInContainer(
|
||||
AllAppsRecyclerView allAppsRecyclerView,
|
||||
List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
|
||||
int psHeaderHeight,
|
||||
int allAppsCellHeight) {
|
||||
int rowToExpandToWithRespectToHeader = -1;
|
||||
int itemToScrollTo = -1;
|
||||
// Looks for the item in the app list to scroll to so that the header is visible.
|
||||
for (int i = 0; i < appListAdapterItems.size(); i++) {
|
||||
BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
|
||||
if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
|
||||
itemToScrollTo = i;
|
||||
continue;
|
||||
}
|
||||
if (itemToScrollTo != -1) {
|
||||
itemToScrollTo = i;
|
||||
if (rowToExpandToWithRespectToHeader == -1) {
|
||||
rowToExpandToWithRespectToHeader = currentItem.rowIndex;
|
||||
}
|
||||
int rowToScrollTo =
|
||||
(int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
|
||||
- mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
|
||||
int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
|
||||
// rowToScrollTo - 1 since the item to scroll to is 0 indexed.
|
||||
if (currentRowDistance == rowToScrollTo - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (itemToScrollTo != -1) {
|
||||
// Note: SmoothScroller is meant to be used once.
|
||||
RecyclerView.SmoothScroller smoothScroller =
|
||||
new LinearSmoothScroller(mAllApps.getContext()) {
|
||||
@Override protected int getVerticalSnapPreference() {
|
||||
return LinearSmoothScroller.SNAP_TO_ANY;
|
||||
}
|
||||
};
|
||||
smoothScroller.setTargetPosition(itemToScrollTo);
|
||||
RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
layoutManager.startSmoothScroll(smoothScroller);
|
||||
}
|
||||
}
|
||||
return itemToScrollTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls up to the private space header and animates the collapsing of the text.
|
||||
*/
|
||||
private ValueAnimator animateCollapseAnimation() {
|
||||
float from = 1;
|
||||
float to = 0;
|
||||
RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
|
||||
ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
|
||||
collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
|
||||
collapseAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (scrollBar != null) {
|
||||
scrollBar.setVisibility(INVISIBLE);
|
||||
}
|
||||
// Scroll up to header.
|
||||
collapse();
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
if (scrollBar != null) {
|
||||
scrollBar.setThumbOffsetY(-1);
|
||||
scrollBar.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
return collapseAnim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
|
||||
* animation. At the moment, collapsing, setting alpha changes, and animating the text is done
|
||||
* here.
|
||||
*/
|
||||
private void updatePrivateStateAnimator(boolean expand, @Nullable ViewGroup psHeader) {
|
||||
if (psHeader == null) {
|
||||
return;
|
||||
}
|
||||
ViewGroup settingsAndLockGroup = psHeader.findViewById(R.id.settingsAndLockGroup);
|
||||
ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
|
||||
if (settingsAndLockGroup.getLayoutTransition() == null) {
|
||||
// Set a new transition if the current ViewGroup does not already contain one as each
|
||||
// transition should only happen once when applied.
|
||||
enableLayoutTransition(settingsAndLockGroup);
|
||||
}
|
||||
|
||||
PropertySetter setter = new AnimatedPropertySetter();
|
||||
ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
|
||||
updateSettingsGearAlpha(settingsButton, expand, setter);
|
||||
AnimatorSet animatorSet = setter.buildAnim();
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
// Animate the collapsing of the text at the same time while updating lock button.
|
||||
lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
|
||||
setAnimationRunning(true);
|
||||
}
|
||||
});
|
||||
animatorSet.addListener(forEndCallback(() -> {
|
||||
setAnimationRunning(false);
|
||||
mAnimate = false;
|
||||
if (!expand) {
|
||||
// Call onAppsUpdated() because it may be canceled when this animation occurs.
|
||||
mAllApps.getPersonalAppList().onAppsUpdated();
|
||||
}
|
||||
}));
|
||||
// Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
|
||||
// header. Otherwise the smooth scrolling will scroll higher when played with the state
|
||||
// animator.
|
||||
if (!expand) {
|
||||
animatorSet.playTogether(animateCollapseAnimation());
|
||||
}
|
||||
animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
|
||||
animatorSet.start();
|
||||
}
|
||||
|
||||
/** Animates the layout changes when the text of the button becomes visible/gone. */
|
||||
private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
|
||||
LayoutTransition settingsAndLockTransition = new LayoutTransition();
|
||||
settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
|
||||
settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
|
||||
@Override
|
||||
public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
|
||||
View view, int i) {
|
||||
}
|
||||
@Override
|
||||
public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
|
||||
View view, int i) {
|
||||
settingsAndLockGroup.setLayoutTransition(null);
|
||||
mAnimate = false;
|
||||
}
|
||||
});
|
||||
settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
|
||||
}
|
||||
|
||||
/** Change the settings gear alpha when expanded or collapsed. */
|
||||
private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
|
||||
PropertySetter setter) {
|
||||
float toAlpha = expand ? 1 : 0;
|
||||
setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
|
||||
.setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
|
||||
}
|
||||
|
||||
void expandPrivateSpace() {
|
||||
// If we are on main adapter view, we apply the PS Container expansion animation and
|
||||
// scroll down to load the entire container, making animation visible.
|
||||
ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
|
||||
List<BaseAllAppsAdapter.AdapterItem> adapterItems =
|
||||
mainAdapterHolder.mAppsList.getAdapterItems();
|
||||
if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
|
||||
&& mAllApps.isPersonalTab()) {
|
||||
// Animate the text and settings icon.
|
||||
DeviceProfile deviceProfile =
|
||||
ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
|
||||
scrollForViewToBeVisibleInContainer(mainAdapterHolder.mRecyclerView, adapterItems,
|
||||
getPsHeaderHeight(), deviceProfile.allAppsCellHeightPx);
|
||||
ViewGroup psHeader = getPsHeader(mainAdapterHolder.mRecyclerView, adapterItems);
|
||||
updatePrivateStateAnimator(true, psHeader);
|
||||
}
|
||||
}
|
||||
|
||||
private void exitSearchAndExpand() {
|
||||
mAllApps.updateHeaderScroll(0);
|
||||
// Animate to A-Z with 0 time to reset the animation with proper state management.
|
||||
mAllApps.animateToSearchState(false, 0);
|
||||
MAIN_EXECUTOR.post(() -> {
|
||||
mAllApps.mSearchUiManager.resetSearch();
|
||||
mAllApps.switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
|
||||
expandPrivateSpace();
|
||||
});
|
||||
}
|
||||
|
||||
private void collapsePrivateSpace() {
|
||||
AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
|
||||
AlphabeticalAppsList<?> appList = allAppsRecyclerView.getApps();
|
||||
if (appList == null) {
|
||||
return;
|
||||
}
|
||||
ViewGroup psHeader = getPsHeader(allAppsRecyclerView, appList.getAdapterItems());
|
||||
assert psHeader != null;
|
||||
updatePrivateStateAnimator(false, psHeader);
|
||||
}
|
||||
|
||||
int getPsHeaderHeight() {
|
||||
return mHeaderHeight;
|
||||
}
|
||||
|
||||
/** Get the private space header from the adapter items. */
|
||||
@Nullable
|
||||
private ViewGroup getPsHeader(AllAppsRecyclerView allAppsRecyclerView,
|
||||
List<BaseAllAppsAdapter.AdapterItem> adapterItems){
|
||||
ViewGroup psHeader = null;
|
||||
for (int i = 0; i < adapterItems.size(); i++) {
|
||||
BaseAllAppsAdapter.AdapterItem currentItem = adapterItems.get(i);
|
||||
if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
|
||||
RecyclerView.ViewHolder viewHolder =
|
||||
allAppsRecyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (viewHolder != null) {
|
||||
psHeader = (ViewGroup) viewHolder.itemView;
|
||||
}
|
||||
}
|
||||
}
|
||||
return psHeader;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user