1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.browser_controls; 6 7 import android.os.Handler; 8 import android.os.SystemClock; 9 10 import androidx.annotation.VisibleForTesting; 11 12 import org.chromium.base.CommandLine; 13 import org.chromium.base.supplier.ObservableSupplier; 14 import org.chromium.base.supplier.Supplier; 15 import org.chromium.chrome.browser.flags.ChromeSwitches; 16 import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate; 17 import org.chromium.content_public.common.BrowserControlsState; 18 import org.chromium.ui.util.TokenHolder; 19 20 /** 21 * Determines the desired visibility of the browser controls based on the current state of the 22 * running activity. 23 */ 24 public class BrowserStateBrowserControlsVisibilityDelegate 25 extends BrowserControlsVisibilityDelegate { 26 /** Minimum duration (in milliseconds) that the controls are shown when requested. */ 27 @VisibleForTesting 28 static final long MINIMUM_SHOW_DURATION_MS = 3000; 29 30 private static boolean sDisableOverridesForTesting; 31 32 private final TokenHolder mTokenHolder; 33 34 private final Handler mHandler = new Handler(); 35 36 /** Predicate that tells if we're in persistent fullscreen mode. */ 37 private final Supplier<Boolean> mPersistentFullscreenMode; 38 39 private long mCurrentShowingStartTime; 40 41 /** 42 * Constructs a BrowserControlsVisibilityDelegate designed to deal with overrides driven by 43 * the browser UI (as opposed to the state of the tab). 44 * 45 * @param persistentFullscreenMode Predicate that tells if we're in persistent fullscreen mode. 46 */ BrowserStateBrowserControlsVisibilityDelegate( ObservableSupplier<Boolean> persistentFullscreenMode)47 public BrowserStateBrowserControlsVisibilityDelegate( 48 ObservableSupplier<Boolean> persistentFullscreenMode) { 49 super(BrowserControlsState.BOTH); 50 mTokenHolder = new TokenHolder(this::updateVisibilityConstraints); 51 mPersistentFullscreenMode = persistentFullscreenMode; 52 persistentFullscreenMode.addObserver((persistentMode) -> updateVisibilityConstraints()); 53 updateVisibilityConstraints(); 54 } 55 ensureControlsVisibleForMinDuration()56 private void ensureControlsVisibleForMinDuration() { 57 // Do not lock the controls as visible. Such as in testing. 58 if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_MINIMUM_SHOW_DURATION)) { 59 return; 60 } 61 if (mHandler.hasMessages(0)) return; // Messages sent via post/postDelayed have what=0 62 63 long currentShowingTime = SystemClock.uptimeMillis() - mCurrentShowingStartTime; 64 if (currentShowingTime >= MINIMUM_SHOW_DURATION_MS) return; 65 66 final int temporaryToken = mTokenHolder.acquireToken(); 67 mHandler.postDelayed(() 68 -> mTokenHolder.releaseToken(temporaryToken), 69 MINIMUM_SHOW_DURATION_MS - currentShowingTime); 70 } 71 72 /** 73 * Trigger a temporary showing of the browser controls. 74 */ showControlsTransient()75 public void showControlsTransient() { 76 if (!mTokenHolder.hasTokens()) mCurrentShowingStartTime = SystemClock.uptimeMillis(); 77 ensureControlsVisibleForMinDuration(); 78 } 79 80 /** 81 * Trigger a permanent showing of the browser controls until requested otherwise. 82 * 83 * @return The token that determines whether the requester still needs persistent controls to 84 * be present on the screen. 85 * @see #releasePersistentShowingToken(int) 86 */ showControlsPersistent()87 public int showControlsPersistent() { 88 if (!mTokenHolder.hasTokens()) mCurrentShowingStartTime = SystemClock.uptimeMillis(); 89 return mTokenHolder.acquireToken(); 90 } 91 92 /** 93 * Same behavior as {@link #showControlsPersistent()} but also handles removing a previously 94 * requested token if necessary. 95 * 96 * @param oldToken The old fullscreen token to be cleared. 97 * @return The fullscreen token as defined in {@link #showControlsPersistent()}. 98 */ showControlsPersistentAndClearOldToken(int oldToken)99 public int showControlsPersistentAndClearOldToken(int oldToken) { 100 int newToken = showControlsPersistent(); 101 mTokenHolder.releaseToken(oldToken); 102 return newToken; 103 } 104 105 /** 106 * Notify the manager that the browser controls are no longer required for the given token. 107 * 108 * @param token The fullscreen token returned from {@link #showControlsPersistent()}. 109 */ releasePersistentShowingToken(int token)110 public void releasePersistentShowingToken(int token) { 111 if (mTokenHolder.containsOnly(token)) { 112 ensureControlsVisibleForMinDuration(); 113 } 114 mTokenHolder.releaseToken(token); 115 } 116 117 @BrowserControlsState calculateVisibilityConstraints()118 private int calculateVisibilityConstraints() { 119 if (mPersistentFullscreenMode.get()) { 120 return BrowserControlsState.HIDDEN; 121 } else if (mTokenHolder.hasTokens() && !sDisableOverridesForTesting) { 122 return BrowserControlsState.SHOWN; 123 } 124 return BrowserControlsState.BOTH; 125 } 126 updateVisibilityConstraints()127 private void updateVisibilityConstraints() { 128 set(calculateVisibilityConstraints()); 129 } 130 131 /** 132 * Disable any browser visibility overrides for testing. 133 */ disableForTesting()134 public static void disableForTesting() { 135 sDisableOverridesForTesting = true; 136 } 137 138 /** 139 * Performs clean-up. 140 */ destroy()141 public void destroy() { 142 mHandler.removeCallbacksAndMessages(null); 143 } 144 } 145