TaskStackViewLayoutAlgorithm.java revision ffa2ec664479bff6b4b61d4c349d9db2cb37ca16
1/*
2 * Copyright (C) 2014 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 */
16
17package com.android.systemui.recents.views;
18
19import android.graphics.Rect;
20import com.android.systemui.recents.Constants;
21import com.android.systemui.recents.RecentsConfiguration;
22import com.android.systemui.recents.misc.Utilities;
23
24/* The layout logic for a TaskStackView */
25public class TaskStackViewLayoutAlgorithm {
26
27    // These are all going to change
28    static final float StackOverlapPct = 0.65f; // The overlap height relative to the task height
29    static final float StackPeekHeightPct = 0.1f; // The height of the peek space relative to the stack height
30    static final float StackPeekMinScale = 0.8f; // The min scale of the last card in the peek area
31    static final int StackPeekNumCards = 3; // The number of cards we see in the peek space
32
33    RecentsConfiguration mConfig;
34
35    // The various rects that define the stack view
36    Rect mRect = new Rect();
37    Rect mStackRect = new Rect();
38    Rect mStackRectSansPeek = new Rect();
39    Rect mTaskRect = new Rect();
40
41    // The min/max scroll
42    int mMinScroll;
43    int mMaxScroll;
44
45    public TaskStackViewLayoutAlgorithm(RecentsConfiguration config) {
46        mConfig = config;
47    }
48
49    /** Computes the stack and task rects */
50    public void computeRects(int width, int height, int insetLeft, int insetBottom) {
51        // Note: We let the stack view be the full height because we want the cards to go under the
52        //       navigation bar if possible.  However, the stack rects which we use to calculate
53        //       max scroll, etc. need to take the nav bar into account
54
55        // Compute the stack rects
56        mRect.set(0, 0, width, height);
57        mStackRect.set(mRect);
58        mStackRect.left += insetLeft;
59        mStackRect.bottom -= insetBottom;
60
61        int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
62        int heightPadding = mConfig.taskStackTopPaddingPx;
63        if (Constants.DebugFlags.App.EnableSearchLayout) {
64            mStackRect.top += heightPadding;
65            mStackRect.left += widthPadding;
66            mStackRect.right -= widthPadding;
67            mStackRect.bottom -= heightPadding;
68        } else {
69            mStackRect.inset(widthPadding, heightPadding);
70        }
71        mStackRectSansPeek.set(mStackRect);
72        mStackRectSansPeek.top += StackPeekHeightPct * mStackRect.height();
73
74        // Compute the task rect
75        int size = mStackRect.width();
76        int left = mStackRect.left + (mStackRect.width() - size) / 2;
77        mTaskRect.set(left, mStackRectSansPeek.top,
78                left + size, mStackRectSansPeek.top + size);
79    }
80
81    void computeMinMaxScroll(int taskCount) {
82        // Compute the min and max scroll values
83        int numTasks = Math.max(1, taskCount);
84        int taskHeight = mTaskRect.height();
85        int stackHeight = mStackRectSansPeek.height();
86        int maxScrollHeight = taskHeight + getStackScrollForTaskIndex(numTasks - 1);
87
88        if (numTasks <= 1) {
89            // If there is only one task, then center the task in the stack rect (sans peek)
90            mMinScroll = mMaxScroll = -(stackHeight - taskHeight) / 2;
91        } else {
92            mMinScroll = Math.min(stackHeight, maxScrollHeight) - stackHeight;
93            mMaxScroll = maxScrollHeight - stackHeight;
94        }
95    }
96
97    /** Update/get the transform */
98    public TaskViewTransform getStackTransform(int groupIndexInStack, int taskIndexInGroup,
99                                               int stackScroll, TaskViewTransform transformOut) {
100        // Return early if we have an invalid index
101        if (groupIndexInStack < 0) {
102            transformOut.reset();
103            return transformOut;
104        }
105
106        // Map the items to an continuous position relative to the specified scroll
107        int numPeekCards = StackPeekNumCards;
108        float overlapHeight = StackOverlapPct * mTaskRect.height();
109        float peekHeight = StackPeekHeightPct * mStackRect.height();
110        float t = ((groupIndexInStack * overlapHeight) - stackScroll) / overlapHeight;
111        float boundedT = Math.max(t, -(numPeekCards + 1));
112
113        // Set the scale relative to its position
114        int numFrontScaledCards = 3;
115        float minScale = StackPeekMinScale;
116        float scaleRange = 1f - minScale;
117        float scaleInc = scaleRange / (numPeekCards + numFrontScaledCards);
118        float scale = Math.max(minScale, Math.min(1f, minScale +
119            ((boundedT + (numPeekCards + 1)) * scaleInc)));
120        float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2;
121        transformOut.scale = scale;
122
123        // Set the y translation
124        if (boundedT < 0f) {
125            transformOut.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
126                    numPeekCards) * peekHeight - scaleYOffset);
127        } else {
128            transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
129        }
130        transformOut.translationY += 100 * taskIndexInGroup;
131
132        // Set the z translation
133        int minZ = mConfig.taskViewTranslationZMinPx;
134        int incZ = mConfig.taskViewTranslationZIncrementPx;
135        transformOut.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
136
137        // Set the alphas
138        transformOut.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
139
140        // Update the rect and visibility
141        transformOut.rect.set(mTaskRect);
142        if (t < -(numPeekCards + 1)) {
143            transformOut.visible = false;
144        } else {
145            transformOut.rect.offset(0, transformOut.translationY);
146            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
147            transformOut.visible = Rect.intersects(mRect, transformOut.rect);
148        }
149        transformOut.t = t;
150        return transformOut;
151    }
152
153    /**
154     * Returns the overlap between one task and the next.
155     */
156    float getTaskOverlapHeight() {
157        return StackOverlapPct * mTaskRect.height();
158    }
159
160    /**
161     * Returns the scroll to such that the task transform at that index will have t=0. (If the scroll
162     * is not bounded)
163     */
164    int getStackScrollForTaskIndex(int i) {
165        return (int) (i * getTaskOverlapHeight());
166    }
167
168}