1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.quickstep.views;
17
18import static com.android.launcher3.LauncherAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
19import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
20import static com.android.launcher3.LauncherState.NORMAL;
21import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
22
23import android.animation.AnimatorSet;
24import android.animation.ObjectAnimator;
25import android.annotation.TargetApi;
26import android.content.Context;
27import android.graphics.Canvas;
28import android.graphics.Rect;
29import android.os.Build;
30import android.util.AttributeSet;
31import android.util.FloatProperty;
32import android.view.View;
33import android.view.ViewDebug;
34
35import com.android.launcher3.DeviceProfile;
36import com.android.launcher3.Launcher;
37import com.android.launcher3.LauncherState;
38import com.android.launcher3.R;
39import com.android.launcher3.anim.Interpolators;
40import com.android.launcher3.views.ScrimView;
41import com.android.quickstep.OverviewInteractionState;
42import com.android.quickstep.util.ClipAnimationHelper;
43import com.android.quickstep.util.LayoutUtils;
44
45/**
46 * {@link RecentsView} used in Launcher activity
47 */
48@TargetApi(Build.VERSION_CODES.O)
49public class LauncherRecentsView extends RecentsView<Launcher> {
50
51    public static final FloatProperty<LauncherRecentsView> TRANSLATION_Y_FACTOR =
52            new FloatProperty<LauncherRecentsView>("translationYFactor") {
53
54                @Override
55                public void setValue(LauncherRecentsView view, float v) {
56                    view.setTranslationYFactor(v);
57                }
58
59                @Override
60                public Float get(LauncherRecentsView view) {
61                    return view.mTranslationYFactor;
62                }
63            };
64
65    @ViewDebug.ExportedProperty(category = "launcher")
66    private float mTranslationYFactor;
67
68    public LauncherRecentsView(Context context) {
69        this(context, null);
70    }
71
72    public LauncherRecentsView(Context context, AttributeSet attrs) {
73        this(context, attrs, 0);
74    }
75
76    public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
77        super(context, attrs, defStyleAttr);
78        setContentAlpha(0);
79    }
80
81    @Override
82    protected void onAllTasksRemoved() {
83        mActivity.getStateManager().goToState(NORMAL);
84    }
85
86    @Override
87    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
88        super.onLayout(changed, left, top, right, bottom);
89        setTranslationYFactor(mTranslationYFactor);
90    }
91
92    public void setTranslationYFactor(float translationFactor) {
93        mTranslationYFactor = translationFactor;
94        setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
95    }
96
97    public float computeTranslationYForFactor(float translationYFactor) {
98        return translationYFactor * (getPaddingBottom() - getPaddingTop());
99    }
100
101    @Override
102    public void draw(Canvas canvas) {
103        maybeDrawEmptyMessage(canvas);
104        super.draw(canvas);
105    }
106
107    @Override
108    public void onViewAdded(View child) {
109        super.onViewAdded(child);
110        updateEmptyMessage();
111    }
112
113    @Override
114    protected void onTaskStackUpdated() {
115        // Lazily update the empty message only when the task stack is reapplied
116        updateEmptyMessage();
117    }
118
119    /**
120     * Animates adjacent tasks and translate hotseat off screen as well.
121     */
122    @Override
123    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv,
124            ClipAnimationHelper helper) {
125        AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
126
127        if (!OverviewInteractionState.getInstance(mActivity).isSwipeUpGestureEnabled()) {
128            // Hotseat doesn't move when opening recents with the button,
129            // so don't animate it here either.
130            return anim;
131        }
132
133        float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN;
134        LauncherState state = mActivity.getStateManager().getState();
135        if ((state.getVisibleElements(mActivity) & ALL_APPS_HEADER_EXTRA) != 0) {
136            float maxShiftRange = mActivity.getDeviceProfile().heightPx;
137            float currShiftRange = mActivity.getAllAppsController().getShiftRange();
138            allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange;
139        }
140        anim.play(ObjectAnimator.ofFloat(
141                mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
142
143        ObjectAnimator dragHandleAnim = ObjectAnimator.ofInt(
144                mActivity.findViewById(R.id.scrim_view), ScrimView.DRAG_HANDLE_ALPHA, 0);
145        dragHandleAnim.setInterpolator(Interpolators.ACCEL_2);
146        anim.play(dragHandleAnim);
147
148        return anim;
149    }
150
151    @Override
152    protected void getTaskSize(DeviceProfile dp, Rect outRect) {
153        LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
154    }
155
156    @Override
157    protected void onTaskLaunched(boolean success) {
158        if (success) {
159            mActivity.getStateManager().goToState(NORMAL, false /* animate */);
160        } else {
161            LauncherState state = mActivity.getStateManager().getState();
162            mActivity.getAllAppsController().setState(state);
163        }
164        super.onTaskLaunched(success);
165    }
166
167    @Override
168    public boolean shouldUseMultiWindowTaskSizeStrategy() {
169        return mActivity.isInMultiWindowModeCompat();
170    }
171}
172