| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.fullscreen; | 5 package org.chromium.chrome.browser.fullscreen; |
| 6 | 6 |
| 7 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; | 7 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; |
| 8 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; | 8 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; |
| 9 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; | 9 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; |
| 10 | 10 |
| 11 import android.content.res.Resources; | 11 import android.content.res.Resources; |
| 12 import android.os.Build; | 12 import android.os.Build; |
| 13 import android.os.Bundle; | 13 import android.os.Bundle; |
| 14 import android.os.Handler; | 14 import android.os.Handler; |
| 15 import android.os.Message; | 15 import android.os.Message; |
| 16 import android.view.Gravity; | 16 import android.view.Gravity; |
| 17 import android.view.View; | 17 import android.view.View; |
| 18 import android.view.View.OnLayoutChangeListener; | 18 import android.view.View.OnLayoutChangeListener; |
| 19 import android.view.Window; | 19 import android.view.Window; |
| 20 import android.view.WindowManager; | 20 import android.view.WindowManager; |
| 21 | 21 |
| 22 import org.chromium.chrome.R; | 22 import org.chromium.chrome.R; |
| 23 import org.chromium.chrome.browser.widget.TextBubble; | 23 import org.chromium.chrome.browser.widget.TextBubble; |
| 24 import org.chromium.content.browser.ContentViewCore; | 24 import org.chromium.content.browser.ContentViewCore; |
| 25 | 25 |
| 26 import java.lang.ref.WeakReference; |
| 27 |
| 26 /** | 28 /** |
| 27 * Handles updating the UI based on requests to the HTML Fullscreen API. | 29 * Handles updating the UI based on requests to the HTML Fullscreen API. |
| 28 */ | 30 */ |
| 29 public class FullscreenHtmlApiHandler { | 31 public class FullscreenHtmlApiHandler { |
| 30 private static final int MSG_ID_HIDE_NOTIFICATION_BUBBLE = 1; | 32 private static final int MSG_ID_HIDE_NOTIFICATION_BUBBLE = 1; |
| 31 private static final int MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS = 2; | 33 private static final int MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS = 2; |
| 32 private static final int MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG = 3; | 34 private static final int MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG = 3; |
| 33 | 35 |
| 34 private static final int MAX_NOTIFICATION_DIMENSION_DP = 600; | 36 private static final int MAX_NOTIFICATION_DIMENSION_DP = 600; |
| 35 | 37 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 */ | 99 */ |
| 98 void onFullscreenExited(ContentViewCore contentViewCore); | 100 void onFullscreenExited(ContentViewCore contentViewCore); |
| 99 | 101 |
| 100 /** | 102 /** |
| 101 * @return Whether the notification bubble should be shown. For fullscre
en video in | 103 * @return Whether the notification bubble should be shown. For fullscre
en video in |
| 102 * overlay mode, the notification bubble should be disabled. | 104 * overlay mode, the notification bubble should be disabled. |
| 103 */ | 105 */ |
| 104 boolean shouldShowNotificationBubble(); | 106 boolean shouldShowNotificationBubble(); |
| 105 } | 107 } |
| 106 | 108 |
| 109 // This static inner class holds a WeakReference to the outer object, to avo
id triggering the |
| 110 // lint HandlerLeak warning. |
| 111 private static class FullscreenHandler extends Handler { |
| 112 private final WeakReference<FullscreenHtmlApiHandler> mFullscreenHtmlApi
Handler; |
| 113 |
| 114 public FullscreenHandler(FullscreenHtmlApiHandler fullscreenHtmlApiHandl
er) { |
| 115 mFullscreenHtmlApiHandler = new WeakReference<FullscreenHtmlApiHandl
er>( |
| 116 fullscreenHtmlApiHandler); |
| 117 } |
| 118 |
| 119 @Override |
| 120 public void handleMessage(Message msg) { |
| 121 if (msg == null) return; |
| 122 FullscreenHtmlApiHandler fullscreenHtmlApiHandler = mFullscreenHtmlA
piHandler.get(); |
| 123 switch (msg.what) { |
| 124 case MSG_ID_HIDE_NOTIFICATION_BUBBLE: |
| 125 fullscreenHtmlApiHandler.hideNotificationBubble(); |
| 126 break; |
| 127 case MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS: { |
| 128 assert fullscreenHtmlApiHandler.getPersistentFullscreenMode(
) : |
| 129 "Calling after we exited fullscreen"; |
| 130 final ContentViewCore contentViewCore = |
| 131 fullscreenHtmlApiHandler.getContentViewCoreInFullscr
een(); |
| 132 if (contentViewCore == null) return; |
| 133 final View contentView = contentViewCore.getContainerView(); |
| 134 int systemUiVisibility = contentView.getSystemUiVisibility()
; |
| 135 if ((systemUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) |
| 136 == SYSTEM_UI_FLAG_FULLSCREEN) { |
| 137 return; |
| 138 } |
| 139 systemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN; |
| 140 systemUiVisibility |= SYSTEM_UI_FLAG_LOW_PROFILE; |
| 141 contentView.setSystemUiVisibility(systemUiVisibility); |
| 142 |
| 143 // Trigger a update to clear the SYSTEM_UI_FLAG_LAYOUT_FULLS
CREEN flag |
| 144 // once the view has been laid out after this system UI upda
te. Without |
| 145 // clearing this flag, the keyboard appearing will not trigg
er a relayout |
| 146 // of the contents, which prevents updating the overdraw amo
unt to the |
| 147 // renderer. |
| 148 contentView.addOnLayoutChangeListener(new OnLayoutChangeList
ener() { |
| 149 @Override |
| 150 public void onLayoutChange(View v, int left, int top, in
t right, |
| 151 int bottom, int oldLeft, int oldTop, int oldRigh
t, |
| 152 int oldBottom) { |
| 153 sendEmptyMessageDelayed(MSG_ID_CLEAR_LAYOUT_FULLSCRE
EN_FLAG, |
| 154 CLEAR_LAYOUT_FULLSCREEN_DELAY_MS); |
| 155 contentView.removeOnLayoutChangeListener(this); |
| 156 } |
| 157 }); |
| 158 break; |
| 159 } |
| 160 case MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG: { |
| 161 // Change this assert to simply ignoring the message to work
around |
| 162 // http://crbug/365638 |
| 163 // TODO(aberent): Fix bug |
| 164 // assert mIsPersistentMode : "Calling after we exited fulls
creen"; |
| 165 if (!fullscreenHtmlApiHandler.getPersistentFullscreenMode())
return; |
| 166 final ContentViewCore contentViewCore = |
| 167 fullscreenHtmlApiHandler.getContentViewCoreInFullscr
een(); |
| 168 if (contentViewCore == null) return; |
| 169 final View view = contentViewCore.getContainerView(); |
| 170 int systemUiVisibility = view.getSystemUiVisibility(); |
| 171 if ((systemUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
== 0) { |
| 172 return; |
| 173 } |
| 174 systemUiVisibility &= ~SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; |
| 175 view.setSystemUiVisibility(systemUiVisibility); |
| 176 break; |
| 177 } |
| 178 default: |
| 179 assert false : "Unexpected message for ID: " + msg.what; |
| 180 break; |
| 181 } |
| 182 } |
| 183 } |
| 184 |
| 107 /** | 185 /** |
| 108 * Constructs the handler that will manage the UI transitions from the HTML
fullscreen API. | 186 * Constructs the handler that will manage the UI transitions from the HTML
fullscreen API. |
| 109 * | 187 * |
| 110 * @param window The window containing the view going to fullscreen. | 188 * @param window The window containing the view going to fullscreen. |
| 111 * @param delegate The delegate that allows embedders to handle fullscreen t
ransitions. | 189 * @param delegate The delegate that allows embedders to handle fullscreen t
ransitions. |
| 112 * @param persistentFullscreenSupported | 190 * @param persistentFullscreenSupported |
| 113 */ | 191 */ |
| 114 public FullscreenHtmlApiHandler(Window window, FullscreenHtmlApiDelegate del
egate, | 192 public FullscreenHtmlApiHandler(Window window, FullscreenHtmlApiDelegate del
egate, |
| 115 boolean persistentFullscreenSupported) { | 193 boolean persistentFullscreenSupported) { |
| 116 mWindow = window; | 194 mWindow = window; |
| 117 mDelegate = delegate; | 195 mDelegate = delegate; |
| 118 mPersistentFullscreenSupported = persistentFullscreenSupported; | 196 mPersistentFullscreenSupported = persistentFullscreenSupported; |
| 119 | 197 mHandler = new FullscreenHandler(this); |
| 120 mHandler = new Handler() { | |
| 121 @Override | |
| 122 public void handleMessage(Message msg) { | |
| 123 if (msg == null) return; | |
| 124 switch (msg.what) { | |
| 125 case MSG_ID_HIDE_NOTIFICATION_BUBBLE: | |
| 126 hideNotificationBubble(); | |
| 127 break; | |
| 128 case MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS: { | |
| 129 assert mIsPersistentMode : "Calling after we exited full
screen"; | |
| 130 final ContentViewCore contentViewCore = mContentViewCore
InFullscreen; | |
| 131 if (contentViewCore == null) return; | |
| 132 final View contentView = contentViewCore.getContainerVie
w(); | |
| 133 int systemUiVisibility = contentView.getSystemUiVisibili
ty(); | |
| 134 if ((systemUiVisibility & SYSTEM_UI_FLAG_FULLSCREEN) | |
| 135 == SYSTEM_UI_FLAG_FULLSCREEN) { | |
| 136 return; | |
| 137 } | |
| 138 systemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN; | |
| 139 systemUiVisibility |= SYSTEM_UI_FLAG_LOW_PROFILE; | |
| 140 contentView.setSystemUiVisibility(systemUiVisibility); | |
| 141 | |
| 142 // Trigger a update to clear the SYSTEM_UI_FLAG_LAYOUT_F
ULLSCREEN flag | |
| 143 // once the view has been laid out after this system UI
update. Without | |
| 144 // clearing this flag, the keyboard appearing will not t
rigger a relayout | |
| 145 // of the contents, which prevents updating the overdraw
amount to the | |
| 146 // renderer. | |
| 147 contentView.addOnLayoutChangeListener(new OnLayoutChange
Listener() { | |
| 148 @Override | |
| 149 public void onLayoutChange(View v, int left, int top
, int right, | |
| 150 int bottom, int oldLeft, int oldTop, int old
Right, | |
| 151 int oldBottom) { | |
| 152 sendEmptyMessageDelayed(MSG_ID_CLEAR_LAYOUT_FULL
SCREEN_FLAG, | |
| 153 CLEAR_LAYOUT_FULLSCREEN_DELAY_MS); | |
| 154 contentView.removeOnLayoutChangeListener(this); | |
| 155 } | |
| 156 }); | |
| 157 break; | |
| 158 } | |
| 159 case MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG: { | |
| 160 // Change this assert to simply ignoring the message to
work around | |
| 161 // http://crbug/365638 | |
| 162 // TODO(aberent): Fix bug | |
| 163 // assert mIsPersistentMode : "Calling after we exited f
ullscreen"; | |
| 164 if (!mIsPersistentMode) return; | |
| 165 if (mContentViewCoreInFullscreen == null) return; | |
| 166 final View view = mContentViewCoreInFullscreen.getContai
nerView(); | |
| 167 int systemUiVisibility = view.getSystemUiVisibility(); | |
| 168 if ((systemUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCRE
EN) == 0) { | |
| 169 return; | |
| 170 } | |
| 171 systemUiVisibility &= ~SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; | |
| 172 view.setSystemUiVisibility(systemUiVisibility); | |
| 173 break; | |
| 174 } | |
| 175 default: | |
| 176 assert false : "Unexpected message for ID: " + msg.what; | |
| 177 break; | |
| 178 } | |
| 179 } | |
| 180 }; | |
| 181 | |
| 182 Resources resources = mWindow.getContext().getResources(); | 198 Resources resources = mWindow.getContext().getResources(); |
| 183 float density = resources.getDisplayMetrics().density; | 199 float density = resources.getDisplayMetrics().density; |
| 184 mNotificationMaxDimension = (int) (density * MAX_NOTIFICATION_DIMENSION_
DP); | 200 mNotificationMaxDimension = (int) (density * MAX_NOTIFICATION_DIMENSION_
DP); |
| 185 } | 201 } |
| 186 | 202 |
| 187 /** | 203 /** |
| 188 * Enters or exits persistent fullscreen mode. In this mode, the top contro
ls will be | 204 * Enters or exits persistent fullscreen mode. In this mode, the top contro
ls will be |
| 189 * permanently hidden until this mode is exited. | 205 * permanently hidden until this mode is exited. |
| 190 * | 206 * |
| 191 * @param enabled Whether to enable persistent fullscreen mode. | 207 * @param enabled Whether to enable persistent fullscreen mode. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 } | 311 } |
| 296 contentView.removeOnLayoutChangeListener(this); | 312 contentView.removeOnLayoutChangeListener(this); |
| 297 } | 313 } |
| 298 }; | 314 }; |
| 299 contentView.addOnLayoutChangeListener(mFullscreenOnLayoutChangeListener)
; | 315 contentView.addOnLayoutChangeListener(mFullscreenOnLayoutChangeListener)
; |
| 300 contentView.setSystemUiVisibility(systemUiVisibility); | 316 contentView.setSystemUiVisibility(systemUiVisibility); |
| 301 mContentViewCoreInFullscreen = contentViewCore; | 317 mContentViewCoreInFullscreen = contentViewCore; |
| 302 } | 318 } |
| 303 | 319 |
| 304 /** | 320 /** |
| 321 * Gets the fullscreen ContentViewCore. |
| 322 */ |
| 323 public ContentViewCore getContentViewCoreInFullscreen() { |
| 324 return mContentViewCoreInFullscreen; |
| 325 } |
| 326 |
| 327 /** |
| 305 * Creates (if necessary) and returns a notification bubble. | 328 * Creates (if necessary) and returns a notification bubble. |
| 306 */ | 329 */ |
| 307 private TextBubble getOrCreateNotificationBubble() { | 330 private TextBubble getOrCreateNotificationBubble() { |
| 308 if (mNotificationBubble == null) { | 331 if (mNotificationBubble == null) { |
| 309 Bundle b = new Bundle(); | 332 Bundle b = new Bundle(); |
| 310 b.putBoolean(TextBubble.BACKGROUND_INTRINSIC_PADDING, true); | 333 b.putBoolean(TextBubble.BACKGROUND_INTRINSIC_PADDING, true); |
| 311 b.putBoolean(TextBubble.CENTER, true); | 334 b.putBoolean(TextBubble.CENTER, true); |
| 312 b.putBoolean(TextBubble.UP_DOWN, true); | 335 b.putBoolean(TextBubble.UP_DOWN, true); |
| 313 b.putInt(TextBubble.TEXT_STYLE_ID, android.R.style.TextAppearance_De
viceDefault_Medium); | 336 b.putInt(TextBubble.TEXT_STYLE_ID, android.R.style.TextAppearance_De
viceDefault_Medium); |
| 314 b.putInt(TextBubble.ANIM_STYLE_ID, R.style.FullscreenNotificationBub
ble); | 337 b.putInt(TextBubble.ANIM_STYLE_ID, R.style.FullscreenNotificationBub
ble); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 if (!hasWindowFocus) hideNotificationBubble(); | 398 if (!hasWindowFocus) hideNotificationBubble(); |
| 376 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return; | 399 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return; |
| 377 | 400 |
| 378 mHandler.removeMessages(MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS); | 401 mHandler.removeMessages(MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS); |
| 379 mHandler.removeMessages(MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG); | 402 mHandler.removeMessages(MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG); |
| 380 if (mContentViewCoreInFullscreen == null || !mIsPersistentMode || !hasWi
ndowFocus) return; | 403 if (mContentViewCoreInFullscreen == null || !mIsPersistentMode || !hasWi
ndowFocus) return; |
| 381 mHandler.sendEmptyMessageDelayed( | 404 mHandler.sendEmptyMessageDelayed( |
| 382 MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS, ANDROID_CONTROLS_SHOW_DUR
ATION_MS); | 405 MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS, ANDROID_CONTROLS_SHOW_DUR
ATION_MS); |
| 383 } | 406 } |
| 384 } | 407 } |
| OLD | NEW |