blob: 8c5d319439babe2469a8bb513c0e6ef4b08c21af [file] [log] [blame]
Filip Gruszczynski466f3212015-09-21 17:57:57 -07001/*
2 * Copyright (C) 2012 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.server.wm;
18
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070019import static android.app.ActivityManager.DOCKED_STACK_ID;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070020import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
22import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
23import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
24import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING;
25import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
26import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070027import static com.android.server.wm.TaskStack.DOCKED_BOTTOM;
28import static com.android.server.wm.TaskStack.DOCKED_INVALID;
29import static com.android.server.wm.TaskStack.DOCKED_LEFT;
30import static com.android.server.wm.TaskStack.DOCKED_RIGHT;
31import static com.android.server.wm.TaskStack.DOCKED_TOP;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070032
33import android.content.Context;
34import android.graphics.PixelFormat;
35import android.graphics.Rect;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070036import android.os.RemoteException;
37import android.util.Slog;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070038import android.view.LayoutInflater;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070039import android.view.MotionEvent;
Filip Gruszczynski466f3212015-09-21 17:57:57 -070040import android.view.View;
41import android.view.WindowManager;
42import android.view.WindowManagerGlobal;
43
44/**
45 * Controls showing and hiding of a docked stack divider on the display.
46 */
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070047public class DockedStackDividerController implements View.OnTouchListener {
Filip Gruszczynski466f3212015-09-21 17:57:57 -070048 private static final String TAG = "DockedStackDivider";
49 private final Context mContext;
50 private final int mDividerWidth;
51 private final DisplayContent mDisplayContent;
52 private View mView;
53 private Rect mTmpRect = new Rect();
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070054 private Rect mLastResizeRect = new Rect();
55 private int mStartX;
56 private int mStartY;
57 private TaskStack mTaskStack;
58 private Rect mOriginalRect = new Rect();
59 private int mDockSide;
60
Filip Gruszczynski466f3212015-09-21 17:57:57 -070061
62 DockedStackDividerController(Context context, DisplayContent displayContent) {
63 mContext = context;
64 mDisplayContent = displayContent;
65 mDividerWidth = context.getResources().getDimensionPixelSize(
66 com.android.internal.R.dimen.docked_stack_divider_thickness);
67 }
68
69 private void addDivider() {
70 View view = LayoutInflater.from(mContext).inflate(
71 com.android.internal.R.layout.docked_stack_divider, null);
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070072 view.setOnTouchListener(this);
Filip Gruszczynski466f3212015-09-21 17:57:57 -070073 WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
74 WindowManager.LayoutParams params = new WindowManager.LayoutParams(
75 mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
76 FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
77 | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
78 PixelFormat.OPAQUE);
79 params.setTitle(TAG);
80 manager.addView(view, params, mDisplayContent.getDisplay(), null);
81 mView = view;
82 }
83
84 private void removeDivider() {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070085 mView.setOnTouchListener(null);
Filip Gruszczynski466f3212015-09-21 17:57:57 -070086 WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
87 manager.removeView(mView, true /* immediate */);
88 mView = null;
89 }
90
91 boolean hasDivider() {
92 return mView != null;
93 }
94
95 void update() {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -070096 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -070097 if (stack != null && mView == null) {
98 addDivider();
99 } else if (stack == null && mView != null) {
100 removeDivider();
101 }
102 }
103
104 int getWidth() {
105 return mDividerWidth;
106 }
107
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700108 void positionDockedStackedDivider(Rect frame) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700109 TaskStack stack = mDisplayContent.getDockedStackLocked();
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700110 if (stack == null) {
111 // Unfortunately we might end up with still having a divider, even though the underlying
112 // stack was already removed. This is because we are on AM thread and the removal of the
113 // divider was deferred to WM thread and hasn't happened yet.
114 return;
115 }
116 final @TaskStack.DockSide int side = stack.getDockSide();
117 stack.getBounds(mTmpRect);
118 switch (side) {
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700119 case DOCKED_LEFT:
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700120 frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
121 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700122 case DOCKED_TOP:
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700123 frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
124 mTmpRect.bottom + frame.height());
125 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700126 case DOCKED_RIGHT:
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700127 frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
128 break;
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700129 case DOCKED_BOTTOM:
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700130 frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
131 break;
132 }
133 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700134
135 @Override
136 public boolean onTouch(View v, MotionEvent event) {
137 final int action = event.getAction() & MotionEvent.ACTION_MASK;
138 switch (action) {
139 case MotionEvent.ACTION_DOWN:
140 // We use raw values, because getX/Y() would give us results relative to the
141 // dock divider bounds.
142 mStartX = (int) event.getRawX();
143 mStartY = (int) event.getRawY();
144 synchronized (mDisplayContent.mService.mWindowMap) {
145 mTaskStack = mDisplayContent.getDockedStackLocked();
146 mTaskStack.getBounds(mOriginalRect);
147 mDockSide = mTaskStack.getDockSide();
148 }
149 break;
150 case MotionEvent.ACTION_MOVE:
151 if (mTaskStack != null) {
152 resizeStack(event);
153 }
154 break;
155 case MotionEvent.ACTION_UP:
156 case MotionEvent.ACTION_CANCEL:
157 mTaskStack = null;
158 mDockSide = TaskStack.DOCKED_INVALID;
159 break;
160 }
161 return true;
162 }
163
164 private void resizeStack(MotionEvent event) {
165 mTmpRect.set(mOriginalRect);
166 final int deltaX = (int) event.getRawX() - mStartX;
167 final int deltaY = (int) event.getRawY() - mStartY;
168 switch (mDockSide) {
169 case DOCKED_LEFT:
170 mTmpRect.right += deltaX;
171 break;
172 case DOCKED_TOP:
173 mTmpRect.bottom += deltaY;
174 break;
175 case DOCKED_RIGHT:
176 mTmpRect.left += deltaX;
177 break;
178 case DOCKED_BOTTOM:
179 mTmpRect.top += deltaY;
180 break;
181 }
182 if (mTmpRect.equals(mLastResizeRect)) {
183 return;
184 }
185 mLastResizeRect.set(mTmpRect);
186 try {
187 mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect);
188 } catch (RemoteException e) {
189 }
190 }
191
192 boolean isResizing() {
193 return mTaskStack != null;
194 }
195
196 int getWidthAdjustment() {
197 return getWidth() / 2;
198 }
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700199}