1 /*
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 
17 package com.android.systemui.statusbar.phone;
18 
19 import android.annotation.ColorInt;
20 import android.annotation.DrawableRes;
21 import android.annotation.LayoutRes;
22 import android.app.StatusBarManager;
23 import android.content.Context;
24 import android.content.res.Configuration;
25 import android.content.res.TypedArray;
26 import android.graphics.Canvas;
27 import android.graphics.Paint;
28 import android.graphics.PorterDuff;
29 import android.graphics.PorterDuffXfermode;
30 import android.graphics.Rect;
31 import android.graphics.drawable.Drawable;
32 import android.media.AudioManager;
33 import android.media.session.MediaSessionLegacyHelper;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.IBinder;
37 import android.os.SystemClock;
38 import android.util.AttributeSet;
39 import android.view.ActionMode;
40 import android.view.InputDevice;
41 import android.view.InputQueue;
42 import android.view.KeyEvent;
43 import android.view.LayoutInflater;
44 import android.view.Menu;
45 import android.view.MenuItem;
46 import android.view.MotionEvent;
47 import android.view.SurfaceHolder;
48 import android.view.View;
49 import android.view.ViewGroup;
50 import android.view.ViewTreeObserver;
51 import android.view.Window;
52 import android.view.WindowManager;
53 import android.view.WindowManagerGlobal;
54 import android.widget.FrameLayout;
55 
56 import com.android.internal.annotations.VisibleForTesting;
57 import com.android.internal.view.FloatingActionMode;
58 import com.android.internal.widget.FloatingToolbar;
59 import com.android.systemui.R;
60 import com.android.systemui.classifier.FalsingManager;
61 import com.android.systemui.statusbar.DragDownHelper;
62 import com.android.systemui.statusbar.StatusBarState;
63 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
64 
65 
66 public class StatusBarWindowView extends FrameLayout {
67     public static final String TAG = "StatusBarWindowView";
68     public static final boolean DEBUG = StatusBar.DEBUG;
69 
70     private DragDownHelper mDragDownHelper;
71     private DoubleTapHelper mDoubleTapHelper;
72     private NotificationStackScrollLayout mStackScrollLayout;
73     private NotificationPanelView mNotificationPanel;
74     private View mBrightnessMirror;
75 
76     private int mRightInset = 0;
77     private int mLeftInset = 0;
78 
79     private StatusBar mService;
80     private final Paint mTransparentSrcPaint = new Paint();
81     private FalsingManager mFalsingManager;
82 
83     // Implements the floating action mode for TextView's Cut/Copy/Past menu. Normally provided by
84     // DecorView, but since this is a special window we have to roll our own.
85     private View mFloatingActionModeOriginatingView;
86     private ActionMode mFloatingActionMode;
87     private FloatingToolbar mFloatingToolbar;
88     private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
89     private boolean mTouchCancelled;
90     private boolean mTouchActive;
91 
StatusBarWindowView(Context context, AttributeSet attrs)92     public StatusBarWindowView(Context context, AttributeSet attrs) {
93         super(context, attrs);
94         setMotionEventSplittingEnabled(false);
95         mTransparentSrcPaint.setColor(0);
96         mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
97         mFalsingManager = FalsingManager.getInstance(context);
98         mDoubleTapHelper = new DoubleTapHelper(this, active -> {}, () -> {
99             mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this);
100             return true;
101         }, null, null);
102     }
103 
104     @Override
fitSystemWindows(Rect insets)105     protected boolean fitSystemWindows(Rect insets) {
106         if (getFitsSystemWindows()) {
107             boolean paddingChanged = insets.top != getPaddingTop()
108                     || insets.bottom != getPaddingBottom();
109 
110             // Super-special right inset handling, because scrims and backdrop need to ignore it.
111             if (insets.right != mRightInset || insets.left != mLeftInset) {
112                 mRightInset = insets.right;
113                 mLeftInset = insets.left;
114                 applyMargins();
115             }
116             // Drop top inset, and pass through bottom inset.
117             if (paddingChanged) {
118                 setPadding(0, 0, 0, 0);
119             }
120             insets.left = 0;
121             insets.top = 0;
122             insets.right = 0;
123         } else {
124             if (mRightInset != 0 || mLeftInset != 0) {
125                 mRightInset = 0;
126                 mLeftInset = 0;
127                 applyMargins();
128             }
129             boolean changed = getPaddingLeft() != 0
130                     || getPaddingRight() != 0
131                     || getPaddingTop() != 0
132                     || getPaddingBottom() != 0;
133             if (changed) {
134                 setPadding(0, 0, 0, 0);
135             }
136             insets.top = 0;
137         }
138         return false;
139     }
140 
applyMargins()141     private void applyMargins() {
142         final int N = getChildCount();
143         for (int i = 0; i < N; i++) {
144             View child = getChildAt(i);
145             if (child.getLayoutParams() instanceof LayoutParams) {
146                 LayoutParams lp = (LayoutParams) child.getLayoutParams();
147                 if (!lp.ignoreRightInset
148                         && (lp.rightMargin != mRightInset || lp.leftMargin != mLeftInset)) {
149                     lp.rightMargin = mRightInset;
150                     lp.leftMargin = mLeftInset;
151                     child.requestLayout();
152                 }
153             }
154         }
155     }
156 
157     @Override
generateLayoutParams(AttributeSet attrs)158     public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
159         return new LayoutParams(getContext(), attrs);
160     }
161 
162     @Override
generateDefaultLayoutParams()163     protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
164         return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
165     }
166 
167     @Override
onFinishInflate()168     protected void onFinishInflate() {
169         super.onFinishInflate();
170         mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
171                 R.id.notification_stack_scroller);
172         mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
173         mBrightnessMirror = findViewById(R.id.brightness_mirror);
174     }
175 
176     @Override
onViewAdded(View child)177     public void onViewAdded(View child) {
178         super.onViewAdded(child);
179         if (child.getId() == R.id.brightness_mirror) {
180             mBrightnessMirror = child;
181         }
182     }
183 
setService(StatusBar service)184     public void setService(StatusBar service) {
185         mService = service;
186         setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService));
187     }
188 
189     @VisibleForTesting
setDragDownHelper(DragDownHelper dragDownHelper)190     void setDragDownHelper(DragDownHelper dragDownHelper) {
191         mDragDownHelper = dragDownHelper;
192     }
193 
194     @Override
onAttachedToWindow()195     protected void onAttachedToWindow () {
196         super.onAttachedToWindow();
197 
198         // We need to ensure that our window doesn't suffer from overdraw which would normally
199         // occur if our window is translucent. Since we are drawing the whole window anyway with
200         // the scrim, we don't need the window to be cleared in the beginning.
201         if (mService.isScrimSrcModeEnabled()) {
202             IBinder windowToken = getWindowToken();
203             WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
204             lp.token = windowToken;
205             setLayoutParams(lp);
206             WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true);
207             setWillNotDraw(false);
208         } else {
209             setWillNotDraw(!DEBUG);
210         }
211     }
212 
213     @Override
dispatchKeyEvent(KeyEvent event)214     public boolean dispatchKeyEvent(KeyEvent event) {
215         if (mService.interceptMediaKey(event)) {
216             return true;
217         }
218         if (super.dispatchKeyEvent(event)) {
219             return true;
220         }
221         boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
222         switch (event.getKeyCode()) {
223             case KeyEvent.KEYCODE_BACK:
224                 if (!down) {
225                     mService.onBackPressed();
226                 }
227                 return true;
228             case KeyEvent.KEYCODE_MENU:
229                 if (!down) {
230                     return mService.onMenuPressed();
231                 }
232             case KeyEvent.KEYCODE_SPACE:
233                 if (!down) {
234                     return mService.onSpacePressed();
235                 }
236                 break;
237             case KeyEvent.KEYCODE_VOLUME_DOWN:
238             case KeyEvent.KEYCODE_VOLUME_UP:
239                 if (mService.isDozing()) {
240                     MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
241                             event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
242                     return true;
243                 }
244                 break;
245         }
246         return false;
247     }
248 
249     @Override
dispatchTouchEvent(MotionEvent ev)250     public boolean dispatchTouchEvent(MotionEvent ev) {
251         boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
252         if (isDown && mNotificationPanel.isFullyCollapsed()) {
253             mNotificationPanel.startExpandLatencyTracking();
254         }
255         if (isDown) {
256             mTouchActive = true;
257             mTouchCancelled = false;
258         } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
259                 || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
260             mTouchActive = false;
261         }
262         if (mTouchCancelled) {
263             return false;
264         }
265         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
266         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
267             // Disallow new pointers while the brightness mirror is visible. This is so that you
268             // can't touch anything other than the brightness slider while the mirror is showing
269             // and the rest of the panel is transparent.
270             if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
271                 return false;
272             }
273         }
274         if (isDown) {
275             mStackScrollLayout.closeControlsIfOutsideTouch(ev);
276         }
277         if (mService.isDozing()) {
278             mService.mDozeScrimController.extendPulse();
279         }
280 
281         return super.dispatchTouchEvent(ev);
282     }
283 
284     @Override
onInterceptTouchEvent(MotionEvent ev)285     public boolean onInterceptTouchEvent(MotionEvent ev) {
286         if (mService.isDozing() && !mStackScrollLayout.hasPulsingNotifications()) {
287             // Capture all touch events in always-on.
288             return true;
289         }
290         boolean intercept = false;
291         if (mNotificationPanel.isFullyExpanded()
292                 && mStackScrollLayout.getVisibility() == View.VISIBLE
293                 && mService.getBarState() == StatusBarState.KEYGUARD
294                 && !mService.isBouncerShowing()
295                 && !mService.isDozing()) {
296             intercept = mDragDownHelper.onInterceptTouchEvent(ev);
297         }
298         if (!intercept) {
299             super.onInterceptTouchEvent(ev);
300         }
301         if (intercept) {
302             MotionEvent cancellation = MotionEvent.obtain(ev);
303             cancellation.setAction(MotionEvent.ACTION_CANCEL);
304             mStackScrollLayout.onInterceptTouchEvent(cancellation);
305             mNotificationPanel.onInterceptTouchEvent(cancellation);
306             cancellation.recycle();
307         }
308         return intercept;
309     }
310 
311     @Override
onTouchEvent(MotionEvent ev)312     public boolean onTouchEvent(MotionEvent ev) {
313         boolean handled = false;
314         if (mService.isDozing()) {
315             mDoubleTapHelper.onTouchEvent(ev);
316             handled = true;
317         }
318         if ((mService.getBarState() == StatusBarState.KEYGUARD && !handled)
319                 || mDragDownHelper.isDraggingDown()) {
320             // we still want to finish our drag down gesture when locking the screen
321             handled = mDragDownHelper.onTouchEvent(ev);
322         }
323         if (!handled) {
324             handled = super.onTouchEvent(ev);
325         }
326         final int action = ev.getAction();
327         if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
328             mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
329         }
330         return handled;
331     }
332 
333     @Override
onDraw(Canvas canvas)334     public void onDraw(Canvas canvas) {
335         super.onDraw(canvas);
336         if (mService.isScrimSrcModeEnabled()) {
337             // We need to ensure that our window is always drawn fully even when we have paddings,
338             // since we simulate it to be opaque.
339             int paddedBottom = getHeight() - getPaddingBottom();
340             int paddedRight = getWidth() - getPaddingRight();
341             if (getPaddingTop() != 0) {
342                 canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint);
343             }
344             if (getPaddingBottom() != 0) {
345                 canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint);
346             }
347             if (getPaddingLeft() != 0) {
348                 canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom,
349                         mTransparentSrcPaint);
350             }
351             if (getPaddingRight() != 0) {
352                 canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom,
353                         mTransparentSrcPaint);
354             }
355         }
356         if (DEBUG) {
357             Paint pt = new Paint();
358             pt.setColor(0x80FFFF00);
359             pt.setStrokeWidth(12.0f);
360             pt.setStyle(Paint.Style.STROKE);
361             canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), pt);
362         }
363     }
364 
cancelExpandHelper()365     public void cancelExpandHelper() {
366         if (mStackScrollLayout != null) {
367             mStackScrollLayout.cancelExpandHelper();
368         }
369     }
370 
cancelCurrentTouch()371     public void cancelCurrentTouch() {
372         if (mTouchActive) {
373             final long now = SystemClock.uptimeMillis();
374             MotionEvent event = MotionEvent.obtain(now, now,
375                     MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
376             event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
377             dispatchTouchEvent(event);
378             event.recycle();
379             mTouchCancelled = true;
380         }
381     }
382 
383     public class LayoutParams extends FrameLayout.LayoutParams {
384 
385         public boolean ignoreRightInset;
386 
LayoutParams(int width, int height)387         public LayoutParams(int width, int height) {
388             super(width, height);
389         }
390 
LayoutParams(Context c, AttributeSet attrs)391         public LayoutParams(Context c, AttributeSet attrs) {
392             super(c, attrs);
393 
394             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout);
395             ignoreRightInset = a.getBoolean(
396                     R.styleable.StatusBarWindowView_Layout_ignoreRightInset, false);
397             a.recycle();
398         }
399     }
400 
401     @Override
startActionModeForChild(View originalView, ActionMode.Callback callback, int type)402     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback,
403             int type) {
404         if (type == ActionMode.TYPE_FLOATING) {
405             return startActionMode(originalView, callback, type);
406         }
407         return super.startActionModeForChild(originalView, callback, type);
408     }
409 
createFloatingActionMode( View originatingView, ActionMode.Callback2 callback)410     private ActionMode createFloatingActionMode(
411             View originatingView, ActionMode.Callback2 callback) {
412         if (mFloatingActionMode != null) {
413             mFloatingActionMode.finish();
414         }
415         cleanupFloatingActionModeViews();
416         mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
417         final FloatingActionMode mode =
418                 new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
419         mFloatingActionModeOriginatingView = originatingView;
420         mFloatingToolbarPreDrawListener =
421                 new ViewTreeObserver.OnPreDrawListener() {
422                     @Override
423                     public boolean onPreDraw() {
424                         mode.updateViewLocationInWindow();
425                         return true;
426                     }
427                 };
428         return mode;
429     }
430 
setHandledFloatingActionMode(ActionMode mode)431     private void setHandledFloatingActionMode(ActionMode mode) {
432         mFloatingActionMode = mode;
433         mFloatingActionMode.invalidate();  // Will show the floating toolbar if necessary.
434         mFloatingActionModeOriginatingView.getViewTreeObserver()
435                 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
436     }
437 
cleanupFloatingActionModeViews()438     private void cleanupFloatingActionModeViews() {
439         if (mFloatingToolbar != null) {
440             mFloatingToolbar.dismiss();
441             mFloatingToolbar = null;
442         }
443         if (mFloatingActionModeOriginatingView != null) {
444             if (mFloatingToolbarPreDrawListener != null) {
445                 mFloatingActionModeOriginatingView.getViewTreeObserver()
446                         .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
447                 mFloatingToolbarPreDrawListener = null;
448             }
449             mFloatingActionModeOriginatingView = null;
450         }
451     }
452 
startActionMode( View originatingView, ActionMode.Callback callback, int type)453     private ActionMode startActionMode(
454             View originatingView, ActionMode.Callback callback, int type) {
455         ActionMode.Callback2 wrappedCallback = new ActionModeCallback2Wrapper(callback);
456         ActionMode mode = createFloatingActionMode(originatingView, wrappedCallback);
457         if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
458             setHandledFloatingActionMode(mode);
459         } else {
460             mode = null;
461         }
462         return mode;
463     }
464 
465     private class ActionModeCallback2Wrapper extends ActionMode.Callback2 {
466         private final ActionMode.Callback mWrapped;
467 
ActionModeCallback2Wrapper(ActionMode.Callback wrapped)468         public ActionModeCallback2Wrapper(ActionMode.Callback wrapped) {
469             mWrapped = wrapped;
470         }
471 
onCreateActionMode(ActionMode mode, Menu menu)472         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
473             return mWrapped.onCreateActionMode(mode, menu);
474         }
475 
onPrepareActionMode(ActionMode mode, Menu menu)476         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
477             requestFitSystemWindows();
478             return mWrapped.onPrepareActionMode(mode, menu);
479         }
480 
onActionItemClicked(ActionMode mode, MenuItem item)481         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
482             return mWrapped.onActionItemClicked(mode, item);
483         }
484 
onDestroyActionMode(ActionMode mode)485         public void onDestroyActionMode(ActionMode mode) {
486             mWrapped.onDestroyActionMode(mode);
487             if (mode == mFloatingActionMode) {
488                 cleanupFloatingActionModeViews();
489                 mFloatingActionMode = null;
490             }
491             requestFitSystemWindows();
492         }
493 
494         @Override
onGetContentRect(ActionMode mode, View view, Rect outRect)495         public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
496             if (mWrapped instanceof ActionMode.Callback2) {
497                 ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
498             } else {
499                 super.onGetContentRect(mode, view, outRect);
500             }
501         }
502     }
503 
504     /**
505      * Minimal window to satisfy FloatingToolbar.
506      */
507     private Window mFakeWindow = new Window(mContext) {
508         @Override
509         public void takeSurface(SurfaceHolder.Callback2 callback) {
510         }
511 
512         @Override
513         public void takeInputQueue(InputQueue.Callback callback) {
514         }
515 
516         @Override
517         public boolean isFloating() {
518             return false;
519         }
520 
521         @Override
522         public void alwaysReadCloseOnTouchAttr() {
523         }
524 
525         @Override
526         public void setContentView(@LayoutRes int layoutResID) {
527         }
528 
529         @Override
530         public void setContentView(View view) {
531         }
532 
533         @Override
534         public void setContentView(View view, ViewGroup.LayoutParams params) {
535         }
536 
537         @Override
538         public void addContentView(View view, ViewGroup.LayoutParams params) {
539         }
540 
541         @Override
542         public void clearContentView() {
543         }
544 
545         @Override
546         public View getCurrentFocus() {
547             return null;
548         }
549 
550         @Override
551         public LayoutInflater getLayoutInflater() {
552             return null;
553         }
554 
555         @Override
556         public void setTitle(CharSequence title) {
557         }
558 
559         @Override
560         public void setTitleColor(@ColorInt int textColor) {
561         }
562 
563         @Override
564         public void openPanel(int featureId, KeyEvent event) {
565         }
566 
567         @Override
568         public void closePanel(int featureId) {
569         }
570 
571         @Override
572         public void togglePanel(int featureId, KeyEvent event) {
573         }
574 
575         @Override
576         public void invalidatePanelMenu(int featureId) {
577         }
578 
579         @Override
580         public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
581             return false;
582         }
583 
584         @Override
585         public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
586             return false;
587         }
588 
589         @Override
590         public void closeAllPanels() {
591         }
592 
593         @Override
594         public boolean performContextMenuIdentifierAction(int id, int flags) {
595             return false;
596         }
597 
598         @Override
599         public void onConfigurationChanged(Configuration newConfig) {
600         }
601 
602         @Override
603         public void setBackgroundDrawable(Drawable drawable) {
604         }
605 
606         @Override
607         public void setFeatureDrawableResource(int featureId, @DrawableRes int resId) {
608         }
609 
610         @Override
611         public void setFeatureDrawableUri(int featureId, Uri uri) {
612         }
613 
614         @Override
615         public void setFeatureDrawable(int featureId, Drawable drawable) {
616         }
617 
618         @Override
619         public void setFeatureDrawableAlpha(int featureId, int alpha) {
620         }
621 
622         @Override
623         public void setFeatureInt(int featureId, int value) {
624         }
625 
626         @Override
627         public void takeKeyEvents(boolean get) {
628         }
629 
630         @Override
631         public boolean superDispatchKeyEvent(KeyEvent event) {
632             return false;
633         }
634 
635         @Override
636         public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
637             return false;
638         }
639 
640         @Override
641         public boolean superDispatchTouchEvent(MotionEvent event) {
642             return false;
643         }
644 
645         @Override
646         public boolean superDispatchTrackballEvent(MotionEvent event) {
647             return false;
648         }
649 
650         @Override
651         public boolean superDispatchGenericMotionEvent(MotionEvent event) {
652             return false;
653         }
654 
655         @Override
656         public View getDecorView() {
657             return StatusBarWindowView.this;
658         }
659 
660         @Override
661         public View peekDecorView() {
662             return null;
663         }
664 
665         @Override
666         public Bundle saveHierarchyState() {
667             return null;
668         }
669 
670         @Override
671         public void restoreHierarchyState(Bundle savedInstanceState) {
672         }
673 
674         @Override
675         protected void onActive() {
676         }
677 
678         @Override
679         public void setChildDrawable(int featureId, Drawable drawable) {
680         }
681 
682         @Override
683         public void setChildInt(int featureId, int value) {
684         }
685 
686         @Override
687         public boolean isShortcutKey(int keyCode, KeyEvent event) {
688             return false;
689         }
690 
691         @Override
692         public void setVolumeControlStream(int streamType) {
693         }
694 
695         @Override
696         public int getVolumeControlStream() {
697             return 0;
698         }
699 
700         @Override
701         public int getStatusBarColor() {
702             return 0;
703         }
704 
705         @Override
706         public void setStatusBarColor(@ColorInt int color) {
707         }
708 
709         @Override
710         public int getNavigationBarColor() {
711             return 0;
712         }
713 
714         @Override
715         public void setNavigationBarColor(@ColorInt int color) {
716         }
717 
718         @Override
719         public void setDecorCaptionShade(int decorCaptionShade) {
720         }
721 
722         @Override
723         public void setResizingCaptionDrawable(Drawable drawable) {
724         }
725 
726         @Override
727         public void onMultiWindowModeChanged() {
728         }
729 
730         @Override
731         public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
732         }
733 
734         @Override
735         public void reportActivityRelaunched() {
736         }
737     };
738 
739 }
740 
741