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
19f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ngimport static android.view.WindowManager.DOCKED_INVALID;
20f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ngimport static android.view.WindowManager.DOCKED_LEFT;
21f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ngimport static android.view.WindowManager.DOCKED_RIGHT;
22f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng
231fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggiimport android.content.Context;
2419cf2972582198484816ac15ba83a4f46946082bJorim Jaggiimport android.content.res.Configuration;
25737af724eb31f513386e91ee5510cc6991350937Jorim Jaggiimport android.content.res.Resources;
2681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggiimport android.graphics.Rect;
2719cf2972582198484816ac15ba83a4f46946082bJorim Jaggiimport android.hardware.display.DisplayManager;
2819cf2972582198484816ac15ba83a4f46946082bJorim Jaggiimport android.view.Display;
2919cf2972582198484816ac15ba83a4f46946082bJorim Jaggiimport android.view.DisplayInfo;
301fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
311fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggiimport java.util.ArrayList;
321fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
331fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi/**
341fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * Calculates the snap targets and the snap position given a position and a velocity. All positions
351fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi * here are to be interpreted as the left/top edge of the divider rectangle.
36737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi *
37737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi * @hide
381fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi */
391fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggipublic class DividerSnapAlgorithm {
401fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
41df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
42df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
43df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
4481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
4581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
4681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
4781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_MODE_16_9 = 0;
4881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
4981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
5081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
5181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
5281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_FIXED_RATIO = 1;
5381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
5481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    /**
5581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     * 1 snap target: 1:1
5681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi     */
5781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private static final int SNAP_ONLY_1_1 = 2;
5881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
59e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    /**
60e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng     * 1 snap target: minimized height, (1 - minimized height)
61e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng     */
62e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    private static final int SNAP_MODE_MINIMIZED = 3;
63e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng
64737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    private final float mMinFlingVelocityPxPerSecond;
65df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private final float mMinDismissVelocityPxPerSecond;
6681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mDisplayWidth;
6781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mDisplayHeight;
681fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final int mDividerSize;
6981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
7081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final Rect mInsets = new Rect();
7181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final int mSnapMode;
7219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    private final int mMinimalSizeResizableTask;
73e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    private final int mTaskHeightInMinimizedMode;
7481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private final float mFixedRatio;
751b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private boolean mIsHorizontalDivision;
761fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
771fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /** The first target which is still splitting the screen */
781fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mFirstSplitTarget;
791fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
801fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /** The last target which is still splitting the screen */
811fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mLastSplitTarget;
821fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
831fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mDismissStartTarget;
841fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    private final SnapTarget mDismissEndTarget;
85d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    private final SnapTarget mMiddleTarget;
861fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
8719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    public static DividerSnapAlgorithm create(Context ctx, Rect insets) {
8819cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        DisplayInfo displayInfo = new DisplayInfo();
8919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        ctx.getSystemService(DisplayManager.class).getDisplay(
9019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                Display.DEFAULT_DISPLAY).getDisplayInfo(displayInfo);
9119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int dividerWindowWidth = ctx.getResources().getDimensionPixelSize(
9219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                com.android.internal.R.dimen.docked_stack_divider_thickness);
9319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int dividerInsets = ctx.getResources().getDimensionPixelSize(
9419cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                com.android.internal.R.dimen.docked_stack_divider_insets);
9519cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        return new DividerSnapAlgorithm(ctx.getResources(),
9619cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                displayInfo.logicalWidth, displayInfo.logicalHeight,
9719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                dividerWindowWidth - 2 * dividerInsets,
989832f8f463a7d5448af2294bce05eac85f4dbef0Winson                ctx.getApplicationContext().getResources().getConfiguration().orientation
9919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                        == Configuration.ORIENTATION_PORTRAIT,
10019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                insets);
10119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    }
10219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi
103df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
104df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            boolean isHorizontalDivision, Rect insets) {
105f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
106f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng                DOCKED_INVALID, false);
107e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    }
108e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng
109e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
110303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        boolean isHorizontalDivision, Rect insets, int dockSide) {
111303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
112303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng            dockSide, false);
113303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng    }
114303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng
115303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
116f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng            boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) {
117df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mMinFlingVelocityPxPerSecond =
118df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
119df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        mMinDismissVelocityPxPerSecond =
120df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                MIN_DISMISS_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
1211fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDividerSize = dividerSize;
12281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mDisplayWidth = displayWidth;
12381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mDisplayHeight = displayHeight;
1241b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        mIsHorizontalDivision = isHorizontalDivision;
12581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mInsets.set(insets);
126e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng        mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
127e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng                res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
128737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        mFixedRatio = res.getFraction(
12981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
13019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        mMinimalSizeResizableTask = res.getDimensionPixelSize(
13119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                com.android.internal.R.dimen.default_minimal_size_resizable_task);
132e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng        mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
133e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng                com.android.internal.R.dimen.task_height_of_minimized_mode);
134f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng        calculateTargets(isHorizontalDivision, dockSide);
1351fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mFirstSplitTarget = mTargets.get(1);
1361fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mLastSplitTarget = mTargets.get(mTargets.size() - 2);
1371fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDismissStartTarget = mTargets.get(0);
1381fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        mDismissEndTarget = mTargets.get(mTargets.size() - 1);
139d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi        mMiddleTarget = mTargets.get(mTargets.size() / 2);
1401fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
1411fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
14219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    /**
14319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     * @return whether it's feasible to enable split screen in the current configuration, i.e. when
14419cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     *         snapping in the middle both tasks are larger than the minimal task size.
14519cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     */
14619cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    public boolean isSplitScreenFeasible() {
14719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int statusBarSize = mInsets.top;
14819cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int navBarSize = mIsHorizontalDivision ? mInsets.bottom : mInsets.right;
14919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int size = mIsHorizontalDivision
15019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                ? mDisplayHeight
15119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                : mDisplayWidth;
15219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int availableSpace = size - navBarSize - statusBarSize - mDividerSize;
15319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        return availableSpace / 2 >= mMinimalSizeResizableTask;
15419cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    }
15519cf2972582198484816ac15ba83a4f46946082bJorim Jaggi
1561fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    public SnapTarget calculateSnapTarget(int position, float velocity) {
157df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        return calculateSnapTarget(position, velocity, true /* hardDismiss */);
158df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    }
159df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
160df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    /**
161df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param position the top/left position of the divider
162df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param velocity current dragging velocity
163df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     * @param hardDismiss if set, make it a bit harder to get reach the dismiss targets
164df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi     */
165df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    public SnapTarget calculateSnapTarget(int position, float velocity, boolean hardDismiss) {
166df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (position < mFirstSplitTarget.position && velocity < -mMinDismissVelocityPxPerSecond) {
1671fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mDismissStartTarget;
1681fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
169df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (position > mLastSplitTarget.position && velocity > mMinDismissVelocityPxPerSecond) {
1701fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mDismissEndTarget;
1711fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
172df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
173df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            return snap(position, hardDismiss);
174df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        }
1751fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        if (velocity < 0) {
1761fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mFirstSplitTarget;
1771fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        } else {
1781fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            return mLastSplitTarget;
1791fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
1801fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
1811fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
182737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    public SnapTarget calculateNonDismissingSnapTarget(int position) {
183df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        SnapTarget target = snap(position, false /* hardDismiss */);
184737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        if (target == mDismissStartTarget) {
185737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return mFirstSplitTarget;
186737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        } else if (target == mDismissEndTarget) {
187737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return mLastSplitTarget;
188737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        } else {
189737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi            return target;
190737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi        }
191737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi    }
192737af724eb31f513386e91ee5510cc6991350937Jorim Jaggi
1935098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    public float calculateDismissingFraction(int position) {
1945098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        if (position < mFirstSplitTarget.position) {
1951b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return 1f - (float) (position - getStartInset())
1961b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi                    / (mFirstSplitTarget.position - getStartInset());
1975098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        } else if (position > mLastSplitTarget.position) {
1985098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return (float) (position - mLastSplitTarget.position)
19981ba11eccbc2519338782100c13cf4a5909ad6beJorim Jaggi                    / (mDismissEndTarget.position - mLastSplitTarget.position - mDividerSize);
2005098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        }
2015098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        return 0f;
2025098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    }
2035098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi
2045098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    public SnapTarget getClosestDismissTarget(int position) {
2058f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        if (position < mFirstSplitTarget.position) {
2068f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi            return mDismissStartTarget;
2078f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        } else if (position > mLastSplitTarget.position) {
2088f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi            return mDismissEndTarget;
2098f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi        } else if (position - mDismissStartTarget.position
2108f8155ba8a1c66d539101e55f2d06ae0422682c0Jorim Jaggi                < mDismissEndTarget.position - position) {
2115098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return mDismissStartTarget;
2125098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        } else {
2135098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi            return mDismissEndTarget;
2145098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi        }
2155098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi    }
2165098159ae31bc59aa3857fecb1847f8d7bb73e54Jorim Jaggi
217e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getFirstSplitTarget() {
218e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mFirstSplitTarget;
219e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
220e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
221e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getLastSplitTarget() {
222e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mLastSplitTarget;
223e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
224e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
225e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getDismissStartTarget() {
226e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mDismissStartTarget;
227e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
228e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
229e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    public SnapTarget getDismissEndTarget() {
230e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi        return mDismissEndTarget;
231e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi    }
232e435e982fa43832b183bac2d00d9415ac58ac06eJorim Jaggi
2331b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private int getStartInset() {
2341b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        if (mIsHorizontalDivision) {
2351b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.top;
2361b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        } else {
2371b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.left;
2381b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        }
2391b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    }
2401b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi
2411b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    private int getEndInset() {
2421b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        if (mIsHorizontalDivision) {
2431b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.bottom;
2441b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        } else {
2451b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi            return mInsets.right;
2461b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi        }
2471b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi    }
2481b12ef55b74f47eedde8afe22b997d40c3668a31Jorim Jaggi
249df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi    private SnapTarget snap(int position, boolean hardDismiss) {
2501fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int minIndex = -1;
251df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        float minDistance = Float.MAX_VALUE;
2521fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int size = mTargets.size();
2531fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        for (int i = 0; i < size; i++) {
254df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            SnapTarget target = mTargets.get(i);
255df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            float distance = Math.abs(position - target.position);
256df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            if (hardDismiss) {
257df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi                distance /= target.distanceMultiplier;
258df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            }
2591fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            if (distance < minDistance) {
2601fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi                minIndex = i;
2611fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi                minDistance = distance;
2621fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            }
2631fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
2641fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        return mTargets.get(minIndex);
2651fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
2661fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
267f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng    private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
26881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        mTargets.clear();
2691fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        int dividerMax = isHorizontalDivision
27081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight
27181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth;
272e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng        int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right;
273303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        int startPos = -mDividerSize;
274303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        if (dockedSide == DOCKED_RIGHT) {
275303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng            startPos += mInsets.left;
276303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        }
277303071233bff3cd4242f24d00a104a14091d54e0Matthew Ng        mTargets.add(new SnapTarget(startPos, startPos, SnapTarget.FLAG_DISMISS_START,
2788563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi                0.35f));
27981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        switch (mSnapMode) {
28081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_MODE_16_9:
28119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                addRatio16_9Targets(isHorizontalDivision, dividerMax);
28281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
28381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_FIXED_RATIO:
28419cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                addFixedDivisionTargets(isHorizontalDivision, dividerMax);
28581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
28681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi            case SNAP_ONLY_1_1:
28781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                addMiddleTarget(isHorizontalDivision);
28881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                break;
289e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng            case SNAP_MODE_MINIMIZED:
290f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng                addMinimizedTarget(isHorizontalDivision, dockedSide);
291e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng                break;
29281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        }
2938563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
2948563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi                SnapTarget.FLAG_DISMISS_END, 0.35f));
29581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
2961fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
29719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
29819cf2972582198484816ac15ba83a4f46946082bJorim Jaggi            int bottomPosition, int dividerMax) {
29919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        maybeAddTarget(topPosition, topPosition - mInsets.top);
30019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        addMiddleTarget(isHorizontalDivision);
30119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        maybeAddTarget(bottomPosition, dividerMax - mInsets.bottom
30219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi                - (bottomPosition + mDividerSize));
30319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    }
3048563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi
30519cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) {
30681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
30781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int end = isHorizontalDivision
30881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight - mInsets.bottom
30981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth - mInsets.right;
3108563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        int size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
3118563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        int topPosition = start + size;
3128563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        int bottomPosition = end - size - mDividerSize;
31319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
31481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
31581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
31619cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    private void addRatio16_9Targets(boolean isHorizontalDivision, int dividerMax) {
31781fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
31881fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int end = isHorizontalDivision
31981fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayHeight - mInsets.bottom
32081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayWidth - mInsets.right;
32181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
32281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int endOther = isHorizontalDivision
32381fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                ? mDisplayWidth - mInsets.right
32481fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi                : mDisplayHeight - mInsets.bottom;
32581fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        float size = 9.0f / 16.0f * (endOther - startOther);
32681fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi        int sizeInt = (int) Math.floor(size);
32719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int topPosition = start + sizeInt;
32819cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        int bottomPosition = end - sizeInt - mDividerSize;
32919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
33019cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    }
33119cf2972582198484816ac15ba83a4f46946082bJorim Jaggi
33219cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    /**
33319cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     * Adds a target at {@param position} but only if the area with size of {@param smallerSize}
33419cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     * meets the minimal size requirement.
33519cf2972582198484816ac15ba83a4f46946082bJorim Jaggi     */
33619cf2972582198484816ac15ba83a4f46946082bJorim Jaggi    private void maybeAddTarget(int position, int smallerSize) {
33719cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        if (smallerSize >= mMinimalSizeResizableTask) {
3388563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi            mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
33919cf2972582198484816ac15ba83a4f46946082bJorim Jaggi        }
34081fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    }
34181fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi
34281fe2d1f0adc9e752d7f1a410d66af6a326fd6e2Jorim Jaggi    private void addMiddleTarget(boolean isHorizontalDivision) {
3438563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
3448563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi                mInsets, mDisplayWidth, mDisplayHeight, mDividerSize);
3458563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
346e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng    }
347e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng
348f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng    private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
3497ccdb52fc98da546bdd565d0757f1fa09522862dMatthew Ng        // In portrait offset the position by the statusbar height, in landscape add the statusbar
3507ccdb52fc98da546bdd565d0757f1fa09522862dMatthew Ng        // height as well to match portrait offset
3517ccdb52fc98da546bdd565d0757f1fa09522862dMatthew Ng        int position = mTaskHeightInMinimizedMode + mInsets.top;
3527ccdb52fc98da546bdd565d0757f1fa09522862dMatthew Ng        if (!isHorizontalDivision) {
353f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng            if (dockedSide == DOCKED_LEFT) {
354f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng                position += mInsets.left;
355f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng            } else if (dockedSide == DOCKED_RIGHT) {
35662c7846bf89c170f1f41624866d3249a4e30a33aMatthew Ng                position = mDisplayWidth - position - mInsets.right - mDividerSize;
357f59a4132e8d65ab253f3f4cdd1e69f3f99526ba8Matthew Ng            }
3587ccdb52fc98da546bdd565d0757f1fa09522862dMatthew Ng        }
359e15352e516fb6ecde12866f0eb27c32470ddbdedMatthew Ng        mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
3601fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
3611fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
362d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    public SnapTarget getMiddleTarget() {
363d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi        return mMiddleTarget;
364d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi    }
365d434dcbfc9407baad28b6b40fea75b1b6050ad7eJorim Jaggi
36650cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    public SnapTarget getNextTarget(SnapTarget snapTarget) {
36750cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        int index = mTargets.indexOf(snapTarget);
36850cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        if (index != -1 && index < mTargets.size() - 1) {
36950cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi            return mTargets.get(index + 1);
37050cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        }
37150cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        return snapTarget;
37250cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    }
37350cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi
37450cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    public SnapTarget getPreviousTarget(SnapTarget snapTarget) {
37550cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        int index = mTargets.indexOf(snapTarget);
37650cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        if (index != -1 && index > 0) {
37750cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi            return mTargets.get(index - 1);
37850cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        }
37950cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi        return snapTarget;
38050cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi    }
38150cd6361d7cb50bdc0ee199f42307885abc65f0bJorim Jaggi
3826317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng    /**
3836317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng     * @return whether or not there are more than 1 split targets that do not include the two
3846317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng     * dismiss targets, used in deciding to display the middle target for accessibility
3856317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng     */
3866317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng    public boolean showMiddleSplitTargetForAccessibility() {
3876317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng        return (mTargets.size() - 2) > 1;
3886317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng    }
3896317df6e1e7bc1338089c8402efadccb39201abaMatthew Ng
390ce9630da86342c7bf30f00d1ced34a1d051c55baWinson    public boolean isFirstSplitTargetAvailable() {
391ce9630da86342c7bf30f00d1ced34a1d051c55baWinson        return mFirstSplitTarget != mMiddleTarget;
392ce9630da86342c7bf30f00d1ced34a1d051c55baWinson    }
393ce9630da86342c7bf30f00d1ced34a1d051c55baWinson
394ce9630da86342c7bf30f00d1ced34a1d051c55baWinson    public boolean isLastSplitTargetAvailable() {
395ce9630da86342c7bf30f00d1ced34a1d051c55baWinson        return mLastSplitTarget != mMiddleTarget;
396ce9630da86342c7bf30f00d1ced34a1d051c55baWinson    }
397ce9630da86342c7bf30f00d1ced34a1d051c55baWinson
3981fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    /**
399a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li     * Cycles through all non-dismiss targets with a stepping of {@param increment}. It moves left
400a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li     * if {@param increment} is negative and moves right otherwise.
401a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li     */
402a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li    public SnapTarget cycleNonDismissTarget(SnapTarget snapTarget, int increment) {
403a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li        int index = mTargets.indexOf(snapTarget);
404a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li        if (index != -1) {
405a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li            SnapTarget newTarget = mTargets.get((index + mTargets.size() + increment)
406a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li                    % mTargets.size());
407a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li            if (newTarget == mDismissStartTarget) {
408a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li                return mLastSplitTarget;
409a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li            } else if (newTarget == mDismissEndTarget) {
410a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li                return mFirstSplitTarget;
411a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li            } else {
412a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li                return newTarget;
413a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li            }
414a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li        }
415a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li        return snapTarget;
416a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li    }
417a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li
418a212999f245032f033e6a0993fd2be9832a9b9ccMuyuan Li    /**
4191fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi     * Represents a snap target for the divider.
4201fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi     */
4211fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    public static class SnapTarget {
4221fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_NONE = 0;
4231fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
4241fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        /** If the divider reaches this value, the left/top task should be dismissed. */
4251fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_DISMISS_START = 1;
4261fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
4271fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        /** If the divider reaches this value, the right/bottom task should be dismissed */
4281fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public static final int FLAG_DISMISS_END = 2;
4291fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
4308563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        /** Position of this snap target. The right/bottom edge of the top/left task snaps here. */
4311fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public final int position;
4328563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi
4338563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        /**
4348563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi         * Like {@link #position}, but used to calculate the task bounds which might be different
4358563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi         * from the stack bounds.
4368563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi         */
4378563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        public final int taskPosition;
4388563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi
4391fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        public final int flag;
4401fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi
441df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        /**
442df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         * Multiplier used to calculate distance to snap position. The lower this value, the harder
443df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         * it's to snap on this target
444df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi         */
445df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        private final float distanceMultiplier;
446df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
4478563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        public SnapTarget(int position, int taskPosition, int flag) {
4488563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi            this(position, taskPosition, flag, 1f);
449df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi        }
450df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi
4518563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi        public SnapTarget(int position, int taskPosition, int flag, float distanceMultiplier) {
4521fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            this.position = position;
4538563943bd39107b5a7ff9ea475592d0040423ba1Jorim Jaggi            this.taskPosition = taskPosition;
4541fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi            this.flag = flag;
455df012d5102735412d9f38513c103aa53df4bcab9Jorim Jaggi            this.distanceMultiplier = distanceMultiplier;
4561fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi        }
4571fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi    }
4581fcbab6ae5c99acab70eacc015d194e2c6ddd4e2Jorim Jaggi}
459