DividerSnapAlgorithm.java revision 1b12ef55b74f47eedde8afe22b997d40c3668a31
11fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi/*
21fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * Copyright (C) 2015 The Android Open Source Project
31fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi *
41fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
51fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * you may not use this file except in compliance with the License.
61fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * You may obtain a copy of the License at
71fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi *
81fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
91fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi *
101fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
111fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
121fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * See the License for the specific language governing permissions and
141fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * limitations under the License.
151fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi */
161fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
17737af724eb31f513386e91ee5510cc6991350937Jorim Jaggipackage com.android.internal.policy;
181fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
191fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggiimport android.content.Context;
20737af724eb31f513386e91ee5510cc6991350937Jorim Jaggiimport android.content.res.Resources;
2181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggiimport android.graphics.Rect;
22df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggiimport android.util.Log;
231fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
241fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggiimport java.util.ArrayList;
251fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
261fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi/**
271fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * Calculates the snap targets and the snap position given a position and a velocity. All positions
281fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * here are to be interpreted as the left/top edge of the divider rectangle.
29737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi *
30737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi * @hide
311fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi */
321fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggipublic class DividerSnapAlgorithm {
331fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
34df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
35df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
36df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
3781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
3881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
3981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
4081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_MODE_16_9 = 0;
4181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
4281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
4381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
4481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
4581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_FIXED_RATIO = 1;
4681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
4781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
4881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 1 snap target: 1:1
4981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
5081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_ONLY_1_1 = 2;
5181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
52737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    private final float mMinFlingVelocityPxPerSecond;
53df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private final float mMinDismissVelocityPxPerSecond;
5481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mDisplayWidth;
5581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mDisplayHeight;
561fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final int mDividerSize;
5781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
5881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final Rect mInsets = new Rect();
5981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mSnapMode;
6081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final float mFixedRatio;
611b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private boolean mIsHorizontalDivision;
621fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
631fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /** The first target which is still splitting the screen */
641fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mFirstSplitTarget;
651fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
661fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /** The last target which is still splitting the screen */
671fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mLastSplitTarget;
681fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
691fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mDismissStartTarget;
701fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mDismissEndTarget;
71d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    private final SnapTarget mMiddleTarget;
721fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
73df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
74df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            boolean isHorizontalDivision, Rect insets) {
75df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mMinFlingVelocityPxPerSecond =
76df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
77df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mMinDismissVelocityPxPerSecond =
78df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                MIN_DISMISS_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
791fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDividerSize = dividerSize;
8081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mDisplayWidth = displayWidth;
8181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mDisplayHeight = displayHeight;
821b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        mIsHorizontalDivision = isHorizontalDivision;
8381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mInsets.set(insets);
84737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        mSnapMode = res.getInteger(
8581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                com.android.internal.R.integer.config_dockedStackDividerSnapMode);
86737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        mFixedRatio = res.getFraction(
8781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
8881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        calculateTargets(isHorizontalDivision);
891fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mFirstSplitTarget = mTargets.get(1);
901fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mLastSplitTarget = mTargets.get(mTargets.size() - 2);
911fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDismissStartTarget = mTargets.get(0);
921fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDismissEndTarget = mTargets.get(mTargets.size() - 1);
93d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi        mMiddleTarget = mTargets.get(mTargets.size() / 2);
941fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
951fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
961fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    public SnapTarget calculateSnapTarget(int position, float velocity) {
97df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        return calculateSnapTarget(position, velocity, true /* hardDismiss */);
98df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    }
99df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
100df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    /**
101df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param position the top/left position of the divider
102df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param velocity current dragging velocity
103df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param hardDismiss if set, make it a bit harder to get reach the dismiss targets
104df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     */
105df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    public SnapTarget calculateSnapTarget(int position, float velocity, boolean hardDismiss) {
106df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (position < mFirstSplitTarget.position && velocity < -mMinDismissVelocityPxPerSecond) {
1071fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mDismissStartTarget;
1081fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
109df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (position > mLastSplitTarget.position && velocity > mMinDismissVelocityPxPerSecond) {
1101fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mDismissEndTarget;
1111fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
112df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
113df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            return snap(position, hardDismiss);
114df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        }
1151fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        if (velocity < 0) {
1161fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mFirstSplitTarget;
1171fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        } else {
1181fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mLastSplitTarget;
1191fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
1201fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
1211fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
122737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    public SnapTarget calculateNonDismissingSnapTarget(int position) {
123df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        SnapTarget target = snap(position, false /* hardDismiss */);
124737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        if (target == mDismissStartTarget) {
125737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return mFirstSplitTarget;
126737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        } else if (target == mDismissEndTarget) {
127737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return mLastSplitTarget;
128737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        } else {
129737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return target;
130737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        }
131737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    }
132737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi
1335098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    public float calculateDismissingFraction(int position) {
1345098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        if (position < mFirstSplitTarget.position) {
1351b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return 1f - (float) (position - getStartInset())
1361b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi                    / (mFirstSplitTarget.position - getStartInset());
1375098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        } else if (position > mLastSplitTarget.position) {
1385098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return (float) (position - mLastSplitTarget.position)
1391b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi                    / (mDismissEndTarget.position - getEndInset()
1401b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi                            - mLastSplitTarget.position - mDividerSize);
1415098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        }
1425098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        return 0f;
1435098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    }
1445098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi
1455098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    public SnapTarget getClosestDismissTarget(int position) {
1468f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        if (position < mFirstSplitTarget.position) {
1478f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi            return mDismissStartTarget;
1488f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        } else if (position > mLastSplitTarget.position) {
1498f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi            return mDismissEndTarget;
1508f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        } else if (position - mDismissStartTarget.position
1518f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi                < mDismissEndTarget.position - position) {
1525098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return mDismissStartTarget;
1535098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        } else {
1545098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return mDismissEndTarget;
1555098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        }
1565098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    }
1575098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi
158e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getFirstSplitTarget() {
159e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mFirstSplitTarget;
160e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
161e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
162e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getLastSplitTarget() {
163e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mLastSplitTarget;
164e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
165e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
166e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getDismissStartTarget() {
167e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mDismissStartTarget;
168e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
169e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
170e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getDismissEndTarget() {
171e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mDismissEndTarget;
172e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
173e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
1741b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private int getStartInset() {
1751b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        if (mIsHorizontalDivision) {
1761b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.top;
1771b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        } else {
1781b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.left;
1791b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        }
1801b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    }
1811b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi
1821b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private int getEndInset() {
1831b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        if (mIsHorizontalDivision) {
1841b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.bottom;
1851b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        } else {
1861b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.right;
1871b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        }
1881b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    }
1891b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi
190df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private SnapTarget snap(int position, boolean hardDismiss) {
1911fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int minIndex = -1;
192df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        float minDistance = Float.MAX_VALUE;
1931fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int size = mTargets.size();
1941fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        for (int i = 0; i < size; i++) {
195df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            SnapTarget target = mTargets.get(i);
196df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            float distance = Math.abs(position - target.position);
197df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            if (hardDismiss) {
198df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                distance /= target.distanceMultiplier;
199df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            }
2001fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            if (distance < minDistance) {
2011fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi                minIndex = i;
2021fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi                minDistance = distance;
2031fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            }
2041fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
2051fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        return mTargets.get(minIndex);
2061fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
2071fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
20881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private void calculateTargets(boolean isHorizontalDivision) {
20981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.clear();
2101fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int dividerMax = isHorizontalDivision
21181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight
21281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth;
213df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f));
21481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        switch (mSnapMode) {
21581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_MODE_16_9:
21681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                addRatio16_9Targets(isHorizontalDivision);
21781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
21881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_FIXED_RATIO:
21981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                addFixedDivisionTargets(isHorizontalDivision);
22081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
22181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_ONLY_1_1:
22281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                addMiddleTarget(isHorizontalDivision);
22381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
22481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        }
225df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
22681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
2271fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
22881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private void addFixedDivisionTargets(boolean isHorizontalDivision) {
22981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
23081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int end = isHorizontalDivision
23181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight - mInsets.bottom
23281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth - mInsets.right;
23381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
2341fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi                SnapTarget.FLAG_NONE));
23581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        addMiddleTarget(isHorizontalDivision);
23681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
23781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                - mDividerSize / 2, SnapTarget.FLAG_NONE));
23881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
23981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
24081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private void addRatio16_9Targets(boolean isHorizontalDivision) {
24181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
24281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int end = isHorizontalDivision
24381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight - mInsets.bottom
24481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth - mInsets.right;
24581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
24681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int endOther = isHorizontalDivision
24781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayWidth - mInsets.right
24881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayHeight - mInsets.bottom;
24981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        float size = 9.0f / 16.0f * (endOther - startOther);
25081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int sizeInt = (int) Math.floor(size);
25181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
25281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        addMiddleTarget(isHorizontalDivision);
25381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
25481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
25581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
25681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private void addMiddleTarget(boolean isHorizontalDivision) {
2573e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        mTargets.add(new SnapTarget(DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
2583e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                mInsets, mDisplayWidth, mDisplayHeight, mDividerSize), SnapTarget.FLAG_NONE));
2591fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
2601fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
261d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    public SnapTarget getMiddleTarget() {
262d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi        return mMiddleTarget;
263d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    }
264d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi
26550cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    public SnapTarget getNextTarget(SnapTarget snapTarget) {
26650cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        int index = mTargets.indexOf(snapTarget);
26750cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        if (index != -1 && index < mTargets.size() - 1) {
26850cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi            return mTargets.get(index + 1);
26950cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        }
27050cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        return snapTarget;
27150cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    }
27250cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi
27350cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    public SnapTarget getPreviousTarget(SnapTarget snapTarget) {
27450cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        int index = mTargets.indexOf(snapTarget);
27550cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        if (index != -1 && index > 0) {
27650cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi            return mTargets.get(index - 1);
27750cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        }
27850cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        return snapTarget;
27950cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    }
28050cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi
2811fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /**
2821fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi     * Represents a snap target for the divider.
2831fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi     */
2841fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    public static class SnapTarget {
2851fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_NONE = 0;
2861fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
2871fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        /** If the divider reaches this value, the left/top task should be dismissed. */
2881fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_DISMISS_START = 1;
2891fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
2901fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        /** If the divider reaches this value, the right/bottom task should be dismissed */
2911fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_DISMISS_END = 2;
2921fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
2931fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public final int position;
2941fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public final int flag;
2951fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
296df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        /**
297df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         * Multiplier used to calculate distance to snap position. The lower this value, the harder
298df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         * it's to snap on this target
299df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         */
300df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        private final float distanceMultiplier;
301df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
3021fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public SnapTarget(int position, int flag) {
303df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            this(position, flag, 1f);
304df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        }
305df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
306df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        public SnapTarget(int position, int flag, float distanceMultiplier) {
3071fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            this.position = position;
3081fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            this.flag = flag;
309df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            this.distanceMultiplier = distanceMultiplier;
3101fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
3111fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
3121fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi}
313