blob: 1848d4ea438bf0d214de798e5346627f8875f8d6 [file] [log] [blame]
Daniel Sandlerc4f2a562012-05-04 11:55:46 -04001/*
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.systemui.statusbar.phone;
18
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070019import android.annotation.ColorInt;
20import android.annotation.DrawableRes;
21import android.annotation.LayoutRes;
John Spurlock257f2832013-09-21 18:41:53 -040022import android.app.StatusBarManager;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040023import android.content.Context;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070024import android.content.res.Configuration;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070025import android.content.res.TypedArray;
Daniel Sandler198a0302012-08-17 16:04:31 -040026import android.graphics.Canvas;
27import android.graphics.Paint;
Selim Cineka0fad3b2014-09-19 17:20:05 +020028import android.graphics.PorterDuff;
29import android.graphics.PorterDuffXfermode;
John Spurlockfba91202014-04-22 12:58:26 -040030import android.graphics.Rect;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070031import android.graphics.drawable.Drawable;
Jaewan Kim50269362016-12-23 11:22:02 +090032import android.media.AudioManager;
John Spurlock0b99ea92014-10-01 15:32:22 -040033import android.media.session.MediaSessionLegacyHelper;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070034import android.net.Uri;
35import android.os.Bundle;
Selim Cineka0fad3b2014-09-19 17:20:05 +020036import android.os.IBinder;
Adrian Roos8008bd12017-02-22 15:02:09 +010037import android.os.SystemClock;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040038import android.util.AttributeSet;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070039import android.view.ActionMode;
40import android.view.InputQueue;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040041import android.view.KeyEvent;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070042import android.view.LayoutInflater;
43import android.view.Menu;
44import android.view.MenuItem;
Chris Wren5de6e942012-05-16 14:22:21 -040045import android.view.MotionEvent;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070046import android.view.SurfaceHolder;
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -070047import android.view.View;
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070048import android.view.ViewGroup;
49import android.view.ViewTreeObserver;
50import android.view.Window;
Selim Cineka0fad3b2014-09-19 17:20:05 +020051import android.view.WindowManager;
52import android.view.WindowManagerGlobal;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040053import android.widget.FrameLayout;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040054
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070055import com.android.internal.view.FloatingActionMode;
56import com.android.internal.widget.FloatingToolbar;
Chris Wren5de6e942012-05-16 14:22:21 -040057import com.android.systemui.R;
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070058import com.android.systemui.classifier.FalsingManager;
Jorim Jaggiecbab362014-04-23 16:13:15 +020059import com.android.systemui.statusbar.DragDownHelper;
60import com.android.systemui.statusbar.StatusBarState;
Selim Cinekfab078b2014-03-27 22:45:58 +010061import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
Chris Wren5de6e942012-05-16 14:22:21 -040062
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040063
Jorim Jaggiecbab362014-04-23 16:13:15 +020064public class StatusBarWindowView extends FrameLayout {
Daniel Sandler198a0302012-08-17 16:04:31 -040065 public static final String TAG = "StatusBarWindowView";
Jason Monk2a6ea9c2017-01-26 11:14:51 -050066 public static final boolean DEBUG = StatusBar.DEBUG;
Chris Wren5de6e942012-05-16 14:22:21 -040067
Jorim Jaggiecbab362014-04-23 16:13:15 +020068 private DragDownHelper mDragDownHelper;
Adrian Roos8008bd12017-02-22 15:02:09 +010069 private DoubleTapHelper mDoubleTapHelper;
Selim Cinekb6d85eb2014-03-28 20:21:01 +010070 private NotificationStackScrollLayout mStackScrollLayout;
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -070071 private NotificationPanelView mNotificationPanel;
Adrian Roos9dc32092014-09-02 23:34:10 +020072 private View mBrightnessMirror;
Chris Wren5de6e942012-05-16 14:22:21 -040073
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070074 private int mRightInset = 0;
Adrian Roos85d202b2016-06-02 16:27:47 -070075 private int mLeftInset = 0;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -070076
Jason Monk2a6ea9c2017-01-26 11:14:51 -050077 private StatusBar mService;
Selim Cineka0fad3b2014-09-19 17:20:05 +020078 private final Paint mTransparentSrcPaint = new Paint();
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070079 private FalsingManager mFalsingManager;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040080
Adrian Roos0bd8a4b2016-03-14 16:21:44 -070081 // Implements the floating action mode for TextView's Cut/Copy/Past menu. Normally provided by
82 // DecorView, but since this is a special window we have to roll our own.
83 private View mFloatingActionModeOriginatingView;
84 private ActionMode mFloatingActionMode;
85 private FloatingToolbar mFloatingToolbar;
86 private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
87
Daniel Sandlerc4f2a562012-05-04 11:55:46 -040088 public StatusBarWindowView(Context context, AttributeSet attrs) {
89 super(context, attrs);
Chris Wren5de6e942012-05-16 14:22:21 -040090 setMotionEventSplittingEnabled(false);
Selim Cineka0fad3b2014-09-19 17:20:05 +020091 mTransparentSrcPaint.setColor(0);
92 mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -070093 mFalsingManager = FalsingManager.getInstance(context);
Adrian Roos8008bd12017-02-22 15:02:09 +010094 mDoubleTapHelper = new DoubleTapHelper(this, active -> {}, () -> {
95 mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this);
96 return true;
97 }, null, null);
Chris Wren5de6e942012-05-16 14:22:21 -040098 }
99
100 @Override
John Spurlockfba91202014-04-22 12:58:26 -0400101 protected boolean fitSystemWindows(Rect insets) {
102 if (getFitsSystemWindows()) {
Adrian Roos85d202b2016-06-02 16:27:47 -0700103 boolean paddingChanged = insets.top != getPaddingTop()
Jorim Jaggi416493b2014-09-13 03:57:32 +0200104 || insets.bottom != getPaddingBottom();
Jorim Jaggiaa806142015-05-20 18:04:16 -0700105
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700106 // Super-special right inset handling, because scrims and backdrop need to ignore it.
Adrian Roos85d202b2016-06-02 16:27:47 -0700107 if (insets.right != mRightInset || insets.left != mLeftInset) {
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700108 mRightInset = insets.right;
Adrian Roos85d202b2016-06-02 16:27:47 -0700109 mLeftInset = insets.left;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700110 applyMargins();
111 }
Adrian Roos85d202b2016-06-02 16:27:47 -0700112 // Drop top inset, and pass through bottom inset.
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700113 if (paddingChanged) {
Adrian Roos85d202b2016-06-02 16:27:47 -0700114 setPadding(0, 0, 0, 0);
Jorim Jaggi416493b2014-09-13 03:57:32 +0200115 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200116 insets.left = 0;
117 insets.top = 0;
118 insets.right = 0;
John Spurlockfba91202014-04-22 12:58:26 -0400119 } else {
Adrian Roos85d202b2016-06-02 16:27:47 -0700120 if (mRightInset != 0 || mLeftInset != 0) {
Adrian Roose49e4092015-06-10 18:50:18 -0700121 mRightInset = 0;
Adrian Roos85d202b2016-06-02 16:27:47 -0700122 mLeftInset = 0;
Adrian Roose49e4092015-06-10 18:50:18 -0700123 applyMargins();
124 }
Jorim Jaggi416493b2014-09-13 03:57:32 +0200125 boolean changed = getPaddingLeft() != 0
126 || getPaddingRight() != 0
127 || getPaddingTop() != 0
128 || getPaddingBottom() != 0;
129 if (changed) {
130 setPadding(0, 0, 0, 0);
131 }
Jorim Jaggiaa806142015-05-20 18:04:16 -0700132 insets.top = 0;
John Spurlockfba91202014-04-22 12:58:26 -0400133 }
Jorim Jaggid7daab72014-05-06 22:22:20 +0200134 return false;
John Spurlockfba91202014-04-22 12:58:26 -0400135 }
136
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700137 private void applyMargins() {
138 final int N = getChildCount();
139 for (int i = 0; i < N; i++) {
140 View child = getChildAt(i);
141 if (child.getLayoutParams() instanceof LayoutParams) {
142 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Adrian Roos85d202b2016-06-02 16:27:47 -0700143 if (!lp.ignoreRightInset
144 && (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset)) {
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700145 lp.rightMargin = mRightInset;
Adrian Roos85d202b2016-06-02 16:27:47 -0700146 lp.leftMargin = mLeftInset;
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700147 child.requestLayout();
148 }
149 }
150 }
151 }
152
153 @Override
154 public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
155 return new LayoutParams(getContext(), attrs);
156 }
157
158 @Override
159 protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
160 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
161 }
162
John Spurlockfba91202014-04-22 12:58:26 -0400163 @Override
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400164 protected void onFinishInflate() {
165 super.onFinishInflate();
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100166 mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
167 R.id.notification_stack_scroller);
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700168 mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
Adrian Roos9dc32092014-09-02 23:34:10 +0200169 mBrightnessMirror = findViewById(R.id.brightness_mirror);
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400170 }
171
dooyoung.hwange4b841e2016-11-16 08:59:23 +0900172 @Override
173 public void onViewAdded(View child) {
174 super.onViewAdded(child);
175 if (child.getId() == R.id.brightness_mirror) {
176 mBrightnessMirror = child;
177 }
178 }
179
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500180 public void setService(StatusBar service) {
Selim Cinek4e6b2d32015-06-25 20:15:33 -0400181 mService = service;
182 mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
183 }
184
185 @Override
186 protected void onAttachedToWindow () {
187 super.onAttachedToWindow();
Daniel Sandlerb10d8852013-05-08 15:57:06 -0400188
Selim Cineka0fad3b2014-09-19 17:20:05 +0200189 // We need to ensure that our window doesn't suffer from overdraw which would normally
190 // occur if our window is translucent. Since we are drawing the whole window anyway with
191 // the scrim, we don't need the window to be cleared in the beginning.
Jorim Jaggi0e664392014-09-27 01:30:22 +0200192 if (mService.isScrimSrcModeEnabled()) {
193 IBinder windowToken = getWindowToken();
194 WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
195 lp.token = windowToken;
196 setLayoutParams(lp);
197 WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true);
198 setWillNotDraw(false);
199 } else {
200 setWillNotDraw(!DEBUG);
201 }
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400202 }
203
204 @Override
205 public boolean dispatchKeyEvent(KeyEvent event) {
Adrian Roos56cf73a2016-07-18 14:23:32 -0700206 if (mService.interceptMediaKey(event)) {
207 return true;
208 }
209 if (super.dispatchKeyEvent(event)) {
210 return true;
211 }
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400212 boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
213 switch (event.getKeyCode()) {
Jorim Jaggi8c8bcc12014-04-16 21:36:51 +0200214 case KeyEvent.KEYCODE_BACK:
215 if (!down) {
216 mService.onBackPressed();
217 }
218 return true;
219 case KeyEvent.KEYCODE_MENU:
220 if (!down) {
221 return mService.onMenuPressed();
222 }
Jorim Jaggi34250762014-07-03 23:51:19 +0200223 case KeyEvent.KEYCODE_SPACE:
224 if (!down) {
225 return mService.onSpacePressed();
226 }
John Spurlock0b99ea92014-10-01 15:32:22 -0400227 break;
John Spurlockd06aa572014-09-10 10:40:49 -0400228 case KeyEvent.KEYCODE_VOLUME_DOWN:
229 case KeyEvent.KEYCODE_VOLUME_UP:
John Spurlock0b99ea92014-10-01 15:32:22 -0400230 if (mService.isDozing()) {
Jaewan Kim50269362016-12-23 11:22:02 +0900231 MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
232 event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
John Spurlock0b99ea92014-10-01 15:32:22 -0400233 return true;
John Spurlockd06aa572014-09-10 10:40:49 -0400234 }
John Spurlock0b99ea92014-10-01 15:32:22 -0400235 break;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400236 }
Adrian Roos56cf73a2016-07-18 14:23:32 -0700237 return false;
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400238 }
Chris Wren5de6e942012-05-16 14:22:21 -0400239
240 @Override
Adrian Roos9dc32092014-09-02 23:34:10 +0200241 public boolean dispatchTouchEvent(MotionEvent ev) {
Jorim Jaggie05256e2016-09-08 14:58:20 -0700242 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
Selim Cinek48ff9b42016-11-09 19:31:51 -0800243 && mNotificationPanel.isFullyCollapsed()) {
Jorim Jaggie05256e2016-09-08 14:58:20 -0700244 mNotificationPanel.startExpandLatencyTracking();
245 }
Blazej Magnowski0e2ffbd2015-09-10 14:37:17 -0700246 mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
Adrian Roos9dc32092014-09-02 23:34:10 +0200247 if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
248 // Disallow new pointers while the brightness mirror is visible. This is so that you
249 // can't touch anything other than the brightness slider while the mirror is showing
250 // and the rest of the panel is transparent.
251 if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
252 return false;
253 }
254 }
Mady Mellor7a9b2a62016-03-23 07:41:47 -0700255 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
256 mStackScrollLayout.closeControlsIfOutsideTouch(ev);
257 }
258
Adrian Roos9dc32092014-09-02 23:34:10 +0200259 return super.dispatchTouchEvent(ev);
260 }
261
262 @Override
Chris Wren5de6e942012-05-16 14:22:21 -0400263 public boolean onInterceptTouchEvent(MotionEvent ev) {
Adrian Roosebea7a72016-10-26 12:51:26 -0700264 if (mService.isDozing() && !mService.isPulsing()) {
Adrian Roos8008bd12017-02-22 15:02:09 +0100265 // Capture all touch events in always-on.
Adrian Roosebea7a72016-10-26 12:51:26 -0700266 return true;
267 }
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700268 boolean intercept = false;
Selim Cinekfab078b2014-03-27 22:45:58 +0100269 if (mNotificationPanel.isFullyExpanded()
Jorim Jaggi03c701e2014-04-02 12:39:51 +0200270 && mStackScrollLayout.getVisibility() == View.VISIBLE
Jorim Jaggi4222d9a2014-04-23 16:13:15 +0200271 && mService.getBarState() == StatusBarState.KEYGUARD
Adrian Roos500263a2017-01-23 14:49:54 -0800272 && !mService.isBouncerShowing()
273 && !mService.isDozing()) {
Jorim Jaggiecbab362014-04-23 16:13:15 +0200274 intercept = mDragDownHelper.onInterceptTouchEvent(ev);
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700275 }
276 if (!intercept) {
277 super.onInterceptTouchEvent(ev);
278 }
Chris Wren5de6e942012-05-16 14:22:21 -0400279 if (intercept) {
Dianne Hackborna4b7f2f2012-05-21 11:28:41 -0700280 MotionEvent cancellation = MotionEvent.obtain(ev);
281 cancellation.setAction(MotionEvent.ACTION_CANCEL);
Selim Cinekb6d85eb2014-03-28 20:21:01 +0100282 mStackScrollLayout.onInterceptTouchEvent(cancellation);
Selim Cinek31094df2014-08-14 19:28:15 +0200283 mNotificationPanel.onInterceptTouchEvent(cancellation);
Dianne Hackborna4b7f2f2012-05-21 11:28:41 -0700284 cancellation.recycle();
Chris Wren5de6e942012-05-16 14:22:21 -0400285 }
286 return intercept;
287 }
288
289 @Override
290 public boolean onTouchEvent(MotionEvent ev) {
Adrian Roos8008bd12017-02-22 15:02:09 +0100291 boolean handled = false;
292 if (mService.isDozing()) {
293 mDoubleTapHelper.onTouchEvent(ev);
294 handled = true;
295 }
Selim Cinek740c1112016-12-22 16:39:54 +0100296 if (mService.getBarState() == StatusBarState.KEYGUARD
297 && (!handled || mDragDownHelper.isDraggingDown())) {
298 // we still want to finish our drag down gesture when locking the screen
Jorim Jaggiecbab362014-04-23 16:13:15 +0200299 handled = mDragDownHelper.onTouchEvent(ev);
Daniel Sandlerb4e56ed2012-09-12 23:07:44 -0700300 }
301 if (!handled) {
302 handled = super.onTouchEvent(ev);
303 }
John Spurlock257f2832013-09-21 18:41:53 -0400304 final int action = ev.getAction();
John Spurlockd157ca02013-11-04 10:28:05 -0500305 if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
John Spurlock257f2832013-09-21 18:41:53 -0400306 mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
307 }
Chris Wren5de6e942012-05-16 14:22:21 -0400308 return handled;
309 }
Daniel Sandler198a0302012-08-17 16:04:31 -0400310
311 @Override
312 public void onDraw(Canvas canvas) {
313 super.onDraw(canvas);
Jorim Jaggi0e664392014-09-27 01:30:22 +0200314 if (mService.isScrimSrcModeEnabled()) {
315 // We need to ensure that our window is always drawn fully even when we have paddings,
316 // since we simulate it to be opaque.
317 int paddedBottom = getHeight() - getPaddingBottom();
318 int paddedRight = getWidth() - getPaddingRight();
319 if (getPaddingTop() != 0) {
320 canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint);
321 }
322 if (getPaddingBottom() != 0) {
323 canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint);
324 }
325 if (getPaddingLeft() != 0) {
326 canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom,
327 mTransparentSrcPaint);
328 }
329 if (getPaddingRight() != 0) {
330 canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom,
331 mTransparentSrcPaint);
332 }
Selim Cineka0fad3b2014-09-19 17:20:05 +0200333 }
Daniel Sandler198a0302012-08-17 16:04:31 -0400334 if (DEBUG) {
335 Paint pt = new Paint();
336 pt.setColor(0x80FFFF00);
337 pt.setStrokeWidth(12.0f);
338 pt.setStyle(Paint.Style.STROKE);
339 canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt);
340 }
341 }
Daniel Sandlerac47ff72012-10-23 10:41:44 -0400342
343 public void cancelExpandHelper() {
Selim Cinek1408eb52014-06-02 14:45:38 +0200344 if (mStackScrollLayout != null) {
345 mStackScrollLayout.cancelExpandHelper();
Daniel Sandler1a3bdd52012-10-23 19:21:20 -0400346 }
Daniel Sandlerac47ff72012-10-23 10:41:44 -0400347 }
Adrian Roos2f2bd9a2015-06-04 18:11:14 -0700348
349 public class LayoutParams extends FrameLayout.LayoutParams {
350
351 public boolean ignoreRightInset;
352
353 public LayoutParams(int width, int height) {
354 super(width, height);
355 }
356
357 public LayoutParams(Context c, AttributeSet attrs) {
358 super(c, attrs);
359
360 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout);
361 ignoreRightInset = a.getBoolean(
362 R.styleable.StatusBarWindowView_Layout_ignoreRightInset, false);
363 a.recycle();
364 }
365 }
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700366
367 @Override
368 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback,
369 int type) {
370 if (type == ActionMode.TYPE_FLOATING) {
371 return startActionMode(originalView, callback, type);
372 }
373 return super.startActionModeForChild(originalView, callback, type);
374 }
375
376 private ActionMode createFloatingActionMode(
377 View originatingView, ActionMode.Callback2 callback) {
378 if (mFloatingActionMode != null) {
379 mFloatingActionMode.finish();
380 }
381 cleanupFloatingActionModeViews();
382 final FloatingActionMode mode =
383 new FloatingActionMode(mContext, callback, originatingView);
384 mFloatingActionModeOriginatingView = originatingView;
385 mFloatingToolbarPreDrawListener =
386 new ViewTreeObserver.OnPreDrawListener() {
387 @Override
388 public boolean onPreDraw() {
389 mode.updateViewLocationInWindow();
390 return true;
391 }
392 };
393 return mode;
394 }
395
396 private void setHandledFloatingActionMode(ActionMode mode) {
397 mFloatingActionMode = mode;
398 mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
399 ((FloatingActionMode) mFloatingActionMode).setFloatingToolbar(mFloatingToolbar);
400 mFloatingActionMode.invalidate(); // Will show the floating toolbar if necessary.
401 mFloatingActionModeOriginatingView.getViewTreeObserver()
402 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
403 }
404
405 private void cleanupFloatingActionModeViews() {
406 if (mFloatingToolbar != null) {
407 mFloatingToolbar.dismiss();
408 mFloatingToolbar = null;
409 }
410 if (mFloatingActionModeOriginatingView != null) {
411 if (mFloatingToolbarPreDrawListener != null) {
412 mFloatingActionModeOriginatingView.getViewTreeObserver()
413 .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
414 mFloatingToolbarPreDrawListener = null;
415 }
416 mFloatingActionModeOriginatingView = null;
417 }
418 }
419
420 private ActionMode startActionMode(
421 View originatingView, ActionMode.Callback callback, int type) {
422 ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
423 ActionMode mode = createFloatingActionMode(originatingView, wrappedCallback);
424 if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
425 setHandledFloatingActionMode(mode);
426 } else {
427 mode = null;
428 }
429 return mode;
430 }
431
432 private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
433 private final ActionMode.Callback mWrapped;
434
435 public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
436 mWrapped = wrapped;
437 }
438
439 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
440 return mWrapped.onCreateActionMode(mode, menu);
441 }
442
443 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
444 requestFitSystemWindows();
445 return mWrapped.onPrepareActionMode(mode, menu);
446 }
447
448 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
449 return mWrapped.onActionItemClicked(mode, item);
450 }
451
452 public void onDestroyActionMode(ActionMode mode) {
453 mWrapped.onDestroyActionMode(mode);
454 if (mode == mFloatingActionMode) {
455 cleanupFloatingActionModeViews();
456 mFloatingActionMode = null;
457 }
458 requestFitSystemWindows();
459 }
460
461 @Override
462 public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
463 if (mWrapped instanceof ActionMode.Callback2) {
464 ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
465 } else {
466 super.onGetContentRect(mode, view, outRect);
467 }
468 }
469 }
470
471 /**
472 * Minimal window to satisfy FloatingToolbar.
473 */
474 private Window mFakeWindow = new Window(mContext) {
475 @Override
476 public void takeSurface(SurfaceHolder.Callback2 callback) {
477 }
478
479 @Override
480 public void takeInputQueue(InputQueue.Callback callback) {
481 }
482
483 @Override
484 public boolean isFloating() {
485 return false;
486 }
487
488 @Override
489 public void alwaysReadCloseOnTouchAttr() {
490 }
491
492 @Override
493 public void setContentView(@LayoutRes int layoutResID) {
494 }
495
496 @Override
497 public void setContentView(View view) {
498 }
499
500 @Override
501 public void setContentView(View view, ViewGroup.LayoutParams params) {
502 }
503
504 @Override
505 public void addContentView(View view, ViewGroup.LayoutParams params) {
506 }
507
508 @Override
509 public void clearContentView() {
510 }
511
512 @Override
513 public View getCurrentFocus() {
514 return null;
515 }
516
517 @Override
518 public LayoutInflater getLayoutInflater() {
519 return null;
520 }
521
522 @Override
523 public void setTitle(CharSequence title) {
524 }
525
526 @Override
527 public void setTitleColor(@ColorInt int textColor) {
528 }
529
530 @Override
531 public void openPanel(int featureId, KeyEvent event) {
532 }
533
534 @Override
535 public void closePanel(int featureId) {
536 }
537
538 @Override
539 public void togglePanel(int featureId, KeyEvent event) {
540 }
541
542 @Override
543 public void invalidatePanelMenu(int featureId) {
544 }
545
546 @Override
547 public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
548 return false;
549 }
550
551 @Override
552 public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
553 return false;
554 }
555
556 @Override
557 public void closeAllPanels() {
558 }
559
560 @Override
561 public boolean performContextMenuIdentifierAction(int id, int flags) {
562 return false;
563 }
564
565 @Override
566 public void onConfigurationChanged(Configuration newConfig) {
567 }
568
569 @Override
570 public void setBackgroundDrawable(Drawable drawable) {
571 }
572
573 @Override
574 public void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
575 }
576
577 @Override
578 public void setFeatureDrawableUri(int featureId, Uri uri) {
579 }
580
581 @Override
582 public void setFeatureDrawable(int featureId, Drawable drawable) {
583 }
584
585 @Override
586 public void setFeatureDrawableAlpha(int featureId, int alpha) {
587 }
588
589 @Override
590 public void setFeatureInt(int featureId, int value) {
591 }
592
593 @Override
594 public void takeKeyEvents(boolean get) {
595 }
596
597 @Override
598 public boolean superDispatchKeyEvent(KeyEvent event) {
599 return false;
600 }
601
602 @Override
603 public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
604 return false;
605 }
606
607 @Override
608 public boolean superDispatchTouchEvent(MotionEvent event) {
609 return false;
610 }
611
612 @Override
613 public boolean superDispatchTrackballEvent(MotionEvent event) {
614 return false;
615 }
616
617 @Override
618 public boolean superDispatchGenericMotionEvent(MotionEvent event) {
619 return false;
620 }
621
622 @Override
623 public View getDecorView() {
624 return StatusBarWindowView.this;
625 }
626
627 @Override
628 public View peekDecorView() {
629 return null;
630 }
631
632 @Override
633 public Bundle saveHierarchyState() {
634 return null;
635 }
636
637 @Override
638 public void restoreHierarchyState(Bundle savedInstanceState) {
639 }
640
641 @Override
642 protected void onActive() {
643 }
644
645 @Override
646 public void setChildDrawable(int featureId, Drawable drawable) {
647 }
648
649 @Override
650 public void setChildInt(int featureId, int value) {
651 }
652
653 @Override
654 public boolean isShortcutKey(int keyCode, KeyEvent event) {
655 return false;
656 }
657
658 @Override
659 public void setVolumeControlStream(int streamType) {
660 }
661
662 @Override
663 public int getVolumeControlStream() {
664 return 0;
665 }
666
667 @Override
668 public int getStatusBarColor() {
669 return 0;
670 }
671
672 @Override
673 public void setStatusBarColor(@ColorInt int color) {
674 }
675
676 @Override
677 public int getNavigationBarColor() {
678 return 0;
679 }
680
681 @Override
682 public void setNavigationBarColor(@ColorInt int color) {
683 }
684
685 @Override
686 public void setDecorCaptionShade(int decorCaptionShade) {
687 }
688
689 @Override
690 public void setResizingCaptionDrawable(Drawable drawable) {
691 }
692
693 @Override
Andrii Kulian933076d2016-03-29 17:04:42 -0700694 public void onMultiWindowModeChanged() {
Adrian Roos0bd8a4b2016-03-14 16:21:44 -0700695 }
696
697 @Override
698 public void reportActivityRelaunched() {
699 }
700 };
701
Daniel Sandlerc4f2a562012-05-04 11:55:46 -0400702}
703