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