Snap for 7921329 from 36705e6039 to sc-v2-release
Change-Id: Ice4379600fbb72aaffd5cb6a4f5b2d75a1c45a2b
This commit is contained in:
@@ -15,18 +15,10 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
|
||||
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
|
||||
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
|
||||
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.ColorInt;
|
||||
import android.graphics.Rect;
|
||||
import android.os.RemoteException;
|
||||
@@ -44,28 +36,17 @@ import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.QuickstepTransitionManager;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.logging.InstanceIdSequence;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.launcher3.util.OnboardingPrefs;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -77,82 +58,15 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
|
||||
private final BaseQuickstepLauncher mLauncher;
|
||||
|
||||
private final AnimatedFloat mIconAlignmentForResumedState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChanged);
|
||||
private final AnimatedFloat mIconAlignmentForGestureState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChanged);
|
||||
private final AnimatedFloat mIconAlignmentForLauncherState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
|
||||
|
||||
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
|
||||
this::onStashedInAppChanged;
|
||||
|
||||
private final StateManager.StateListener<LauncherState> mStateListener =
|
||||
new StateManager.StateListener<LauncherState>() {
|
||||
private Animator mAnimator;
|
||||
|
||||
@Override
|
||||
public void onStateTransitionStart(LauncherState toState) {
|
||||
// Stash animation from going to launcher should be already handled in
|
||||
// createAnimToLauncher.
|
||||
TaskbarStashController controller = mControllers.taskbarStashController;
|
||||
long duration = TASKBAR_STASH_DURATION;
|
||||
controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
|
||||
toState.isTaskbarStashed());
|
||||
Animator stashAnimator = controller.applyStateWithoutStart(duration);
|
||||
if (stashAnimator != null) {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
PendingAnimation pendingAnimation = new PendingAnimation(duration);
|
||||
pendingAnimation.add(stashAnimator);
|
||||
pendingAnimation.setFloat(mIconAlignmentForLauncherState,
|
||||
AnimatedFloat.VALUE, toState.isTaskbarStashed() ? 0 : 1,
|
||||
FAST_OUT_SLOW_IN);
|
||||
pendingAnimation.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
mTargetStateOverrideForStateTransition = toState;
|
||||
// Copy hotseat alpha over to taskbar icons
|
||||
mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
|
||||
mLauncher.getHotseat().setIconsAlpha(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
if (toState.isTaskbarStashed()) {
|
||||
// Reset hotseat alpha to default
|
||||
mLauncher.getHotseat().setIconsAlpha(1);
|
||||
}
|
||||
mTargetStateOverrideForStateTransition = null;
|
||||
mAnimator = null;
|
||||
}
|
||||
});
|
||||
mAnimator = pendingAnimation.buildAnim();
|
||||
mAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
TaskbarStashController controller = mControllers.taskbarStashController;
|
||||
controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
|
||||
finalState.isTaskbarStashed());
|
||||
controller.applyState();
|
||||
}
|
||||
};
|
||||
|
||||
// Initialized in init.
|
||||
private TaskbarControllers mControllers;
|
||||
private AnimatedFloat mTaskbarBackgroundAlpha;
|
||||
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
|
||||
private AlphaProperty mIconAlphaForHome;
|
||||
private boolean mIsAnimatingToLauncherViaResume;
|
||||
private boolean mIsAnimatingToLauncherViaGesture;
|
||||
private TaskbarKeyguardController mKeyguardController;
|
||||
|
||||
private LauncherState mTargetStateOverride = null;
|
||||
private LauncherState mTargetStateOverrideForStateTransition = null;
|
||||
private final TaskbarLauncherStateController
|
||||
mTaskbarLauncherStateController = new TaskbarLauncherStateController();
|
||||
|
||||
private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
|
||||
new DeviceProfile.OnDeviceProfileChangeListener() {
|
||||
@@ -171,37 +85,26 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
protected void init(TaskbarControllers taskbarControllers) {
|
||||
mControllers = taskbarControllers;
|
||||
|
||||
mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
|
||||
.getTaskbarBackgroundAlpha();
|
||||
mTaskbarLauncherStateController.init(mControllers, mLauncher);
|
||||
mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
|
||||
.getOverrideBackgroundAlpha();
|
||||
|
||||
MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
|
||||
mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
|
||||
|
||||
mLauncher.setTaskbarUIController(this);
|
||||
mKeyguardController = taskbarControllers.taskbarKeyguardController;
|
||||
|
||||
onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
|
||||
mIconAlignmentForResumedState.finishAnimation();
|
||||
onIconAlignmentRatioChanged();
|
||||
|
||||
onStashedInAppChanged(mLauncher.getDeviceProfile());
|
||||
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
|
||||
mLauncher.getStateManager().addStateListener(mStateListener);
|
||||
mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
onLauncherResumedOrPaused(false);
|
||||
mIconAlignmentForResumedState.finishAnimation();
|
||||
mIconAlignmentForGestureState.finishAnimation();
|
||||
mIconAlignmentForLauncherState.finishAnimation();
|
||||
mTaskbarLauncherStateController.onDestroy();
|
||||
|
||||
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
|
||||
mLauncher.getStateManager().removeStateListener(mStateListener);
|
||||
mLauncher.getHotseat().setIconsAlpha(1f);
|
||||
mLauncher.setTaskbarUIController(null);
|
||||
mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
|
||||
updateTaskTransitionSpec(true);
|
||||
@@ -209,11 +112,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
|
||||
@Override
|
||||
protected boolean isTaskbarTouchable() {
|
||||
return !isAnimatingToLauncher();
|
||||
}
|
||||
|
||||
private boolean isAnimatingToLauncher() {
|
||||
return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
|
||||
return !mTaskbarLauncherStateController.isAnimatingToLauncher();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,24 +139,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
}
|
||||
}
|
||||
|
||||
long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
|
||||
if (fromInit) {
|
||||
// Since we are creating the starting state, we don't have a state to animate from, so
|
||||
// set our state immediately.
|
||||
duration = 0;
|
||||
}
|
||||
ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue(
|
||||
getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
|
||||
.setDuration(duration);
|
||||
|
||||
anim.addListener(AnimatorListeners.forEndCallback(
|
||||
() -> mIsAnimatingToLauncherViaResume = false));
|
||||
anim.start();
|
||||
mIsAnimatingToLauncherViaResume = isResumed;
|
||||
|
||||
TaskbarStashController stashController = mControllers.taskbarStashController;
|
||||
stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
|
||||
stashController.applyState(duration);
|
||||
mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
|
||||
mTaskbarLauncherStateController.applyState(
|
||||
fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,77 +152,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
*/
|
||||
public Animator createAnimToLauncher(@NonNull LauncherState toState,
|
||||
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
TaskbarStashController stashController = mControllers.taskbarStashController;
|
||||
stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
|
||||
toState.isTaskbarStashed());
|
||||
if (toState.isTaskbarStashed()) {
|
||||
animatorSet.play(stashController.applyStateWithoutStart(duration));
|
||||
} else {
|
||||
animatorSet.play(mIconAlignmentForGestureState
|
||||
.animateToValue(1)
|
||||
.setDuration(duration));
|
||||
}
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
mTargetStateOverride = null;
|
||||
animator.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
mTargetStateOverride = toState;
|
||||
mIsAnimatingToLauncherViaGesture = true;
|
||||
stashController.updateStateForFlag(FLAG_IN_APP, false);
|
||||
stashController.applyState(duration);
|
||||
}
|
||||
});
|
||||
|
||||
TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
|
||||
callbacks.addListener(listener);
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
recentsView.setTaskLaunchListener(() -> {
|
||||
listener.endGestureStateOverride(true);
|
||||
callbacks.removeListener(listener);
|
||||
});
|
||||
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
private float getCurrentIconAlignmentRatio() {
|
||||
return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
|
||||
}
|
||||
|
||||
private float getCurrentIconAlignmentRatioForLauncherState() {
|
||||
return mIconAlignmentForLauncherState.value;
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChangedForStateTransition() {
|
||||
onIconAlignmentRatioChanged(
|
||||
mTargetStateOverrideForStateTransition != null
|
||||
? mTargetStateOverrideForStateTransition
|
||||
: mLauncher.getStateManager().getState(),
|
||||
this::getCurrentIconAlignmentRatioForLauncherState);
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChanged() {
|
||||
onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
|
||||
: mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChanged(LauncherState state,
|
||||
Supplier<Float> alignmentSupplier) {
|
||||
if (mControllers == null) {
|
||||
return;
|
||||
}
|
||||
float alignment = alignmentSupplier.get();
|
||||
mControllers.taskbarViewController.setLauncherIconAlignment(
|
||||
alignment, mLauncher.getDeviceProfile());
|
||||
|
||||
mTaskbarBackgroundAlpha.updateValue(1 - alignment);
|
||||
|
||||
setIconAlpha(state, alignment);
|
||||
return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,20 +172,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
return mControllers.taskbarActivityContext.getDragLayer();
|
||||
}
|
||||
|
||||
private void setIconAlpha(LauncherState state, float progress) {
|
||||
if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
// If the hotseat icons are visible, then switch taskbar in last frame
|
||||
setTaskbarViewVisible(progress < 1);
|
||||
} else {
|
||||
mIconAlphaForHome.setValue(1 - progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTaskbarViewVisible(boolean isVisible) {
|
||||
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
|
||||
mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStashedInAppChanged() {
|
||||
onStashedInAppChanged(mLauncher.getDeviceProfile());
|
||||
@@ -451,35 +251,4 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
|
||||
instanceId);
|
||||
}
|
||||
|
||||
private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
|
||||
private final RecentsAnimationCallbacks mCallbacks;
|
||||
|
||||
TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
|
||||
mCallbacks = callbacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
|
||||
endGestureStateOverride(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
|
||||
endGestureStateOverride(!controller.getFinishTargetIsLauncher());
|
||||
}
|
||||
|
||||
private void endGestureStateOverride(boolean finishedToApp) {
|
||||
mCallbacks.removeListener(this);
|
||||
mIsAnimatingToLauncherViaGesture = false;
|
||||
|
||||
mIconAlignmentForGestureState
|
||||
.animateToValue(0)
|
||||
.start();
|
||||
|
||||
TaskbarStashController controller = mControllers.taskbarStashController;
|
||||
controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
|
||||
controller.applyState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.launcher3.taskbar;
|
||||
|
||||
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
|
||||
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
|
||||
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
|
||||
* the task bar accordingly.
|
||||
*/
|
||||
public class TaskbarLauncherStateController {
|
||||
|
||||
public static final int FLAG_RESUMED = 1 << 0;
|
||||
public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
|
||||
public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2;
|
||||
public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3;
|
||||
|
||||
private final AnimatedFloat mIconAlignmentForResumedState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChanged);
|
||||
private final AnimatedFloat mIconAlignmentForGestureState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChanged);
|
||||
private final AnimatedFloat mIconAlignmentForLauncherState =
|
||||
new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
|
||||
|
||||
private TaskbarControllers mControllers;
|
||||
private AnimatedFloat mTaskbarBackgroundAlpha;
|
||||
private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
|
||||
private BaseQuickstepLauncher mLauncher;
|
||||
|
||||
private int mPrevState;
|
||||
private int mState;
|
||||
|
||||
private LauncherState mTargetStateOverride = null;
|
||||
private LauncherState mTargetStateOverrideForStateTransition = null;
|
||||
|
||||
private boolean mIsAnimatingToLauncherViaGesture;
|
||||
private boolean mIsAnimatingToLauncherViaResume;
|
||||
|
||||
private final StateManager.StateListener<LauncherState> mStateListener =
|
||||
new StateManager.StateListener<LauncherState>() {
|
||||
|
||||
@Override
|
||||
public void onStateTransitionStart(LauncherState toState) {
|
||||
mTargetStateOverrideForStateTransition = toState;
|
||||
updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
|
||||
toState.isTaskbarStashed());
|
||||
applyState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED,
|
||||
finalState.isTaskbarStashed());
|
||||
applyState();
|
||||
}
|
||||
};
|
||||
|
||||
public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
|
||||
mControllers = controllers;
|
||||
mLauncher = launcher;
|
||||
|
||||
mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
|
||||
.getTaskbarBackgroundAlpha();
|
||||
MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
|
||||
mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
|
||||
mIconAlphaForHome.setConsumer(
|
||||
(Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
|
||||
|
||||
mIconAlignmentForResumedState.finishAnimation();
|
||||
onIconAlignmentRatioChanged();
|
||||
|
||||
mLauncher.getStateManager().addStateListener(mStateListener);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
mIconAlignmentForResumedState.finishAnimation();
|
||||
mIconAlignmentForGestureState.finishAnimation();
|
||||
mIconAlignmentForLauncherState.finishAnimation();
|
||||
|
||||
mLauncher.getHotseat().setIconsAlpha(1f);
|
||||
mLauncher.getStateManager().removeStateListener(mStateListener);
|
||||
}
|
||||
|
||||
public Animator createAnimToLauncher(@NonNull LauncherState toState,
|
||||
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
|
||||
// If going to overview, stash the task bar
|
||||
// If going home, align the icons to hotseat
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
|
||||
TaskbarStashController stashController = mControllers.taskbarStashController;
|
||||
stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
|
||||
toState.isTaskbarStashed());
|
||||
stashController.updateStateForFlag(FLAG_IN_APP, false);
|
||||
|
||||
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
|
||||
animatorSet.play(stashController.applyStateWithoutStart(duration));
|
||||
animatorSet.play(applyState(duration, false));
|
||||
animatorSet.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
mTargetStateOverride = null;
|
||||
animator.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
mTargetStateOverride = toState;
|
||||
}
|
||||
});
|
||||
|
||||
TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
|
||||
callbacks.addListener(listener);
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
recentsView.setTaskLaunchListener(() -> {
|
||||
listener.endGestureStateOverride(true);
|
||||
callbacks.removeListener(listener);
|
||||
});
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
public boolean isAnimatingToLauncher() {
|
||||
return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the proper flag to change the state of the task bar.
|
||||
*
|
||||
* Note that this only updates the flag. {@link #applyState()} needs to be called separately.
|
||||
*
|
||||
* @param flag The flag to update.
|
||||
* @param enabled Whether to enable the flag
|
||||
*/
|
||||
public void updateStateForFlag(int flag, boolean enabled) {
|
||||
if (enabled) {
|
||||
mState |= flag;
|
||||
} else {
|
||||
mState &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasAnyFlag(int flagMask) {
|
||||
return hasAnyFlag(mState, flagMask);
|
||||
}
|
||||
|
||||
private boolean hasAnyFlag(int flags, int flagMask) {
|
||||
return (flags & flagMask) != 0;
|
||||
}
|
||||
|
||||
public void applyState() {
|
||||
applyState(TASKBAR_STASH_DURATION);
|
||||
}
|
||||
|
||||
public void applyState(long duration) {
|
||||
applyState(duration, true);
|
||||
}
|
||||
|
||||
public Animator applyState(boolean start) {
|
||||
return applyState(TASKBAR_STASH_DURATION, start);
|
||||
}
|
||||
|
||||
public Animator applyState(long duration, boolean start) {
|
||||
Animator animator = null;
|
||||
if (mPrevState != mState) {
|
||||
int changedFlags = mPrevState ^ mState;
|
||||
animator = onStateChangeApplied(changedFlags, duration, start);
|
||||
mPrevState = mState;
|
||||
}
|
||||
return animator;
|
||||
}
|
||||
|
||||
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
if (hasAnyFlag(changedFlags, FLAG_RESUMED)) {
|
||||
boolean isResumed = isResumed();
|
||||
ObjectAnimator anim = mIconAlignmentForResumedState
|
||||
.animateToValue(getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
|
||||
.setDuration(duration);
|
||||
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIsAnimatingToLauncherViaResume = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mIsAnimatingToLauncherViaResume = isResumed;
|
||||
|
||||
TaskbarStashController stashController = mControllers.taskbarStashController;
|
||||
stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
|
||||
stashController.applyState(duration);
|
||||
}
|
||||
});
|
||||
animatorSet.play(anim);
|
||||
}
|
||||
|
||||
if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) {
|
||||
boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
|
||||
Animator animator = mIconAlignmentForGestureState
|
||||
.animateToValue(isRecentsAnimationRunning ? 1 : 0);
|
||||
if (isRecentsAnimationRunning) {
|
||||
animator.setDuration(duration);
|
||||
}
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mIsAnimatingToLauncherViaGesture = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning();
|
||||
}
|
||||
});
|
||||
animatorSet.play(animator);
|
||||
}
|
||||
|
||||
if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) {
|
||||
playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration,
|
||||
false /* committed */);
|
||||
}
|
||||
|
||||
if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) {
|
||||
playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration,
|
||||
true /* committed */);
|
||||
}
|
||||
|
||||
if (start) {
|
||||
animatorSet.start();
|
||||
}
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
private void playStateTransitionAnim(boolean isTransitionStateStashed,
|
||||
AnimatorSet animatorSet, long duration, boolean committed) {
|
||||
TaskbarStashController controller = mControllers.taskbarStashController;
|
||||
controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
|
||||
isTransitionStateStashed);
|
||||
Animator stashAnimator = controller.applyStateWithoutStart(duration);
|
||||
if (stashAnimator != null) {
|
||||
stashAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (isTransitionStateStashed && committed) {
|
||||
// Reset hotseat alpha to default
|
||||
mLauncher.getHotseat().setIconsAlpha(1);
|
||||
}
|
||||
mTargetStateOverrideForStateTransition = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
|
||||
}
|
||||
});
|
||||
animatorSet.play(stashAnimator);
|
||||
animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
|
||||
getCurrentIconAlignmentRatioForLauncherState(),
|
||||
isTransitionStateStashed ? 0 : 1));
|
||||
} else {
|
||||
mTargetStateOverrideForStateTransition = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResumed() {
|
||||
return (mState & FLAG_RESUMED) != 0;
|
||||
}
|
||||
|
||||
private boolean isRecentsAnimationRunning() {
|
||||
return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
|
||||
}
|
||||
|
||||
private boolean isTransitionStateStartStashed() {
|
||||
return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0;
|
||||
}
|
||||
|
||||
private boolean isTransitionStateCommittedStashed() {
|
||||
return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0;
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChangedForStateTransition() {
|
||||
onIconAlignmentRatioChanged(
|
||||
mTargetStateOverrideForStateTransition != null
|
||||
? mTargetStateOverrideForStateTransition
|
||||
: mLauncher.getStateManager().getState(),
|
||||
this::getCurrentIconAlignmentRatioForLauncherState);
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChanged() {
|
||||
onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
|
||||
: mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
|
||||
}
|
||||
|
||||
private void onIconAlignmentRatioChanged(LauncherState state,
|
||||
Supplier<Float> alignmentSupplier) {
|
||||
if (mControllers == null) {
|
||||
return;
|
||||
}
|
||||
float alignment = alignmentSupplier.get();
|
||||
mControllers.taskbarViewController.setLauncherIconAlignment(
|
||||
alignment, mLauncher.getDeviceProfile());
|
||||
|
||||
mTaskbarBackgroundAlpha.updateValue(1 - alignment);
|
||||
|
||||
setIconAlpha(state, alignment);
|
||||
}
|
||||
|
||||
private float getCurrentIconAlignmentRatio() {
|
||||
return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
|
||||
}
|
||||
|
||||
private float getCurrentIconAlignmentRatioForLauncherState() {
|
||||
return mIconAlignmentForLauncherState.value;
|
||||
}
|
||||
|
||||
private void setIconAlpha(LauncherState state, float progress) {
|
||||
if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
|
||||
// If the hotseat icons are visible, then switch taskbar in last frame
|
||||
setTaskbarViewVisible(progress < 1);
|
||||
} else {
|
||||
mIconAlphaForHome.setValue(1 - progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void setTaskbarViewVisible(boolean isVisible) {
|
||||
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
|
||||
}
|
||||
|
||||
private final class TaskBarRecentsAnimationListener implements
|
||||
RecentsAnimationCallbacks.RecentsAnimationListener {
|
||||
private final RecentsAnimationCallbacks mCallbacks;
|
||||
|
||||
TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
|
||||
mCallbacks = callbacks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
|
||||
endGestureStateOverride(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
|
||||
endGestureStateOverride(!controller.getFinishTargetIsLauncher());
|
||||
}
|
||||
|
||||
private void endGestureStateOverride(boolean finishedToApp) {
|
||||
mCallbacks.removeListener(this);
|
||||
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
|
||||
applyState();
|
||||
|
||||
TaskbarStashController controller = mControllers.taskbarStashController;
|
||||
controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
|
||||
controller.applyState();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,11 +117,12 @@ public class OverviewCommandHelper {
|
||||
mPendingCommands.clear();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskView getNextTask(RecentsView view) {
|
||||
final TaskView runningTaskView = view.getRunningTaskView();
|
||||
|
||||
if (runningTaskView == null) {
|
||||
return view.getTaskViewCount() > 0 ? view.getTaskViewAt(0) : null;
|
||||
return view.getTaskViewAt(0);
|
||||
} else {
|
||||
final TaskView nextTask = view.getNextTaskView();
|
||||
return nextTask != null ? nextTask : runningTaskView;
|
||||
@@ -256,8 +257,8 @@ public class OverviewCommandHelper {
|
||||
// Ensure that recents view has focus so that it receives the followup key inputs
|
||||
TaskView taskView = rv.getNextTaskView();
|
||||
if (taskView == null) {
|
||||
if (rv.getTaskViewCount() > 0) {
|
||||
taskView = rv.getTaskViewAt(0);
|
||||
taskView = rv.getTaskViewAt(0);
|
||||
if (taskView != null) {
|
||||
taskView.requestFocus();
|
||||
} else {
|
||||
rv.requestFocus();
|
||||
|
||||
@@ -383,7 +383,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
protected final RecentsOrientedState mOrientationState;
|
||||
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
|
||||
@Nullable
|
||||
protected RecentsAnimationController mRecentsAnimationController;
|
||||
@Nullable
|
||||
protected SurfaceTransactionApplier mSyncTransactionApplier;
|
||||
protected int mTaskWidth;
|
||||
protected int mTaskHeight;
|
||||
@@ -394,12 +396,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// mTaskGridVerticalDiff and mTopBottomRowHeightDiff summed together provides the top
|
||||
// position for bottom row of grid tasks.
|
||||
|
||||
@Nullable
|
||||
protected RemoteTargetHandle[] mRemoteTargetHandles;
|
||||
protected final Rect mLastComputedTaskSize = new Rect();
|
||||
protected final Rect mLastComputedGridSize = new Rect();
|
||||
protected final Rect mLastComputedGridTaskSize = new Rect();
|
||||
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
|
||||
@Nullable
|
||||
protected Float mLastComputedTaskStartPushOutDistance = null;
|
||||
@Nullable
|
||||
protected Float mLastComputedTaskEndPushOutDistance = null;
|
||||
protected boolean mEnableDrawingLiveTile = false;
|
||||
protected final Rect mTempRect = new Rect();
|
||||
@@ -454,11 +459,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private final IntSet mTopRowIdSet = new IntSet();
|
||||
|
||||
// The GestureEndTarget that is still in progress.
|
||||
@Nullable
|
||||
protected GestureState.GestureEndTarget mCurrentGestureEndTarget;
|
||||
|
||||
// TODO(b/187528071): Remove these and replace with a real scrim.
|
||||
private float mColorTint;
|
||||
private final int mTintingColor;
|
||||
@Nullable
|
||||
private ObjectAnimator mTintingAnimator;
|
||||
|
||||
private int mOverScrollShift = 0;
|
||||
@@ -542,6 +549,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private int mTaskViewIdCount;
|
||||
private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
|
||||
protected boolean mRunningTaskTileHidden;
|
||||
@Nullable
|
||||
private Task[] mTmpRunningTasks;
|
||||
protected int mFocusedTaskViewId = -1;
|
||||
|
||||
@@ -556,7 +564,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private int mDownX;
|
||||
private int mDownY;
|
||||
|
||||
@Nullable
|
||||
private PendingAnimation mPendingAnimation;
|
||||
@Nullable
|
||||
private LayoutTransition mLayoutTransition;
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
@@ -581,7 +591,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
private final Point mLastMeasureSize = new Point();
|
||||
private final int mEmptyMessagePadding;
|
||||
private boolean mShowEmptyMessage;
|
||||
@Nullable
|
||||
private OnEmptyMessageUpdatedListener mOnEmptyMessageUpdatedListener;
|
||||
@Nullable
|
||||
private Layout mEmptyTextLayout;
|
||||
|
||||
/**
|
||||
@@ -596,8 +608,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* ensure this View doesn't go back into the {@link #mTaskViewPool},
|
||||
* see {@link #onViewRemoved(View)}
|
||||
*/
|
||||
@Nullable
|
||||
private TaskView mSplitHiddenTaskView;
|
||||
@Nullable
|
||||
private TaskView mSecondSplitHiddenTaskView;
|
||||
@Nullable
|
||||
private StagedSplitBounds mSplitBoundsConfig;
|
||||
private final Toast mSplitToast = Toast.makeText(getContext(),
|
||||
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
|
||||
@@ -613,12 +628,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* removed from recentsView
|
||||
*/
|
||||
private int mSplitHiddenTaskViewIndex;
|
||||
@Nullable
|
||||
private FloatingTaskView mFirstFloatingTaskView;
|
||||
@Nullable
|
||||
private FloatingTaskView mSecondFloatingTaskView;
|
||||
|
||||
/**
|
||||
* The task to be removed and immediately re-added. Should not be added to task pool.
|
||||
*/
|
||||
@Nullable
|
||||
private TaskView mMovingTaskView;
|
||||
|
||||
private OverviewActionsView mActionsView;
|
||||
@@ -638,10 +656,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
private RunnableList mSideTaskLaunchCallback;
|
||||
@Nullable
|
||||
private TaskLaunchListener mTaskLaunchListener;
|
||||
|
||||
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
|
||||
BaseActivityInterface sizeStrategy) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setEnableFreeScroll(true);
|
||||
@@ -782,6 +802,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
|
||||
if (mHandleTaskStackChanges) {
|
||||
TaskView taskView = getTaskViewByTaskId(taskId);
|
||||
@@ -1017,6 +1038,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskView getLastGridTaskView() {
|
||||
return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
|
||||
}
|
||||
@@ -1070,6 +1092,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return getScrollForPage(taskIndex) == getPagedOrientationHandler().getPrimaryScroll(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TaskView} that has taskId matching {@code taskId} or null if no match.
|
||||
*/
|
||||
@Nullable
|
||||
public TaskView getTaskViewByTaskId(int taskId) {
|
||||
if (taskId == -1) {
|
||||
return null;
|
||||
@@ -1309,6 +1335,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return;
|
||||
}
|
||||
|
||||
mLoadPlanEverApplied = true;
|
||||
if (taskGroups == null || taskGroups.isEmpty()) {
|
||||
removeTasksViewsAndClearAllButton();
|
||||
onTaskStackUpdated();
|
||||
@@ -1411,7 +1438,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
resetTaskVisuals();
|
||||
onTaskStackUpdated();
|
||||
updateEnabledOverlays();
|
||||
mLoadPlanEverApplied = true;
|
||||
}
|
||||
|
||||
private boolean isModal() {
|
||||
@@ -1920,6 +1946,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return getTaskViewFromTaskViewId(mFocusedTaskViewId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TaskView getTaskViewFromTaskViewId(int taskViewId) {
|
||||
if (taskViewId == -1) {
|
||||
return null;
|
||||
@@ -3088,12 +3115,17 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
|
||||
pageToSnapTo--;
|
||||
}
|
||||
boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
|
||||
removeViewInLayout(dismissedTaskView);
|
||||
mTopRowIdSet.remove(dismissedTaskViewId);
|
||||
|
||||
if (taskCount == 1) {
|
||||
removeViewInLayout(mClearAllButton);
|
||||
startHome();
|
||||
if (isHomeTaskDismissed) {
|
||||
updateEmptyMessage();
|
||||
} else {
|
||||
startHome();
|
||||
}
|
||||
} else {
|
||||
// Update focus task and its size.
|
||||
if (finalIsFocusedTaskDismissed) {
|
||||
@@ -4371,12 +4403,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
}
|
||||
|
||||
public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
|
||||
/**
|
||||
* Finish recents animation.
|
||||
*/
|
||||
public void finishRecentsAnimation(boolean toRecents, @Nullable Runnable onFinishComplete) {
|
||||
finishRecentsAnimation(toRecents, true /* shouldPip */, onFinishComplete);
|
||||
}
|
||||
|
||||
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
|
||||
Runnable onFinishComplete) {
|
||||
@Nullable Runnable onFinishComplete) {
|
||||
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
|
||||
cleanupRemoteTargets();
|
||||
if (!toRecents && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
@@ -4939,10 +4974,13 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
private static class PinnedStackAnimationListener<T extends BaseActivity> extends
|
||||
IPipAnimationListener.Stub {
|
||||
@Nullable
|
||||
private T mActivity;
|
||||
@Nullable
|
||||
private RecentsView mRecentsView;
|
||||
|
||||
public void setActivityAndRecentsView(T activity, RecentsView recentsView) {
|
||||
public void setActivityAndRecentsView(@Nullable T activity,
|
||||
@Nullable RecentsView recentsView) {
|
||||
mActivity = activity;
|
||||
mRecentsView = recentsView;
|
||||
}
|
||||
|
||||
@@ -459,15 +459,36 @@ public class TaskThumbnailView extends View {
|
||||
float availableHeight = surfaceHeight
|
||||
- (thumbnailClipHint.top + thumbnailClipHint.bottom);
|
||||
|
||||
if (isRotated) {
|
||||
float canvasAspect = canvasWidth / (float) canvasHeight;
|
||||
float availableAspect = availableHeight / availableWidth;
|
||||
float canvasAspect = canvasWidth / (float) canvasHeight;
|
||||
float availableAspect = isRotated
|
||||
? availableHeight / availableWidth
|
||||
: availableWidth / availableHeight;
|
||||
boolean isAspectLargelyDifferent = Utilities.isRelativePercentDifferenceGreaterThan(
|
||||
canvasAspect, availableAspect, 0.1f);
|
||||
if (isRotated && isAspectLargelyDifferent) {
|
||||
// Do not rotate thumbnail if it would not improve fit
|
||||
if (Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
|
||||
availableAspect, 0.1f)) {
|
||||
isRotated = false;
|
||||
isOrientationDifferent = false;
|
||||
isRotated = false;
|
||||
isOrientationDifferent = false;
|
||||
}
|
||||
|
||||
if (isAspectLargelyDifferent) {
|
||||
// Crop letterbox insets if insets isn't already clipped
|
||||
if (!TaskView.clipLeft(dp)) {
|
||||
thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
|
||||
}
|
||||
if (!TaskView.clipRight(dp)) {
|
||||
thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
|
||||
}
|
||||
if (!TaskView.clipTop(dp)) {
|
||||
thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
|
||||
}
|
||||
if (!TaskView.clipBottom(dp)) {
|
||||
thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
|
||||
}
|
||||
availableWidth = surfaceWidth
|
||||
- (thumbnailClipHint.left + thumbnailClipHint.right);
|
||||
availableHeight = surfaceHeight
|
||||
- (thumbnailClipHint.top + thumbnailClipHint.bottom);
|
||||
}
|
||||
|
||||
final float targetW, targetH;
|
||||
@@ -478,30 +499,25 @@ public class TaskThumbnailView extends View {
|
||||
targetW = canvasWidth;
|
||||
targetH = canvasHeight;
|
||||
}
|
||||
float canvasAspect = targetW / targetH;
|
||||
float targetAspect = targetW / targetH;
|
||||
|
||||
// Update the clipHint such that
|
||||
// > the final clipped position has same aspect ratio as requested by canvas
|
||||
// > the clipped region is within the task insets if possible
|
||||
// > the clipped region is not scaled up when drawing. If that is not possible
|
||||
// while staying within the taskInsets, move outside the insets.
|
||||
// > first fit the width and crop the extra height
|
||||
// > if that will leave empty space, fit the height and crop the width instead
|
||||
float croppedWidth = availableWidth;
|
||||
if (croppedWidth < targetW) {
|
||||
croppedWidth = Math.min(targetW, surfaceWidth);
|
||||
}
|
||||
|
||||
float croppedHeight = croppedWidth / canvasAspect;
|
||||
float croppedHeight = croppedWidth / targetAspect;
|
||||
if (croppedHeight > availableHeight) {
|
||||
croppedHeight = availableHeight;
|
||||
if (croppedHeight < targetH) {
|
||||
croppedHeight = Math.min(targetH, surfaceHeight);
|
||||
}
|
||||
croppedWidth = croppedHeight * canvasAspect;
|
||||
croppedWidth = croppedHeight * targetAspect;
|
||||
|
||||
// One last check in case the task aspect radio messed up something
|
||||
if (croppedWidth > surfaceWidth) {
|
||||
croppedWidth = surfaceWidth;
|
||||
croppedHeight = croppedWidth / canvasAspect;
|
||||
croppedHeight = croppedWidth / targetAspect;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -383,7 +383,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: {
|
||||
Bundle result = new Bundle();
|
||||
result.putInt(LauncherSettings.Settings.EXTRA_VALUE,
|
||||
mOpenHelper.generateNewScreenId());
|
||||
mOpenHelper.getNewScreenId());
|
||||
return result;
|
||||
}
|
||||
case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
|
||||
@@ -628,7 +628,6 @@ public class LauncherProvider extends ContentProvider {
|
||||
private final Context mContext;
|
||||
private final boolean mForMigration;
|
||||
private int mMaxItemId = -1;
|
||||
private int mMaxScreenId = -1;
|
||||
private boolean mBackupTableExists;
|
||||
private boolean mHotseatRestoreTableExists;
|
||||
|
||||
@@ -672,9 +671,6 @@ public class LauncherProvider extends ContentProvider {
|
||||
if (mMaxItemId == -1) {
|
||||
mMaxItemId = initializeMaxItemId(getWritableDatabase());
|
||||
}
|
||||
if (mMaxScreenId == -1) {
|
||||
mMaxScreenId = initializeMaxScreenId(getWritableDatabase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -682,7 +678,6 @@ public class LauncherProvider extends ContentProvider {
|
||||
if (LOGD) Log.d(TAG, "creating new launcher database");
|
||||
|
||||
mMaxItemId = 1;
|
||||
mMaxScreenId = 0;
|
||||
|
||||
addFavoritesTable(db, false);
|
||||
|
||||
@@ -1043,36 +1038,19 @@ public class LauncherProvider extends ContentProvider {
|
||||
public void checkId(ContentValues values) {
|
||||
int id = values.getAsInteger(Favorites._ID);
|
||||
mMaxItemId = Math.max(id, mMaxItemId);
|
||||
|
||||
Integer screen = values.getAsInteger(Favorites.SCREEN);
|
||||
Integer container = values.getAsInteger(Favorites.CONTAINER);
|
||||
if (screen != null && container != null
|
||||
&& container.intValue() == Favorites.CONTAINER_DESKTOP) {
|
||||
mMaxScreenId = Math.max(screen, mMaxScreenId);
|
||||
}
|
||||
}
|
||||
|
||||
private int initializeMaxItemId(SQLiteDatabase db) {
|
||||
return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID, Favorites.TABLE_NAME);
|
||||
}
|
||||
|
||||
// Generates a new ID to use for an workspace screen in your database. This method
|
||||
// should be only called from the main UI thread. As an exception, we do call it when we
|
||||
// call the constructor from the worker thread; however, this doesn't extend until after the
|
||||
// constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
|
||||
// after that point
|
||||
public int generateNewScreenId() {
|
||||
if (mMaxScreenId < 0) {
|
||||
throw new RuntimeException("Error: max screen id was not initialized");
|
||||
}
|
||||
mMaxScreenId += 1;
|
||||
return mMaxScreenId;
|
||||
}
|
||||
|
||||
private int initializeMaxScreenId(SQLiteDatabase db) {
|
||||
return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
|
||||
// Returns a new ID to use for an workspace screen in your database that is greater than all
|
||||
// existing screen IDs.
|
||||
private int getNewScreenId() {
|
||||
return getMaxId(getWritableDatabase(),
|
||||
"SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
|
||||
Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
|
||||
Favorites.CONTAINER_DESKTOP);
|
||||
Favorites.CONTAINER_DESKTOP) + 1;
|
||||
}
|
||||
|
||||
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
|
||||
@@ -1081,7 +1059,6 @@ public class LauncherProvider extends ContentProvider {
|
||||
|
||||
// Ensure that the max ids are initialized
|
||||
mMaxItemId = initializeMaxItemId(db);
|
||||
mMaxScreenId = initializeMaxScreenId(db);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1721,6 +1721,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
|
||||
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
if (mScroller.isFinished()) {
|
||||
// This was not caused by the scroller, skip it.
|
||||
return;
|
||||
}
|
||||
int newDestinationPage = getDestinationPage();
|
||||
if (newDestinationPage >= 0 && newDestinationPage != mCurrentScrollOverPage) {
|
||||
mCurrentScrollOverPage = newDestinationPage;
|
||||
|
||||
@@ -869,13 +869,13 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
mWorkspaceScreens.remove(emptyScreenId);
|
||||
mScreenOrder.removeValue(emptyScreenId);
|
||||
|
||||
int newScreenId = -1;
|
||||
int newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
|
||||
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
|
||||
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
|
||||
// Launcher database isn't aware of empty pages that are already bound, so we need to
|
||||
// skip those IDs manually.
|
||||
while (newScreenId == -1 || mWorkspaceScreens.containsKey(newScreenId)) {
|
||||
newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
|
||||
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
|
||||
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
|
||||
while (mWorkspaceScreens.containsKey(newScreenId)) {
|
||||
newScreenId++;
|
||||
}
|
||||
|
||||
mWorkspaceScreens.put(newScreenId, cl);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
|
||||
import static com.android.launcher3.WorkspaceLayoutManager.SECOND_SCREEN_ID;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
@@ -300,11 +299,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
|
||||
IntSet screensToExclude = new IntSet();
|
||||
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
|
||||
screensToExclude.add(FIRST_SCREEN_ID);
|
||||
|
||||
// On split display we don't want to add the new items onto the second screen.
|
||||
if (app.getInvariantDeviceProfile().isSplitDisplay) {
|
||||
screensToExclude.add(SECOND_SCREEN_ID);
|
||||
}
|
||||
}
|
||||
|
||||
for (int screen = 0; screen < screenCount; screen++) {
|
||||
|
||||
@@ -292,7 +292,7 @@ public class ModelWriter {
|
||||
FileLog.d(TAG, "removing items from db " + items.stream().map(
|
||||
(item) -> item.getTargetComponent() == null ? ""
|
||||
: item.getTargetComponent().getPackageName()).collect(
|
||||
Collectors.joining(",")), new Exception());
|
||||
Collectors.joining(",")));
|
||||
notifyDelete(items);
|
||||
enqueueDeleteRunnable(() -> {
|
||||
for (ItemInfo item : items) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.view.View;
|
||||
import com.android.launcher3.anim.AlphaUpdateListener;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Utility class to handle separating a single value as a factor of multiple values
|
||||
@@ -85,6 +86,8 @@ public class MultiValueAlpha {
|
||||
// Factor of all other alpha channels, only valid if mMyMask is present in mValidMask.
|
||||
private float mOthers = 1;
|
||||
|
||||
private Consumer<Float> mConsumer;
|
||||
|
||||
AlphaProperty(int myMask) {
|
||||
mMyMask = myMask;
|
||||
}
|
||||
@@ -109,16 +112,24 @@ public class MultiValueAlpha {
|
||||
mValidMask = mMyMask;
|
||||
mValue = value;
|
||||
|
||||
mView.setAlpha(mOthers * mValue);
|
||||
final float alpha = mOthers * mValue;
|
||||
mView.setAlpha(alpha);
|
||||
if (mUpdateVisibility) {
|
||||
AlphaUpdateListener.updateVisibility(mView);
|
||||
}
|
||||
if (mConsumer != null) {
|
||||
mConsumer.accept(mValue);
|
||||
}
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setConsumer(Consumer<Float> consumer) {
|
||||
mConsumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Float.toString(mValue);
|
||||
|
||||
@@ -86,8 +86,6 @@ public class AddWorkspaceItemsTaskTest {
|
||||
|
||||
@Test
|
||||
public void testFindSpaceForItem_prefers_second() throws Exception {
|
||||
mIdp.isSplitDisplay = false;
|
||||
|
||||
// First screen has only one hole of size 1
|
||||
int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
|
||||
|
||||
@@ -108,24 +106,6 @@ public class AddWorkspaceItemsTaskTest {
|
||||
.isRegionVacant(spaceFound[1], spaceFound[2], 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindSpaceForItem_prefers_third_on_split_display() throws Exception {
|
||||
mIdp.isSplitDisplay = true;
|
||||
// First screen has only one hole of size 1
|
||||
int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
|
||||
|
||||
// Second screen has 2 holes of sizes 3x2 and 2x3
|
||||
setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
|
||||
|
||||
int[] spaceFound = newTask().findSpaceForItem(
|
||||
mAppState, mModelHelper.getBgDataModel(), mExistingScreens, mNewScreens, 1, 1);
|
||||
// For split display, it picks the next screen, even if there is enough space
|
||||
// on previous screen
|
||||
assertEquals(2, spaceFound[0]);
|
||||
assertTrue(mScreenOccupancy.get(spaceFound[0])
|
||||
.isRegionVacant(spaceFound[1], spaceFound[2], 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindSpaceForItem_adds_new_screen() throws Exception {
|
||||
// First screen has 2 holes of sizes 3x2 and 2x3
|
||||
|
||||
Reference in New Issue
Block a user