Merge 24Q3 (ab/AP3A.240905.001) to aosp-main-future
Bug: 347831320 Merged-In: I0898d202b9dd4742c0c7d2c0d6b340c748e8acf7 Change-Id: I9b2cede0bdd9bb9a06ee825be7de3df030f51065
This commit is contained in:
@@ -27,6 +27,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.animation.Interpolator
|
||||
import android.window.OnBackInvokedDispatcher
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
|
||||
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
|
||||
@@ -66,11 +67,14 @@ constructor(
|
||||
/** Container where the tooltip's body should be inflated. */
|
||||
lateinit var content: ViewGroup
|
||||
private set
|
||||
|
||||
private lateinit var arrow: View
|
||||
|
||||
/** Callback invoked when the tooltip is being closed. */
|
||||
var onCloseCallback: () -> Unit = {}
|
||||
private var openCloseAnimator: AnimatorSet? = null
|
||||
/** Used to set whether users can tap outside the current tooltip window to dismiss it */
|
||||
var allowTouchDismissal = true
|
||||
|
||||
/** Animates the tooltip into view. */
|
||||
fun show() {
|
||||
@@ -134,14 +138,25 @@ constructor(
|
||||
override fun isOfType(type: Int): Boolean = type and TYPE_TASKBAR_EDUCATION_DIALOG != 0
|
||||
|
||||
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||
if (ev?.action == ACTION_DOWN && !activityContext.dragLayer.isEventOverView(this, ev)) {
|
||||
if (
|
||||
ev?.action == ACTION_DOWN &&
|
||||
!activityContext.dragLayer.isEventOverView(this, ev) &&
|
||||
allowTouchDismissal
|
||||
) {
|
||||
close(true)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
findOnBackInvokedDispatcher()
|
||||
?.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, this)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
findOnBackInvokedDispatcher()?.unregisterOnBackInvokedCallback(this)
|
||||
Settings.Secure.putInt(mContext.contentResolver, LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -86,10 +86,13 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
!activityContext.isPhoneMode &&
|
||||
!activityContext.isTinyTaskbar
|
||||
}
|
||||
|
||||
private val isOpen: Boolean
|
||||
get() = tooltip?.isOpen ?: false
|
||||
|
||||
val isBeforeTooltipFeaturesStep: Boolean
|
||||
get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
|
||||
|
||||
private lateinit var controllers: TaskbarControllers
|
||||
|
||||
// Keep track of whether the user has seen the Search Edu
|
||||
@@ -152,6 +155,7 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
tooltipStep = TOOLTIP_STEP_NONE
|
||||
inflateTooltip(R.layout.taskbar_edu_features)
|
||||
tooltip?.run {
|
||||
allowTouchDismissal = false
|
||||
val splitscreenAnim = requireViewById<LottieAnimationView>(R.id.splitscreen_animation)
|
||||
val suggestionsAnim = requireViewById<LottieAnimationView>(R.id.suggestions_animation)
|
||||
val pinningAnim = requireViewById<LottieAnimationView>(R.id.pinning_animation)
|
||||
@@ -216,6 +220,7 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
inflateTooltip(R.layout.taskbar_edu_pinning)
|
||||
|
||||
tooltip?.run {
|
||||
allowTouchDismissal = true
|
||||
requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
|
||||
.supportLightTheme()
|
||||
|
||||
@@ -260,6 +265,7 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
userHasSeenSearchEdu = true
|
||||
inflateTooltip(R.layout.taskbar_edu_search)
|
||||
tooltip?.run {
|
||||
allowTouchDismissal = true
|
||||
requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
|
||||
val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
|
||||
showDisclosureText(eduSubtitle)
|
||||
@@ -332,7 +338,9 @@ open class TaskbarEduTooltipController(context: Context) :
|
||||
}
|
||||
|
||||
/** Closes the current [tooltip]. */
|
||||
fun hide() = tooltip?.close(true)
|
||||
fun hide() {
|
||||
tooltip?.close(true)
|
||||
}
|
||||
|
||||
/** Initializes [tooltip] with content from [contentResId]. */
|
||||
private fun inflateTooltip(@LayoutRes contentResId: Int) {
|
||||
|
||||
@@ -35,7 +35,6 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAnimUtils;
|
||||
import com.android.launcher3.LauncherInitListener;
|
||||
@@ -213,10 +212,10 @@ public final class LauncherActivityInterface extends
|
||||
if (launcher.isStarted() && (isInLiveTileMode() || launcher.hasBeenResumed())) {
|
||||
return launcher;
|
||||
}
|
||||
if (Flags.useActivityOverlay()
|
||||
&& SystemUiProxy.INSTANCE.get(launcher).getHomeVisibilityState().isHomeVisible()) {
|
||||
if (isInMinusOne()) {
|
||||
return launcher;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -293,6 +292,15 @@ public final class LauncherActivityInterface extends
|
||||
&& TopTaskTracker.INSTANCE.get(launcher).getCachedTopTask(false).isHomeTask();
|
||||
}
|
||||
|
||||
private boolean isInMinusOne() {
|
||||
QuickstepLauncher launcher = getCreatedContainer();
|
||||
|
||||
return launcher != null
|
||||
&& launcher.getStateManager().getState() == NORMAL
|
||||
&& !launcher.isStarted()
|
||||
&& TopTaskTracker.INSTANCE.get(launcher).getCachedTopTask(false).isHomeTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLaunchTaskFailed() {
|
||||
QuickstepLauncher launcher = getCreatedContainer();
|
||||
|
||||
@@ -132,6 +132,13 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> implem
|
||||
* Init drag layer and overview panel views.
|
||||
*/
|
||||
protected void setupViews() {
|
||||
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
|
||||
// SplitSelectStateController needs to be created before setContentView()
|
||||
mSplitSelectStateController =
|
||||
new SplitSelectStateController(this, mHandler, getStateManager(),
|
||||
null /* depthController */, getStatsLogManager(),
|
||||
systemUiProxy, RecentsModel.INSTANCE.get(this),
|
||||
null /*activityBackCallback*/);
|
||||
inflateRootView(R.layout.fallback_recents_activity);
|
||||
setContentView(getRootView());
|
||||
mDragLayer = findViewById(R.id.drag_layer);
|
||||
@@ -139,12 +146,6 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> implem
|
||||
mFallbackRecentsView = findViewById(R.id.overview_panel);
|
||||
mActionsView = findViewById(R.id.overview_actions_view);
|
||||
getRootView().getSysUiScrim().getSysUIProgress().updateValue(0);
|
||||
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
|
||||
mSplitSelectStateController =
|
||||
new SplitSelectStateController(this, mHandler, getStateManager(),
|
||||
null /* depthController */, getStatsLogManager(),
|
||||
systemUiProxy, RecentsModel.INSTANCE.get(this),
|
||||
null /*activityBackCallback*/);
|
||||
mDragLayer.recreateControllers();
|
||||
if (enableDesktopWindowingMode()) {
|
||||
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.quickstep;
|
||||
|
||||
import static com.android.app.animation.Interpolators.ACCELERATE_1_5;
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
|
||||
import static com.android.launcher3.PagedView.INVALID_PAGE;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -449,7 +450,7 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
float alpha = mAnimationFactory.getWindowAlpha(progress);
|
||||
|
||||
mHomeAnim.setPlayFraction(progress);
|
||||
if (mTargetTaskView == null) {
|
||||
if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) {
|
||||
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
|
||||
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
|
||||
mLocalTransformParams
|
||||
@@ -464,10 +465,15 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
|
||||
mLocalTransformParams.applySurfaceParams(
|
||||
mLocalTransformParams.createSurfaceParams(this));
|
||||
mAnimationFactory.update(
|
||||
currentRect, progress, mMatrix.mapRadius(cornerRadius), (int) (alpha * 255));
|
||||
|
||||
if (mTargetTaskView == null) {
|
||||
mAnimationFactory.update(
|
||||
currentRect,
|
||||
progress,
|
||||
mMatrix.mapRadius(cornerRadius),
|
||||
!enableAdditionalHomeAnimations() || mTargetTaskView == null
|
||||
? 0 : (int) (alpha * 255));
|
||||
|
||||
if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) {
|
||||
return;
|
||||
}
|
||||
if (mAnimationFactory.isAnimatingIntoIcon() && mAnimationFactory.isAnimationReady()) {
|
||||
@@ -506,7 +512,7 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
public void onAnimationStart(Animator animation) {
|
||||
setUp();
|
||||
mHomeAnim.dispatchOnStart();
|
||||
if (mTargetTaskView == null) {
|
||||
if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) {
|
||||
return;
|
||||
}
|
||||
Rect thumbnailBounds = new Rect();
|
||||
@@ -521,7 +527,7 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
}
|
||||
|
||||
private void setUp() {
|
||||
if (mTargetTaskView == null) {
|
||||
if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) {
|
||||
return;
|
||||
}
|
||||
RecentsView recentsView = mTargetTaskView.getRecentsView();
|
||||
@@ -542,7 +548,7 @@ public abstract class SwipeUpAnimationLogic implements
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
if (mTargetTaskView == null) {
|
||||
if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) {
|
||||
return;
|
||||
}
|
||||
RecentsView recentsView = mTargetTaskView.getRecentsView();
|
||||
|
||||
@@ -492,18 +492,8 @@ public interface TaskShortcutFactory {
|
||||
TaskContainer taskContainer) {
|
||||
boolean isTablet = container.getDeviceProfile().isTablet;
|
||||
boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
|
||||
// Extra conditions if it's not grid-only overview
|
||||
if (!isGridOnlyOverview) {
|
||||
RecentsOrientedState orientedState = taskContainer.getTaskView().getOrientedState();
|
||||
boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
|
||||
&& orientedState.getTouchRotation() != ROTATION_0;
|
||||
if (!isFakeLandscape) {
|
||||
return null;
|
||||
}
|
||||
// Disallow "Select" when swiping up from landscape due to rotated thumbnail.
|
||||
if (orientedState.getDisplayRotation() != ROTATION_0) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
SystemShortcut modalStateSystemShortcut =
|
||||
|
||||
@@ -259,7 +259,8 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
|
||||
return new Pair<>(translationX, translationY);
|
||||
}
|
||||
|
||||
bannerParams.gravity = BOTTOM | ((deviceProfile.isLandscape) ? START : CENTER_HORIZONTAL);
|
||||
bannerParams.gravity =
|
||||
BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL);
|
||||
|
||||
// Set correct width
|
||||
if (desiredTaskId == splitBounds.leftTopTaskId) {
|
||||
|
||||
@@ -50,7 +50,7 @@ private constructor(
|
||||
private val disappearanceDurationMs: Long,
|
||||
private val interpolator: Interpolator,
|
||||
) {
|
||||
private val borderAnimationProgress = AnimatedFloat { updateOutline() }
|
||||
private val borderAnimationProgress = AnimatedFloat { _ -> updateOutline() }
|
||||
private val borderPaint =
|
||||
Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = borderColor
|
||||
@@ -224,6 +224,7 @@ private constructor(
|
||||
|
||||
val borderWidth: Float
|
||||
get() = borderWidthPx * animationProgress
|
||||
|
||||
val alignmentAdjustment: Float
|
||||
// Outset the border by half the width to create an outwards-growth animation
|
||||
get() = -borderWidth / 2f + alignmentAdjustmentInset
|
||||
|
||||
@@ -31,9 +31,11 @@ import static com.android.app.animation.Interpolators.FINAL_FRAME;
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.app.animation.Interpolators.OVERSHOOT_0_75;
|
||||
import static com.android.app.animation.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
|
||||
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
|
||||
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
|
||||
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
|
||||
import static com.android.launcher3.Flags.enableGridOnlyOverview;
|
||||
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
|
||||
@@ -130,6 +132,7 @@ import androidx.annotation.UiThread;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.internal.jank.Cuj;
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Flags;
|
||||
@@ -2688,6 +2691,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
}
|
||||
|
||||
private void animateRotation(int newRotation) {
|
||||
AbstractFloatingView.closeAllOpenViewsExcept(mContainer, false, TYPE_REBIND_SAFE);
|
||||
AnimatorSet pa = setRecentsChangedOrientation(true);
|
||||
pa.addListener(AnimatorListeners.forSuccessCallback(() -> {
|
||||
setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
|
||||
@@ -3801,7 +3805,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
anim.setFloat(taskView, taskView.getSecondaryDismissTranslationProperty(),
|
||||
secondaryTranslation, clampToProgress(LINEAR, animationStartProgress,
|
||||
dismissTranslationInterpolationEnd));
|
||||
anim.setFloat(taskView, TaskView.SCALE_AND_DIM_OUT, 0f,
|
||||
anim.add(taskView.getFocusTransitionScaleAndDimOutAnimator(),
|
||||
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
|
||||
} else {
|
||||
float primaryTranslation =
|
||||
@@ -4520,6 +4524,9 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
* than the running task, when updating page offsets.
|
||||
*/
|
||||
public void setOffsetMidpointIndexOverride(int offsetMidpointIndexOverride) {
|
||||
if (!enableAdditionalHomeAnimations()) {
|
||||
return;
|
||||
}
|
||||
mOffsetMidpointIndexOverride = offsetMidpointIndexOverride;
|
||||
updatePageOffsets();
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.android.launcher3.Flags.privateSpaceRestrictAccessibilityDrag
|
||||
import com.android.launcher3.LauncherSettings
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.Utilities
|
||||
import com.android.launcher3.anim.AnimatedFloat
|
||||
import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
@@ -438,17 +439,17 @@ constructor(
|
||||
focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_FULLSCREEN)
|
||||
private val focusTransitionScaleAndDim =
|
||||
focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_SCALE_AND_DIM)
|
||||
|
||||
/**
|
||||
* Variant of [focusTransitionScaleAndDim] that has a built-in interpolator, to be used with
|
||||
* [com.android.launcher3.anim.PendingAnimation] via [SCALE_AND_DIM_OUT] only. PendingAnimation
|
||||
* doesn't support interpolator per animation, so we'll have to interpolate inside the property.
|
||||
* Returns an animator of [focusTransitionScaleAndDim] that transition out with a built-in
|
||||
* interpolator.
|
||||
*/
|
||||
private var focusTransitionScaleAndDimOut = focusTransitionScaleAndDim.value
|
||||
set(value) {
|
||||
field = value
|
||||
focusTransitionScaleAndDim.value =
|
||||
FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(field)
|
||||
}
|
||||
fun getFocusTransitionScaleAndDimOutAnimator(): ObjectAnimator =
|
||||
AnimatedFloat { v ->
|
||||
focusTransitionScaleAndDim.value =
|
||||
FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(v)
|
||||
}
|
||||
.animateToValue(1f, 0f)
|
||||
|
||||
private var iconAndDimAnimator: ObjectAnimator? = null
|
||||
// The current background requests to load the task thumbnail and icon
|
||||
@@ -1700,16 +1701,6 @@ constructor(
|
||||
override fun get(taskView: TaskView) = taskView.focusTransitionProgress
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val SCALE_AND_DIM_OUT: FloatProperty<TaskView> =
|
||||
object : FloatProperty<TaskView>("scaleAndDimFastOut") {
|
||||
override fun setValue(taskView: TaskView, v: Float) {
|
||||
taskView.focusTransitionScaleAndDimOut = v
|
||||
}
|
||||
|
||||
override fun get(taskView: TaskView) = taskView.focusTransitionScaleAndDimOut
|
||||
}
|
||||
|
||||
private val SPLIT_SELECT_TRANSLATION_X: FloatProperty<TaskView> =
|
||||
object : FloatProperty<TaskView>("splitSelectTranslationX") {
|
||||
override fun setValue(taskView: TaskView, v: Float) {
|
||||
|
||||
@@ -305,9 +305,7 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView {
|
||||
|
||||
@Override
|
||||
public int getScrollBarTop() {
|
||||
return ActivityContext.lookupContext(getContext()).getAppsView().isSearchSupported()
|
||||
? getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding)
|
||||
: 0;
|
||||
return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.util.FloatProperty;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A mutable float which allows animating the value
|
||||
*/
|
||||
@@ -38,9 +40,9 @@ public class AnimatedFloat {
|
||||
}
|
||||
};
|
||||
|
||||
private static final Runnable NO_OP = () -> { };
|
||||
private static final Consumer<Float> NO_OP = t -> { };
|
||||
|
||||
private final Runnable mUpdateCallback;
|
||||
private final Consumer<Float> mUpdateCallback;
|
||||
private ObjectAnimator mValueAnimator;
|
||||
// Only non-null when an animation is playing to this value.
|
||||
private Float mEndValue;
|
||||
@@ -52,6 +54,10 @@ public class AnimatedFloat {
|
||||
}
|
||||
|
||||
public AnimatedFloat(Runnable updateCallback) {
|
||||
this(v -> updateCallback.run());
|
||||
}
|
||||
|
||||
public AnimatedFloat(Consumer<Float> updateCallback) {
|
||||
mUpdateCallback = updateCallback;
|
||||
}
|
||||
|
||||
@@ -60,6 +66,11 @@ public class AnimatedFloat {
|
||||
value = initialValue;
|
||||
}
|
||||
|
||||
public AnimatedFloat(Consumer<Float> updateCallback, float initialValue) {
|
||||
this(updateCallback);
|
||||
value = initialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an animation from the current value to the given value.
|
||||
*/
|
||||
@@ -99,7 +110,7 @@ public class AnimatedFloat {
|
||||
public void updateValue(float v) {
|
||||
if (Float.compare(v, value) != 0) {
|
||||
value = v;
|
||||
mUpdateCallback.run();
|
||||
mUpdateCallback.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,13 @@ public class PendingAnimation extends AnimatedPropertySetter {
|
||||
add(anim, springProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to sent an interpolator on an animation and add it to the list
|
||||
*/
|
||||
public void add(Animator anim, TimeInterpolator interpolator) {
|
||||
add(anim, interpolator, SpringProperty.DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Animator anim) {
|
||||
add(anim, SpringProperty.DEFAULT);
|
||||
|
||||
@@ -209,7 +209,7 @@ public class LoaderTask implements Runnable {
|
||||
mApp.getContext().getContentResolver(),
|
||||
"launcher_broadcast_installed_apps",
|
||||
/* def= */ 0);
|
||||
if (launcherBroadcastInstalledApps == 1) {
|
||||
if (launcherBroadcastInstalledApps == 1 && mIsRestoreFromBackup) {
|
||||
List<FirstScreenBroadcastModel> broadcastModels =
|
||||
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
|
||||
mPmHelper,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.android.launcher3.views;
|
||||
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
|
||||
import static com.android.launcher3.Utilities.boundToRange;
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
|
||||
@@ -97,6 +98,9 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
* within the clip bounds of this view.
|
||||
*/
|
||||
public void setTaskViewArtist(TaskViewArtist taskViewArtist) {
|
||||
if (!enableAdditionalHomeAnimations()) {
|
||||
return;
|
||||
}
|
||||
mTaskViewArtist = taskViewArtist;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.views;
|
||||
import static android.view.Gravity.LEFT;
|
||||
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
|
||||
import static com.android.launcher3.Utilities.getFullDrawable;
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
@@ -164,7 +165,12 @@ public class FloatingIconView extends FrameLayout implements
|
||||
*/
|
||||
public void update(float alpha, RectF rect, float progress, float shapeProgressStart,
|
||||
float cornerRadius, boolean isOpening, int taskViewDrawAlpha) {
|
||||
setAlpha(isLaidOut() ? alpha : 0f);
|
||||
// The non-running task home animation has some very funky first few frames because this
|
||||
// FIV hasn't fully laid out. During those frames, hide this FIV and continue drawing the
|
||||
// TaskView directly while transforming it in the place of this FIV. However, if we fade
|
||||
// the TaskView at all, we need to display this FIV regardless.
|
||||
setAlpha(!enableAdditionalHomeAnimations() || isLaidOut() || taskViewDrawAlpha < 255
|
||||
? alpha : 0f);
|
||||
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, this,
|
||||
mLauncher.getDeviceProfile(), taskViewDrawAlpha);
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.android.launcher3.model
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.os.UserHandle
|
||||
import android.platform.test.flag.junit.SetFlagsRule
|
||||
import android.provider.Settings
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito
|
||||
import com.android.launcher3.Flags
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.LauncherAppState
|
||||
@@ -14,6 +17,7 @@ import com.android.launcher3.icons.IconCache
|
||||
import com.android.launcher3.icons.cache.CachingLogic
|
||||
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
|
||||
import com.android.launcher3.pm.UserCache
|
||||
import com.android.launcher3.provider.RestoreDbTask
|
||||
import com.android.launcher3.ui.TestViewHelpers
|
||||
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
|
||||
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
|
||||
@@ -21,21 +25,30 @@ import com.android.launcher3.util.LooperIdleLock
|
||||
import com.android.launcher3.util.UserIconInfo
|
||||
import com.google.common.truth.Truth
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.ArgumentMatchers.anyList
|
||||
import org.mockito.ArgumentMatchers.anyMap
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.MockitoSession
|
||||
import org.mockito.Spy
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.mockito.quality.Strictness
|
||||
|
||||
private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
|
||||
|
||||
@@ -43,6 +56,20 @@ private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LoaderTaskTest {
|
||||
private var context = SandboxModelContext()
|
||||
private val expectedBroadcastModel =
|
||||
FirstScreenBroadcastModel(
|
||||
installerPackage = "installerPackage",
|
||||
pendingCollectionItems = mutableSetOf("pendingCollectionItem"),
|
||||
pendingWidgetItems = mutableSetOf("pendingWidgetItem"),
|
||||
pendingHotseatItems = mutableSetOf("pendingHotseatItem"),
|
||||
pendingWorkspaceItems = mutableSetOf("pendingWorkspaceItem"),
|
||||
installedHotseatItems = mutableSetOf("installedHotseatItem"),
|
||||
installedWorkspaceItems = mutableSetOf("installedWorkspaceItem"),
|
||||
firstScreenInstalledWidgets = mutableSetOf("installedFirstScreenWidget"),
|
||||
secondaryScreenInstalledWidgets = mutableSetOf("installedSecondaryScreenWidget")
|
||||
)
|
||||
private lateinit var mockitoSession: MockitoSession
|
||||
|
||||
@Mock private lateinit var app: LauncherAppState
|
||||
@Mock private lateinit var bgAllAppsList: AllAppsList
|
||||
@Mock private lateinit var modelDelegate: ModelDelegate
|
||||
@@ -61,7 +88,11 @@ class LoaderTaskTest {
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
mockitoSession =
|
||||
ExtendedMockito.mockitoSession()
|
||||
.strictness(Strictness.LENIENT)
|
||||
.mockStatic(FirstScreenBroadcastHelper::class.java)
|
||||
.startMocking()
|
||||
val idp =
|
||||
InvariantDeviceProfile().apply {
|
||||
numRows = 5
|
||||
@@ -90,6 +121,7 @@ class LoaderTaskTest {
|
||||
@After
|
||||
fun tearDown() {
|
||||
context.onDestroy()
|
||||
mockitoSession.finishMocking()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,6 +198,141 @@ class LoaderTaskTest {
|
||||
verify(bgAllAppsList, Mockito.never())
|
||||
.setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `When launcher_broadcast_installed_apps and is restore then send installed item broadcast`() {
|
||||
// Given
|
||||
val spyContext = spy(context)
|
||||
`when`(app.context).thenReturn(spyContext)
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
|
||||
anyOrNull(),
|
||||
anyList(),
|
||||
anyMap(),
|
||||
anyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(listOf(expectedBroadcastModel))
|
||||
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.sendBroadcastsForModels(
|
||||
spyContext,
|
||||
listOf(expectedBroadcastModel)
|
||||
)
|
||||
)
|
||||
.thenCallRealMethod()
|
||||
|
||||
Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
|
||||
RestoreDbTask.setPending(spyContext)
|
||||
|
||||
// When
|
||||
LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
|
||||
.runSyncOnBackgroundThread()
|
||||
|
||||
// Then
|
||||
val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
|
||||
verify(spyContext).sendBroadcast(argumentCaptor.capture())
|
||||
val actualBroadcastIntent = argumentCaptor.value
|
||||
assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.installedWorkspaceItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.installedHotseatItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(
|
||||
expectedBroadcastModel.firstScreenInstalledWidgets +
|
||||
expectedBroadcastModel.secondaryScreenInstalledWidgets
|
||||
),
|
||||
actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.pendingCollectionItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("folderItem")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("workspaceItem")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.pendingHotseatItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("hotseatItem")
|
||||
)
|
||||
assertEquals(
|
||||
ArrayList(expectedBroadcastModel.pendingWidgetItems),
|
||||
actualBroadcastIntent.getStringArrayListExtra("widgetItem")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `When not a restore then installed item broadcast not sent`() {
|
||||
// Given
|
||||
val spyContext = spy(context)
|
||||
`when`(app.context).thenReturn(spyContext)
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
|
||||
anyOrNull(),
|
||||
anyList(),
|
||||
anyMap(),
|
||||
anyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(listOf(expectedBroadcastModel))
|
||||
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.sendBroadcastsForModels(
|
||||
spyContext,
|
||||
listOf(expectedBroadcastModel)
|
||||
)
|
||||
)
|
||||
.thenCallRealMethod()
|
||||
|
||||
Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
|
||||
|
||||
// When
|
||||
LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
|
||||
.runSyncOnBackgroundThread()
|
||||
|
||||
// Then
|
||||
verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `When launcher_broadcast_installed_apps false then installed item broadcast not sent`() {
|
||||
// Given
|
||||
val spyContext = spy(context)
|
||||
`when`(app.context).thenReturn(spyContext)
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
|
||||
anyOrNull(),
|
||||
anyList(),
|
||||
anyMap(),
|
||||
anyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(listOf(expectedBroadcastModel))
|
||||
|
||||
whenever(
|
||||
FirstScreenBroadcastHelper.sendBroadcastsForModels(
|
||||
spyContext,
|
||||
listOf(expectedBroadcastModel)
|
||||
)
|
||||
)
|
||||
.thenCallRealMethod()
|
||||
|
||||
Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
|
||||
RestoreDbTask.setPending(spyContext)
|
||||
|
||||
// When
|
||||
LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
|
||||
.runSyncOnBackgroundThread()
|
||||
|
||||
// Then
|
||||
verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
private fun LoaderTask.runSyncOnBackgroundThread() {
|
||||
|
||||
Reference in New Issue
Block a user