OSDN Git Service

Refine snap position behavior
authorJorim Jaggi <jjaggi@google.com>
Mon, 21 Dec 2015 13:45:18 +0000 (14:45 +0100)
committerJorim Jaggi <jjaggi@google.com>
Tue, 5 Jan 2016 12:50:20 +0000 (13:50 +0100)
- Use the stable insets to communicate the system insets to the
docked divider view.
- When calculating the sizes for the snap positions, exclude the
system insets.
- Add 3 snap position modes: 16:9 in one window, 1:1, 16:9 in the
other (phone portrait). Only 1:1 (phone landscape). Fixed relation,
1:1, 1 - fixed relation (tablet portrait/landscape).

Change-Id: If2166c5fb99f12535eeab5de18e9f5aaf433d77c

core/res/res/values-land/config.xml [new file with mode: 0644]
core/res/res/values-sw600dp/config.xml
core/res/res/values/config.xml
core/res/res/values/dimens.xml
core/res/res/values/symbols.xml
packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
services/core/java/com/android/server/policy/PhoneWindowManager.java
services/core/java/com/android/server/wm/WindowState.java

diff --git a/core/res/res/values-land/config.xml b/core/res/res/values-land/config.xml
new file mode 100644 (file)
index 0000000..7308dc5
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <integer name="config_dockedStackDividerSnapMode">2</integer>
+</resources>
\ No newline at end of file
index 5a007ce..7f57ded 100644 (file)
@@ -40,5 +40,6 @@
     <!-- Use a larger scaling span for larger screen devices. -->
     <dimen name="config_minScalingSpan">32mm</dimen>
 
+    <integer name="config_dockedStackDividerSnapMode">1</integer>
 </resources>
 
index c03d471..d13a622 100644 (file)
 
     <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
     <string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
+
+    <!-- Controls the snap mode for the docked stack divider
+             0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
+             1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+             2 - 1 snap target: 1:1
+    -->
+    <integer name="config_dockedStackDividerSnapMode">0</integer>
 </resources>
index ef6b467..37b2c12 100644 (file)
 
     <item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
     <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+    <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
 </resources>
index 3c1d944..845c8c9 100644 (file)
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="docked_stack_divider_insets" />
+  <java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
+  <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
index 5af172c..9c70407 100644 (file)
 package com.android.systemui.stackdivider;
 
 import android.content.Context;
-import android.util.DisplayMetrics;
-import android.view.DisplayInfo;
+import android.graphics.Rect;
 
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
 import java.util.ArrayList;
 
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-
 /**
  * Calculates the snap targets and the snap position given a position and a velocity. All positions
  * here are to be interpreted as the left/top edge of the divider rectangle.
  */
 public class DividerSnapAlgorithm {
 
+    /**
+     * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
+     */
+    private static final int SNAP_MODE_16_9 = 0;
+
+    /**
+     * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+     */
+    private static final int SNAP_FIXED_RATIO = 1;
+
+    /**
+     * 1 snap target: 1:1
+     */
+    private static final int SNAP_ONLY_1_1 = 2;
+
     private final Context mContext;
     private final FlingAnimationUtils mFlingAnimationUtils;
+    private final int mDisplayWidth;
+    private final int mDisplayHeight;
     private final int mDividerSize;
-    private final ArrayList<SnapTarget> mTargets;
+    private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
+    private final Rect mInsets = new Rect();
+    private final int mSnapMode;
+    private final float mFixedRatio;
 
     /** The first target which is still splitting the screen */
     private final SnapTarget mFirstSplitTarget;
@@ -47,11 +64,19 @@ public class DividerSnapAlgorithm {
     private final SnapTarget mDismissEndTarget;
 
     public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
-            int dividerSize, boolean isHorizontalDivision) {
+            int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
+            Rect insets) {
         mContext = ctx;
         mFlingAnimationUtils = flingAnimationUtils;
         mDividerSize = dividerSize;
-        mTargets = calculateTargets(isHorizontalDivision);
+        mDisplayWidth = displayWidth;
+        mDisplayHeight = displayHeight;
+        mInsets.set(insets);
+        mSnapMode = ctx.getResources().getInteger(
+                com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+        mFixedRatio = ctx.getResources().getFraction(
+                com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
+        calculateTargets(isHorizontalDivision);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -89,22 +114,61 @@ public class DividerSnapAlgorithm {
         return mTargets.get(minIndex);
     }
 
-    private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
-        ArrayList<SnapTarget> targets = new ArrayList<>();
-        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+    private void calculateTargets(boolean isHorizontalDivision) {
+        mTargets.clear();
         int dividerMax = isHorizontalDivision
-                ? info.heightPixels
-                : info.widthPixels;
+                ? mDisplayHeight
+                : mDisplayWidth;
+        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+        switch (mSnapMode) {
+            case SNAP_MODE_16_9:
+                addRatio16_9Targets(isHorizontalDivision);
+                break;
+            case SNAP_FIXED_RATIO:
+                addFixedDivisionTargets(isHorizontalDivision);
+                break;
+            case SNAP_ONLY_1_1:
+                addMiddleTarget(isHorizontalDivision);
+                break;
+        }
+        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+    }
 
-        // TODO: Better calculation
-        targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
-        targets.add(new SnapTarget((int) (0.3415f * dividerMax) - mDividerSize / 2,
+    private void addFixedDivisionTargets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
                 SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget((int) (0.6585f * dividerMax) - mDividerSize / 2,
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
+                - mDividerSize / 2, SnapTarget.FLAG_NONE));
+    }
+
+    private void addRatio16_9Targets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
+        int endOther = isHorizontalDivision
+                ? mDisplayWidth - mInsets.right
+                : mDisplayHeight - mInsets.bottom;
+        float size = 9.0f / 16.0f * (endOther - startOther);
+        int sizeInt = (int) Math.floor(size);
+        mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
+    }
+
+    private void addMiddleTarget(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        mTargets.add(new SnapTarget(start + (end - start) / 2 - mDividerSize / 2,
                 SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
-        return targets;
     }
 
     /**
index a1d3a2a..23e5a17 100644 (file)
@@ -36,6 +36,7 @@ import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewTreeObserver.InternalInsetsInfo;
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -90,6 +91,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
     private VelocityTracker mVelocityTracker;
     private FlingAnimationUtils mFlingAnimationUtils;
     private DividerSnapAlgorithm mSnapAlgorithm;
+    private final Rect mStableInsets = new Rect();
 
     public DividerView(Context context) {
         super(context);
@@ -132,6 +134,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom());
+        return super.onApplyWindowInsets(insets);
+    }
+
     public void setWindowManager(DividerWindowManager windowManager) {
         mWindowManager = windowManager;
     }
@@ -142,8 +151,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
 
     public boolean startDragging() {
         mDockSide = mWindowManagerProxy.getDockSide();
-        mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
-                mDividerSize, isHorizontalDivision());
+        mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils, mDisplayWidth,
+                mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
             mWindowManager.setSlippery(false);
index 2251874..161f873 100644 (file)
@@ -50,6 +50,9 @@ public class DividerWindowManager {
                         | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         mLp.setTitle(WINDOW_TITLE);
+        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mWindowManager.addView(view, mLp);
         mView = view;
     }
index 6fcf1d6..c013412 100644 (file)
@@ -4243,6 +4243,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (attrs.type == TYPE_STATUS_BAR
                             || attrs.type == TYPE_TOAST
+                            || attrs.type == TYPE_DOCK_DIVIDER
                             || attrs.type == TYPE_VOICE_INTERACTION_STARTING
                             || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
index e51080e..4c38f92 100644 (file)
@@ -762,10 +762,20 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                 frame.right - mVisibleFrame.right,
                 frame.bottom - mVisibleFrame.bottom);
 
-        mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
-                Math.max(mStableFrame.top - frame.top, 0),
-                Math.max(frame.right - mStableFrame.right, 0),
-                Math.max(frame.bottom - mStableFrame.bottom, 0));
+        if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+
+            // For the docked divider, we calculate the stable insets like a full-screen window
+            // so it can use it to calculate the snap positions.
+            mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
+                    Math.max(mStableFrame.top - mDisplayFrame.top, 0),
+                    Math.max(mDisplayFrame.right - mStableFrame.right, 0),
+                    Math.max(mDisplayFrame.bottom - mStableFrame.bottom, 0));
+        } else {
+            mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
+                    Math.max(mStableFrame.top - frame.top, 0),
+                    Math.max(frame.right - mStableFrame.right, 0),
+                    Math.max(frame.bottom - mStableFrame.bottom, 0));
+        }
 
         if (!mInsetFrame.isEmpty()) {
             mContentFrame.set(mFrame);