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.statusbar.stack;
18
19import java.util.ArrayList;
20
21/**
22 * A Functor which interpolates the stack distance linearly based on base values.
23 * The base values are based on an interpolation between a linear function and a
24 * quadratic function
25 */
26public class PiecewiseLinearIndentationFunctor extends StackIndentationFunctor {
27
28    private final ArrayList<Float> mBaseValues;
29    private final float mLinearPart;
30
31    /**
32     * @param maxItemsInStack The maximum number of items which should be visible at the same time,
33     *                        i.e the function returns totalTransitionDistance for the element with
34     *                        index maxItemsInStack
35     * @param peekSize The visual appearance of this is how far the cards in the stack peek
36     *                 out below the top card and it is measured in real pixels.
37     *                 Note that the visual appearance does not necessarily always correspond to
38     *                 the actual visual distance below the top card but is a maximum,
39     *                 achieved when the next card just starts transitioning into the stack and
40     *                 the stack is full.
41     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
42     *                 first element transitions between 0 and distanceToPeekStart.
43     *                 Visualization:
44     *           ---------------------------------------------------   ---
45     *          |                                                   |   |
46     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
47     *          |                                                   |   |
48     *          |---------------------------------------------------|  ---  ---
49     *          |__________________SECOND ITEM______________________|        |  <- peekSize
50     *          |===================================================|       _|_
51     *
52     * @param distanceToPeekStart The distance to the start of the peak.
53     * @param linearPart The interpolation factor between the linear and the quadratic amount taken.
54     *                   This factor must be somewhere in [0 , 1]
55     */
56    PiecewiseLinearIndentationFunctor(int maxItemsInStack,
57                                      int peekSize,
58                                      int distanceToPeekStart,
59                                      float linearPart) {
60        super(maxItemsInStack, peekSize, distanceToPeekStart);
61        mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
62        initBaseValues();
63        mLinearPart = linearPart;
64    }
65
66    private void initBaseValues() {
67        int sumOfSquares = getSumOfSquares(mMaxItemsInStack-1);
68        int totalWeight = 0;
69        mBaseValues.add(0.0f);
70        for (int i = 0; i < mMaxItemsInStack - 1; i++) {
71            totalWeight += (mMaxItemsInStack - i - 1) * (mMaxItemsInStack - i - 1);
72            mBaseValues.add((float) totalWeight / sumOfSquares);
73        }
74    }
75
76    /**
77     * Get the sum of squares up to and including n, i.e sum(i * i, 1, n)
78     *
79     * @param n the maximum square to include
80     * @return
81     */
82    private int getSumOfSquares(int n) {
83        return n * (n + 1) * (2 * n + 1) / 6;
84    }
85
86    @Override
87    public float getValue(float itemsBefore) {
88        if (mStackStartsAtPeek) {
89            // We directly start at the stack, so no initial interpolation.
90            itemsBefore++;
91        }
92        if (itemsBefore < 0) {
93            return 0;
94        } else if (itemsBefore >= mMaxItemsInStack) {
95            return mTotalTransitionDistance;
96        }
97        int below = (int) itemsBefore;
98        float partialIn = itemsBefore - below;
99
100        if (below == 0) {
101            return mDistanceToPeekStart * partialIn;
102        } else {
103            float result = mDistanceToPeekStart;
104            float progress = mBaseValues.get(below - 1) * (1 - partialIn)
105                    + mBaseValues.get(below) * partialIn;
106            result += (progress * (1 - mLinearPart)
107                    + (itemsBefore - 1) / (mMaxItemsInStack - 1)  * mLinearPart) * mPeekSize;
108            return result;
109        }
110    }
111}
112