blob: d36437858a8b5cae4bcbf9d6aa63a78948dc456a [file] [log] [blame]
Michael Kolb8233fac2010-10-26 16:08:53 -07001/*
2 * Copyright (C) 2010 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.browser;
18
John Reck74830e12011-03-14 11:43:05 -070019import android.animation.ObjectAnimator;
Michael Kolb8233fac2010-10-26 16:08:53 -070020import android.app.Activity;
John Reckb9a051b2011-03-18 11:55:48 -070021import android.content.pm.PackageManager;
Michael Kolb8233fac2010-10-26 16:08:53 -070022import android.content.res.Configuration;
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
Michael Kolb5a4372f2011-04-29 13:53:10 -070026import android.graphics.Color;
27import android.graphics.drawable.BitmapDrawable;
Michael Kolb8233fac2010-10-26 16:08:53 -070028import android.graphics.drawable.Drawable;
Michael Kolb5a4372f2011-04-29 13:53:10 -070029import android.graphics.drawable.LayerDrawable;
30import android.graphics.drawable.PaintDrawable;
Michael Kolb8233fac2010-10-26 16:08:53 -070031import android.os.Bundle;
John Reck5d43ce82011-06-21 17:16:51 -070032import android.os.Handler;
33import android.os.Message;
Michael Kolb8233fac2010-10-26 16:08:53 -070034import android.text.TextUtils;
35import android.util.Log;
Michael Kolb8233fac2010-10-26 16:08:53 -070036import android.view.Gravity;
37import android.view.LayoutInflater;
38import android.view.Menu;
John Reckbf2ec202011-06-29 17:47:38 -070039import android.view.MotionEvent;
Michael Kolb8233fac2010-10-26 16:08:53 -070040import android.view.View;
Michael Kolb1514bb72010-11-22 09:11:48 -080041import android.view.View.OnClickListener;
John Reckbf2ec202011-06-29 17:47:38 -070042import android.view.View.OnTouchListener;
43import android.view.ViewConfiguration;
Michael Kolb8233fac2010-10-26 16:08:53 -070044import android.view.ViewGroup;
Michael Kolb1514bb72010-11-22 09:11:48 -080045import android.view.ViewGroup.LayoutParams;
Michael Kolb8233fac2010-10-26 16:08:53 -070046import android.view.WindowManager;
Michael Kolb3a696282010-12-05 13:23:24 -080047import android.view.inputmethod.InputMethodManager;
Michael Kolb8233fac2010-10-26 16:08:53 -070048import android.webkit.WebChromeClient;
Michael Kolb8233fac2010-10-26 16:08:53 -070049import android.webkit.WebView;
50import android.widget.FrameLayout;
Michael Kolb1514bb72010-11-22 09:11:48 -080051import android.widget.ImageButton;
Michael Kolb8233fac2010-10-26 16:08:53 -070052import android.widget.LinearLayout;
53import android.widget.Toast;
54
John Reckbf2ec202011-06-29 17:47:38 -070055import com.android.browser.Tab.LockIcon;
56import com.android.internal.view.menu.MenuBuilder;
57
Michael Kolb1bf23132010-11-19 12:55:12 -080058import java.util.List;
59
Michael Kolb8233fac2010-10-26 16:08:53 -070060/**
61 * UI interface definitions
62 */
John Reckbf2ec202011-06-29 17:47:38 -070063public abstract class BaseUi implements UI, WebViewFactory, OnTouchListener {
Michael Kolb8233fac2010-10-26 16:08:53 -070064
65 private static final String LOGTAG = "BaseUi";
66
Michael Kolb66706532010-12-12 19:50:22 -080067 protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS =
Michael Kolb8233fac2010-10-26 16:08:53 -070068 new FrameLayout.LayoutParams(
69 ViewGroup.LayoutParams.MATCH_PARENT,
70 ViewGroup.LayoutParams.MATCH_PARENT);
71
Michael Kolb66706532010-12-12 19:50:22 -080072 protected static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
Michael Kolb8233fac2010-10-26 16:08:53 -070073 new FrameLayout.LayoutParams(
74 ViewGroup.LayoutParams.MATCH_PARENT,
75 ViewGroup.LayoutParams.MATCH_PARENT,
76 Gravity.CENTER);
77
John Reck5d43ce82011-06-21 17:16:51 -070078 private static final int MSG_HIDE_TITLEBAR = 1;
79 private static final int HIDE_TITLEBAR_DELAY = 1500; // in ms
80
Michael Kolb8233fac2010-10-26 16:08:53 -070081 Activity mActivity;
82 UiController mUiController;
83 TabControl mTabControl;
Michael Kolb377ea312011-02-17 14:36:56 -080084 protected Tab mActiveTab;
Michael Kolb3a696282010-12-05 13:23:24 -080085 private InputMethodManager mInputManager;
Michael Kolb8233fac2010-10-26 16:08:53 -070086
87 private Drawable mSecLockIcon;
88 private Drawable mMixLockIcon;
Michael Kolb5a4372f2011-04-29 13:53:10 -070089 protected Drawable mGenericFavicon;
Michael Kolb8233fac2010-10-26 16:08:53 -070090
Michael Kolb8233fac2010-10-26 16:08:53 -070091 private FrameLayout mBrowserFrameLayout;
Michael Kolb66706532010-12-12 19:50:22 -080092 protected FrameLayout mContentView;
Michael Kolbf2055602011-04-09 17:20:03 -070093 protected FrameLayout mCustomViewContainer;
Michael Kolb8233fac2010-10-26 16:08:53 -070094
95 private View mCustomView;
96 private WebChromeClient.CustomViewCallback mCustomViewCallback;
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -040097 private int mOriginalOrientation;
Michael Kolb8233fac2010-10-26 16:08:53 -070098
99 private CombinedBookmarkHistoryView mComboView;
100
101 private LinearLayout mErrorConsoleContainer = null;
102
103 private Toast mStopToast;
Michael Kolb8233fac2010-10-26 16:08:53 -0700104
John Reckbf2ec202011-06-29 17:47:38 -0700105 private float mInitialY;
John Reck5d43ce82011-06-21 17:16:51 -0700106 private int mTitlebarScrollTriggerSlop;
Michael Kolb5a4372f2011-04-29 13:53:10 -0700107
Michael Kolb8233fac2010-10-26 16:08:53 -0700108 // the default <video> poster
109 private Bitmap mDefaultVideoPoster;
110 // the video progress view
111 private View mVideoProgressView;
112
Michael Kolb8233fac2010-10-26 16:08:53 -0700113 private boolean mActivityPaused;
John Reckbf2ec202011-06-29 17:47:38 -0700114 protected boolean mUseQuickControls;
Michael Kolb8233fac2010-10-26 16:08:53 -0700115
116 public BaseUi(Activity browser, UiController controller) {
117 mActivity = browser;
118 mUiController = controller;
119 mTabControl = controller.getTabControl();
120 Resources res = mActivity.getResources();
Michael Kolb3a696282010-12-05 13:23:24 -0800121 mInputManager = (InputMethodManager)
122 browser.getSystemService(Activity.INPUT_METHOD_SERVICE);
Michael Kolb5a72f182011-01-13 20:35:06 -0800123 mSecLockIcon = res.getDrawable(R.drawable.ic_secure_holo_dark);
Michael Kolb8233fac2010-10-26 16:08:53 -0700124 mMixLockIcon = res.getDrawable(R.drawable.ic_partial_secure);
125
Michael Kolb8233fac2010-10-26 16:08:53 -0700126 FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()
127 .getDecorView().findViewById(android.R.id.content);
128 mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(mActivity)
129 .inflate(R.layout.custom_screen, null);
130 mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(
131 R.id.main_content);
132 mErrorConsoleContainer = (LinearLayout) mBrowserFrameLayout
133 .findViewById(R.id.error_console);
134 mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
135 .findViewById(R.id.fullscreen_custom_content);
136 frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
Michael Kolbc38c6042011-04-27 10:46:06 -0700137 setFullscreen(BrowserSettings.getInstance().useFullscreen());
Michael Kolb5a4372f2011-04-29 13:53:10 -0700138 mGenericFavicon = res.getDrawable(
139 R.drawable.app_web_browser_sm);
John Reck5d43ce82011-06-21 17:16:51 -0700140 ViewConfiguration config = ViewConfiguration.get(browser);
141 mTitlebarScrollTriggerSlop = Math.max(
142 config.getScaledOverflingDistance(),
143 config.getScaledOverscrollDistance());
144 mTitlebarScrollTriggerSlop = Math.max(mTitlebarScrollTriggerSlop,
145 config.getScaledTouchSlop());
Michael Kolb8233fac2010-10-26 16:08:53 -0700146 }
147
John Reckb9a051b2011-03-18 11:55:48 -0700148 @Override
149 public WebView createWebView(boolean privateBrowsing) {
150 // Create a new WebView
151 BrowserWebView w = new BrowserWebView(mActivity, null,
152 android.R.attr.webViewStyle, privateBrowsing);
153 initWebViewSettings(w);
154 return w;
155 }
156
157 @Override
158 public WebView createSubWebView(boolean privateBrowsing) {
159 return createWebView(privateBrowsing);
160 }
161
Michael Kolb66706532010-12-12 19:50:22 -0800162 /**
163 * common webview initialization
164 * @param w the webview to initialize
165 */
166 protected void initWebViewSettings(WebView w) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700167 w.setScrollbarFadingEnabled(true);
168 w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
169 w.setMapTrackballToArrowKeys(false); // use trackball directly
170 // Enable the built-in zoom
171 w.getSettings().setBuiltInZoomControls(true);
John Reckb9a051b2011-03-18 11:55:48 -0700172 boolean supportsMultiTouch = mActivity.getPackageManager()
173 .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH);
174 w.getSettings().setDisplayZoomControls(!supportsMultiTouch);
175 w.setExpandedTileBounds(true); // smoother scrolling
Michael Kolb8233fac2010-10-26 16:08:53 -0700176
177 // Add this WebView to the settings observer list and update the
178 // settings
179 final BrowserSettings s = BrowserSettings.getInstance();
John Reck35e9dd62011-04-25 09:01:54 -0700180 s.startManagingSettings(w.getSettings());
Michael Kolb8233fac2010-10-26 16:08:53 -0700181 }
182
183 private void cancelStopToast() {
184 if (mStopToast != null) {
185 mStopToast.cancel();
186 mStopToast = null;
187 }
188 }
189
190 // lifecycle
191
192 public void onPause() {
Michael Kolb7a5cf472010-11-30 13:23:53 -0800193 if (isCustomViewShowing()) {
194 onHideCustomView();
195 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700196 cancelStopToast();
197 mActivityPaused = true;
198 }
199
200 public void onResume() {
201 mActivityPaused = false;
202 }
203
Michael Kolb66706532010-12-12 19:50:22 -0800204 protected boolean isActivityPaused() {
205 return mActivityPaused;
Michael Kolb8233fac2010-10-26 16:08:53 -0700206 }
207
208 public void onConfigurationChanged(Configuration config) {
209 }
210
211 // key handling
212
213 @Override
214 public boolean onBackKey() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700215 if (mComboView != null) {
216 if (!mComboView.onBackPressed()) {
217 mUiController.removeComboView();
218 }
219 return true;
220 }
221 if (mCustomView != null) {
222 mUiController.hideCustomView();
223 return true;
224 }
225 return false;
226 }
227
Michael Kolb2814a362011-05-19 15:49:41 -0700228 @Override
229 public boolean onMenuKey() {
230 return false;
231 }
232
John Reck30c714c2010-12-16 17:30:34 -0800233 // Tab callbacks
Michael Kolb8233fac2010-10-26 16:08:53 -0700234 @Override
John Reck30c714c2010-12-16 17:30:34 -0800235 public void onTabDataChanged(Tab tab) {
236 setUrlTitle(tab);
237 setFavicon(tab);
238 updateLockIconToLatest(tab);
Michael Kolb5a72f182011-01-13 20:35:06 -0800239 updateNavigationState(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700240 }
241
242 @Override
Leon Scroggins4cd97792010-12-03 15:31:56 -0500243 public void bookmarkedStatusHasChanged(Tab tab) {
John Reck94b7e042011-02-15 15:02:33 -0800244 if (tab.inForeground()) {
245 boolean isBookmark = tab.isBookmarkedSite();
246 getTitleBar().setCurrentUrlIsBookmark(isBookmark);
247 }
Leon Scroggins4cd97792010-12-03 15:31:56 -0500248 }
249
250 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700251 public void onPageStopped(Tab tab) {
252 cancelStopToast();
253 if (tab.inForeground()) {
254 mStopToast = Toast
255 .makeText(mActivity, R.string.stopping, Toast.LENGTH_SHORT);
256 mStopToast.show();
257 }
258 }
259
260 @Override
Michael Kolb1bf23132010-11-19 12:55:12 -0800261 public boolean needsRestoreAllTabs() {
John Reck847b5322011-04-14 17:02:18 -0700262 return true;
Michael Kolb1bf23132010-11-19 12:55:12 -0800263 }
264
265 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700266 public void addTab(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700267 }
268
269 @Override
Michael Kolb377ea312011-02-17 14:36:56 -0800270 public void setActiveTab(final Tab tab) {
John Reck5d43ce82011-06-21 17:16:51 -0700271 mHandler.removeMessages(MSG_HIDE_TITLEBAR);
Michael Kolb77df4562010-11-19 14:49:34 -0800272 if ((tab != mActiveTab) && (mActiveTab != null)) {
273 removeTabFromContentView(mActiveTab);
John Reckbf2ec202011-06-29 17:47:38 -0700274 WebView web = mActiveTab.getWebView();
275 if (web != null) {
276 web.setOnTouchListener(null);
277 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700278 }
Michael Kolb77df4562010-11-19 14:49:34 -0800279 mActiveTab = tab;
John Reckbf2ec202011-06-29 17:47:38 -0700280 WebView web = mActiveTab.getWebView();
281 if (web != null && !mUseQuickControls) {
282 web.setOnTouchListener(this);
283 }
John Reck5d43ce82011-06-21 17:16:51 -0700284 attachTabToContentView(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700285 setShouldShowErrorConsole(tab, mUiController.shouldShowErrorConsole());
John Reck30c714c2010-12-16 17:30:34 -0800286 onTabDataChanged(tab);
287 onProgressChanged(tab);
John Reck117f07d2011-01-24 09:39:03 -0800288 boolean incognito = mActiveTab.getWebView().isPrivateBrowsingEnabled();
Michael Kolb7cdc4902011-02-03 17:54:40 -0800289 getTitleBar().setIncognitoMode(incognito);
Patrick Scott92066772011-03-10 08:46:27 -0500290 updateAutoLogin(tab, false);
Michael Kolb8233fac2010-10-26 16:08:53 -0700291 }
292
Michael Kolbcfa3af52010-12-14 10:36:11 -0800293 Tab getActiveTab() {
294 return mActiveTab;
295 }
296
Michael Kolb8233fac2010-10-26 16:08:53 -0700297 @Override
Michael Kolb1bf23132010-11-19 12:55:12 -0800298 public void updateTabs(List<Tab> tabs) {
Michael Kolb1bf23132010-11-19 12:55:12 -0800299 }
300
301 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700302 public void removeTab(Tab tab) {
Michael Kolb77df4562010-11-19 14:49:34 -0800303 if (mActiveTab == tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700304 removeTabFromContentView(tab);
Michael Kolb77df4562010-11-19 14:49:34 -0800305 mActiveTab = null;
Michael Kolb8233fac2010-10-26 16:08:53 -0700306 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700307 }
308
309 @Override
310 public void detachTab(Tab tab) {
311 removeTabFromContentView(tab);
312 }
313
314 @Override
315 public void attachTab(Tab tab) {
316 attachTabToContentView(tab);
317 }
318
Michael Kolb377ea312011-02-17 14:36:56 -0800319 protected void attachTabToContentView(Tab tab) {
Michael Kolbd1e2ccc2011-01-24 11:38:31 -0800320 if ((tab == null) || (tab.getWebView() == null)) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700321 return;
322 }
323 View container = tab.getViewContainer();
324 WebView mainView = tab.getWebView();
325 // Attach the WebView to the container and then attach the
326 // container to the content view.
327 FrameLayout wrapper =
328 (FrameLayout) container.findViewById(R.id.webview_wrapper);
329 ViewGroup parent = (ViewGroup) mainView.getParent();
330 if (parent != wrapper) {
331 if (parent != null) {
332 Log.w(LOGTAG, "mMainView already has a parent in"
333 + " attachTabToContentView!");
334 parent.removeView(mainView);
335 }
336 wrapper.addView(mainView);
337 } else {
338 Log.w(LOGTAG, "mMainView is already attached to wrapper in"
339 + " attachTabToContentView!");
340 }
341 parent = (ViewGroup) container.getParent();
342 if (parent != mContentView) {
343 if (parent != null) {
344 Log.w(LOGTAG, "mContainer already has a parent in"
345 + " attachTabToContentView!");
346 parent.removeView(container);
347 }
348 mContentView.addView(container, COVER_SCREEN_PARAMS);
349 } else {
350 Log.w(LOGTAG, "mContainer is already attached to content in"
351 + " attachTabToContentView!");
352 }
353 mUiController.attachSubWindow(tab);
354 }
355
356 private void removeTabFromContentView(Tab tab) {
Michael Kolb7cdc4902011-02-03 17:54:40 -0800357 hideTitleBar();
Michael Kolb8233fac2010-10-26 16:08:53 -0700358 // Remove the container that contains the main WebView.
359 WebView mainView = tab.getWebView();
360 View container = tab.getViewContainer();
361 if (mainView == null) {
362 return;
363 }
364 // Remove the container from the content and then remove the
365 // WebView from the container. This will trigger a focus change
366 // needed by WebView.
Michael Kolb20776cc2011-01-31 10:19:05 -0800367 mainView.setEmbeddedTitleBar(null);
Michael Kolb8233fac2010-10-26 16:08:53 -0700368 FrameLayout wrapper =
369 (FrameLayout) container.findViewById(R.id.webview_wrapper);
370 wrapper.removeView(mainView);
371 mContentView.removeView(container);
372 mUiController.endActionMode();
373 mUiController.removeSubWindow(tab);
374 ErrorConsoleView errorConsole = tab.getErrorConsole(false);
375 if (errorConsole != null) {
376 mErrorConsoleContainer.removeView(errorConsole);
377 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700378 }
379
Michael Kolba713ec82010-11-29 17:27:06 -0800380 @Override
381 public void onSetWebView(Tab tab, WebView webView) {
382 View container = tab.getViewContainer();
383 if (container == null) {
384 // The tab consists of a container view, which contains the main
385 // WebView, as well as any other UI elements associated with the tab.
386 container = mActivity.getLayoutInflater().inflate(R.layout.tab,
387 null);
388 tab.setViewContainer(container);
389 }
390 if (tab.getWebView() != webView) {
391 // Just remove the old one.
392 FrameLayout wrapper =
393 (FrameLayout) container.findViewById(R.id.webview_wrapper);
394 wrapper.removeView(tab.getWebView());
395 }
396 }
397
Michael Kolb8233fac2010-10-26 16:08:53 -0700398 /**
Michael Kolb1514bb72010-11-22 09:11:48 -0800399 * create a sub window container and webview for the tab
400 * Note: this methods operates through side-effects for now
401 * it sets both the subView and subViewContainer for the given tab
402 * @param tab tab to create the sub window for
403 * @param subView webview to be set as a subwindow for the tab
404 */
405 @Override
406 public void createSubWindow(Tab tab, WebView subView) {
407 View subViewContainer = mActivity.getLayoutInflater().inflate(
408 R.layout.browser_subwindow, null);
409 ViewGroup inner = (ViewGroup) subViewContainer
410 .findViewById(R.id.inner_container);
411 inner.addView(subView, new LayoutParams(LayoutParams.MATCH_PARENT,
412 LayoutParams.MATCH_PARENT));
413 final ImageButton cancel = (ImageButton) subViewContainer
414 .findViewById(R.id.subwindow_close);
415 final WebView cancelSubView = subView;
416 cancel.setOnClickListener(new OnClickListener() {
417 public void onClick(View v) {
418 cancelSubView.getWebChromeClient().onCloseWindow(cancelSubView);
419 }
420 });
421 tab.setSubWebView(subView);
422 tab.setSubViewContainer(subViewContainer);
423 }
424
425 /**
Michael Kolb8233fac2010-10-26 16:08:53 -0700426 * Remove the sub window from the content view.
427 */
428 @Override
429 public void removeSubWindow(View subviewContainer) {
430 mContentView.removeView(subviewContainer);
431 mUiController.endActionMode();
432 }
433
434 /**
435 * Attach the sub window to the content view.
436 */
437 @Override
438 public void attachSubWindow(View container) {
Michael Kolb1514bb72010-11-22 09:11:48 -0800439 if (container.getParent() != null) {
440 // already attached, remove first
441 ((ViewGroup) container.getParent()).removeView(container);
442 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700443 mContentView.addView(container, COVER_SCREEN_PARAMS);
444 }
445
Michael Kolb11d19782011-03-20 10:17:40 -0700446 protected void refreshWebView() {
Michael Kolb46f987e2011-04-05 10:39:10 -0700447 WebView web = getWebView();
448 if (web != null) {
449 web.invalidate();
Michael Kolb11d19782011-03-20 10:17:40 -0700450 }
451 }
452
Michael Kolb46f987e2011-04-05 10:39:10 -0700453 public void editUrl(boolean clearInput) {
454 if (mUiController.isInCustomActionMode()) {
455 mUiController.endActionMode();
456 }
457 showTitleBar();
458 getTitleBar().startEditingUrl(clearInput);
459 }
460
Michael Kolb7cdc4902011-02-03 17:54:40 -0800461 boolean canShowTitleBar() {
462 return !isTitleBarShowing()
463 && !isActivityPaused()
464 && (getActiveTab() != null)
Michael Kolb46f987e2011-04-05 10:39:10 -0700465 && (getWebView() != null)
Michael Kolb7cdc4902011-02-03 17:54:40 -0800466 && !mUiController.isInCustomActionMode();
467 }
468
469 void showTitleBar() {
Michael Kolb46f987e2011-04-05 10:39:10 -0700470 if (canShowTitleBar()) {
471 getTitleBar().show();
472 }
Michael Kolb7cdc4902011-02-03 17:54:40 -0800473 }
474
475 protected void hideTitleBar() {
Michael Kolb46f987e2011-04-05 10:39:10 -0700476 if (getTitleBar().isShowing()) {
477 getTitleBar().hide();
478 }
Michael Kolb7cdc4902011-02-03 17:54:40 -0800479 }
480
481 protected boolean isTitleBarShowing() {
Michael Kolb46f987e2011-04-05 10:39:10 -0700482 return getTitleBar().isShowing();
Michael Kolb7cdc4902011-02-03 17:54:40 -0800483 }
484
John Reck5d43ce82011-06-21 17:16:51 -0700485 public boolean isEditingUrl() {
486 return getTitleBar().isEditingUrl();
487 }
488
Michael Kolb7cdc4902011-02-03 17:54:40 -0800489 protected abstract TitleBarBase getTitleBar();
490
491 protected void setTitleGravity(int gravity) {
Michael Kolb46f987e2011-04-05 10:39:10 -0700492 WebView web = getWebView();
493 if (web != null) {
494 web.setTitleBarGravity(gravity);
Michael Kolb8233fac2010-10-26 16:08:53 -0700495 }
496 }
497
Michael Kolb66706532010-12-12 19:50:22 -0800498 @Override
Michael Kolb11d19782011-03-20 10:17:40 -0700499 public void showVoiceTitleBar(String title, List<String> results) {
500 getTitleBar().setInVoiceMode(true, results);
Michael Kolb7cdc4902011-02-03 17:54:40 -0800501 getTitleBar().setDisplayTitle(title);
Michael Kolb8233fac2010-10-26 16:08:53 -0700502 }
503
Michael Kolb66706532010-12-12 19:50:22 -0800504 @Override
505 public void revertVoiceTitleBar(Tab tab) {
Michael Kolb11d19782011-03-20 10:17:40 -0700506 getTitleBar().setInVoiceMode(false, null);
John Reck30c714c2010-12-16 17:30:34 -0800507 String url = tab.getUrl();
Michael Kolb7cdc4902011-02-03 17:54:40 -0800508 getTitleBar().setDisplayTitle(url);
Michael Kolb8233fac2010-10-26 16:08:53 -0700509 }
510
511 @Override
Michael Kolb11d19782011-03-20 10:17:40 -0700512 public void registerDropdownChangeListener(DropdownChangeListener d) {
513 getTitleBar().registerDropdownChangeListener(d);
514 }
515
516 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700517 public void showComboView(boolean startWithHistory, Bundle extras) {
John Reck439c9a52010-12-14 10:04:39 -0800518 if (mComboView != null) {
519 return;
520 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700521 mComboView = new CombinedBookmarkHistoryView(mActivity,
522 mUiController,
523 startWithHistory ?
524 CombinedBookmarkHistoryView.FRAGMENT_ID_HISTORY
525 : CombinedBookmarkHistoryView.FRAGMENT_ID_BOOKMARKS,
526 extras);
Michael Kolb47d63f82011-01-18 10:48:40 -0800527 FrameLayout wrapper =
528 (FrameLayout) mContentView.findViewById(R.id.webview_wrapper);
529 wrapper.setVisibility(View.GONE);
Michael Kolbc16c5952011-03-29 15:37:03 -0700530 getTitleBar().stopEditingUrl();
Michael Kolb3a696282010-12-05 13:23:24 -0800531 dismissIME();
Michael Kolbc16c5952011-03-29 15:37:03 -0700532 hideTitleBar();
Michael Kolb3a696282010-12-05 13:23:24 -0800533 if (mActiveTab != null) {
Michael Kolb3a696282010-12-05 13:23:24 -0800534 mActiveTab.putInBackground();
535 }
John Reck74830e12011-03-14 11:43:05 -0700536 mComboView.setAlpha(0f);
537 ObjectAnimator anim = ObjectAnimator.ofFloat(mComboView, "alpha", 0f, 1f);
538 Resources res = mActivity.getResources();
539 anim.setDuration(res.getInteger(R.integer.comboViewFadeInDuration));
540 anim.start();
Michael Kolb8233fac2010-10-26 16:08:53 -0700541 mContentView.addView(mComboView, COVER_SCREEN_PARAMS);
542 }
543
Michael Kolbba238702011-03-08 10:40:50 -0800544 public boolean isComboViewShowing() {
545 return (mComboView != null);
546 }
547
Michael Kolb8233fac2010-10-26 16:08:53 -0700548 /**
549 * dismiss the ComboPage
550 */
551 @Override
552 public void hideComboView() {
553 if (mComboView != null) {
554 mContentView.removeView(mComboView);
Michael Kolb47d63f82011-01-18 10:48:40 -0800555 FrameLayout wrapper =
556 (FrameLayout) mContentView.findViewById(R.id.webview_wrapper);
557 wrapper.setVisibility(View.VISIBLE);
Michael Kolb8233fac2010-10-26 16:08:53 -0700558 mComboView = null;
559 }
Michael Kolb3a696282010-12-05 13:23:24 -0800560 if (mActiveTab != null) {
561 mActiveTab.putInForeground();
562 }
John Reckb3417f02011-01-14 11:01:05 -0800563 mActivity.invalidateOptionsMenu();
Michael Kolb8233fac2010-10-26 16:08:53 -0700564 }
565
566 @Override
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -0400567 public void showCustomView(View view, int requestedOrientation,
Michael Kolb8233fac2010-10-26 16:08:53 -0700568 WebChromeClient.CustomViewCallback callback) {
569 // if a view already exists then immediately terminate the new one
570 if (mCustomView != null) {
571 callback.onCustomViewHidden();
572 return;
573 }
574
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -0400575 mOriginalOrientation = mActivity.getRequestedOrientation();
576
Michael Kolb8233fac2010-10-26 16:08:53 -0700577 // Add the custom view to its container.
578 mCustomViewContainer.addView(view, COVER_SCREEN_GRAVITY_CENTER);
579 mCustomView = view;
580 mCustomViewCallback = callback;
581 // Hide the content view.
582 mContentView.setVisibility(View.GONE);
583 // Finally show the custom view container.
584 setStatusBarVisibility(false);
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -0400585 mActivity.setRequestedOrientation(requestedOrientation);
Michael Kolb8233fac2010-10-26 16:08:53 -0700586 mCustomViewContainer.setVisibility(View.VISIBLE);
587 mCustomViewContainer.bringToFront();
588 }
589
590 @Override
591 public void onHideCustomView() {
592 if (mCustomView == null)
593 return;
594
595 // Hide the custom view.
596 mCustomView.setVisibility(View.GONE);
597 // Remove the custom view from its container.
598 mCustomViewContainer.removeView(mCustomView);
599 mCustomView = null;
600 mCustomViewContainer.setVisibility(View.GONE);
601 mCustomViewCallback.onCustomViewHidden();
602 // Show the content view.
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -0400603 mActivity.setRequestedOrientation(mOriginalOrientation);
Michael Kolb8233fac2010-10-26 16:08:53 -0700604 setStatusBarVisibility(true);
605 mContentView.setVisibility(View.VISIBLE);
606 }
607
608 @Override
609 public boolean isCustomViewShowing() {
610 return mCustomView != null;
611 }
612
Michael Kolb66706532010-12-12 19:50:22 -0800613 protected void dismissIME() {
Michael Kolb3a696282010-12-05 13:23:24 -0800614 if (mInputManager.isActive()) {
615 mInputManager.hideSoftInputFromWindow(mContentView.getWindowToken(),
616 0);
617 }
618 }
619
Michael Kolb66706532010-12-12 19:50:22 -0800620 @Override
621 public boolean showsWeb() {
622 return mCustomView == null
623 && mComboView == null;
624 }
625
Patrick Scott92066772011-03-10 08:46:27 -0500626 @Override
627 public void showAutoLogin(Tab tab) {
628 updateAutoLogin(tab, true);
629 }
630
631 @Override
632 public void hideAutoLogin(Tab tab) {
633 updateAutoLogin(tab, true);
634 }
635
Michael Kolb8233fac2010-10-26 16:08:53 -0700636 // -------------------------------------------------------------------------
637
Michael Kolb5a72f182011-01-13 20:35:06 -0800638 protected void updateNavigationState(Tab tab) {
639 }
640
Michael Kolb11d19782011-03-20 10:17:40 -0700641 protected void updateAutoLogin(Tab tab, boolean animate) {
642 getTitleBar().updateAutoLogin(tab, animate);
643 }
Patrick Scott92066772011-03-10 08:46:27 -0500644
Michael Kolb8233fac2010-10-26 16:08:53 -0700645 /**
646 * Update the lock icon to correspond to our latest state.
647 */
Michael Kolb66706532010-12-12 19:50:22 -0800648 protected void updateLockIconToLatest(Tab t) {
John Reck30c714c2010-12-16 17:30:34 -0800649 if (t != null && t.inForeground()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700650 updateLockIconImage(t.getLockIconType());
651 }
652 }
653
654 /**
Michael Kolb8233fac2010-10-26 16:08:53 -0700655 * Updates the lock-icon image in the title-bar.
656 */
John Reck30c714c2010-12-16 17:30:34 -0800657 private void updateLockIconImage(LockIcon lockIconType) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700658 Drawable d = null;
John Reck30c714c2010-12-16 17:30:34 -0800659 if (lockIconType == LockIcon.LOCK_ICON_SECURE) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700660 d = mSecLockIcon;
John Reck30c714c2010-12-16 17:30:34 -0800661 } else if (lockIconType == LockIcon.LOCK_ICON_MIXED) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700662 d = mMixLockIcon;
663 }
Michael Kolb7cdc4902011-02-03 17:54:40 -0800664 getTitleBar().setLock(d);
Michael Kolb8233fac2010-10-26 16:08:53 -0700665 }
666
John Reck30c714c2010-12-16 17:30:34 -0800667 protected void setUrlTitle(Tab tab) {
668 String url = tab.getUrl();
669 String title = tab.getTitle();
Michael Kolb66706532010-12-12 19:50:22 -0800670 if (TextUtils.isEmpty(title)) {
671 title = url;
Michael Kolb81b6f832010-12-12 12:44:27 -0800672 }
Michael Kolb66706532010-12-12 19:50:22 -0800673 if (tab.isInVoiceSearchMode()) return;
674 if (tab.inForeground()) {
Michael Kolb7cdc4902011-02-03 17:54:40 -0800675 getTitleBar().setDisplayTitle(url);
Michael Kolb66706532010-12-12 19:50:22 -0800676 }
677 }
678
679 // Set the favicon in the title bar.
John Reck30c714c2010-12-16 17:30:34 -0800680 protected void setFavicon(Tab tab) {
681 if (tab.inForeground()) {
682 Bitmap icon = tab.getFavicon();
Michael Kolb7cdc4902011-02-03 17:54:40 -0800683 getTitleBar().setFavicon(icon);
John Reck30c714c2010-12-16 17:30:34 -0800684 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700685 }
686
687 @Override
688 public void onActionModeFinished(boolean inLoad) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700689 }
690
Michael Kolb66706532010-12-12 19:50:22 -0800691 // active tabs page
692
693 public void showActiveTabsPage() {
694 }
695
696 /**
697 * Remove the active tabs page.
698 */
699 public void removeActiveTabsPage() {
700 }
701
Michael Kolb8233fac2010-10-26 16:08:53 -0700702 // menu handling callbacks
703
704 @Override
Michael Kolb1acef692011-03-08 14:12:06 -0800705 public boolean onPrepareOptionsMenu(Menu menu) {
706 return true;
707 }
708
709 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700710 public void onOptionsMenuOpened() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700711 }
712
713 @Override
714 public void onExtendedMenuOpened() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700715 }
716
717 @Override
718 public void onOptionsMenuClosed(boolean inLoad) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700719 }
720
721 @Override
722 public void onExtendedMenuClosed(boolean inLoad) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700723 }
724
725 @Override
726 public void onContextMenuCreated(Menu menu) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700727 }
728
729 @Override
730 public void onContextMenuClosed(Menu menu, boolean inLoad) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700731 }
732
733 // error console
734
735 @Override
736 public void setShouldShowErrorConsole(Tab tab, boolean flag) {
Michael Kolb9fcefd12011-02-17 10:55:59 -0800737 if (tab == null) return;
Michael Kolb8233fac2010-10-26 16:08:53 -0700738 ErrorConsoleView errorConsole = tab.getErrorConsole(true);
739 if (flag) {
740 // Setting the show state of the console will cause it's the layout
741 // to be inflated.
742 if (errorConsole.numberOfErrors() > 0) {
743 errorConsole.showConsole(ErrorConsoleView.SHOW_MINIMIZED);
744 } else {
745 errorConsole.showConsole(ErrorConsoleView.SHOW_NONE);
746 }
747 if (errorConsole.getParent() != null) {
748 mErrorConsoleContainer.removeView(errorConsole);
749 }
750 // Now we can add it to the main view.
751 mErrorConsoleContainer.addView(errorConsole,
752 new LinearLayout.LayoutParams(
753 ViewGroup.LayoutParams.MATCH_PARENT,
754 ViewGroup.LayoutParams.WRAP_CONTENT));
755 } else {
756 mErrorConsoleContainer.removeView(errorConsole);
757 }
758 }
759
760 private void setStatusBarVisibility(boolean visible) {
Joe Onoratod3bf86f2011-01-25 20:07:10 -0800761 WindowManager.LayoutParams params = mActivity.getWindow().getAttributes();
762 params.systemUiVisibility = visible ? View.STATUS_BAR_VISIBLE : View.STATUS_BAR_HIDDEN;
763 mActivity.getWindow().setAttributes(params);
Michael Kolb8233fac2010-10-26 16:08:53 -0700764 }
765
Michael Kolb8233fac2010-10-26 16:08:53 -0700766 // -------------------------------------------------------------------------
767 // Helper function for WebChromeClient
768 // -------------------------------------------------------------------------
769
770 @Override
771 public Bitmap getDefaultVideoPoster() {
772 if (mDefaultVideoPoster == null) {
773 mDefaultVideoPoster = BitmapFactory.decodeResource(
774 mActivity.getResources(), R.drawable.default_video_poster);
775 }
776 return mDefaultVideoPoster;
777 }
778
779 @Override
780 public View getVideoLoadingProgressView() {
781 if (mVideoProgressView == null) {
782 LayoutInflater inflater = LayoutInflater.from(mActivity);
783 mVideoProgressView = inflater.inflate(
784 R.layout.video_loading_progress, null);
785 }
786 return mVideoProgressView;
787 }
788
Michael Kolb843510f2010-12-09 10:51:49 -0800789 @Override
790 public void showMaxTabsWarning() {
791 Toast warning = Toast.makeText(mActivity,
792 mActivity.getString(R.string.max_tabs_warning),
793 Toast.LENGTH_SHORT);
794 warning.show();
795 }
796
Michael Kolbfdb70242011-03-24 09:41:11 -0700797 protected void captureTab(final Tab tab) {
798 captureTab(tab,
799 (int) mActivity.getResources()
800 .getDimension(R.dimen.qc_thumb_width),
801 (int) mActivity.getResources()
802 .getDimension(R.dimen.qc_thumb_height));
803 }
804
805 protected void captureTab(final Tab tab, int width, int height) {
806 if ((tab == null) || (tab.getWebView() == null)) return;
807 Bitmap sshot = Controller.createScreenshot(tab, width, height);
808 tab.setScreenshot(sshot);
809 }
810
Michael Kolb46f987e2011-04-05 10:39:10 -0700811 protected WebView getWebView() {
812 if (mActiveTab != null) {
813 return mActiveTab.getWebView();
814 } else {
815 return null;
816 }
Michael Kolbfdb70242011-03-24 09:41:11 -0700817 }
818
Michael Kolbfedb4922011-04-20 16:45:33 -0700819 protected Menu getMenu() {
820 MenuBuilder menu = new MenuBuilder(mActivity);
821 mActivity.getMenuInflater().inflate(R.menu.browser, menu);
822 return menu;
823 }
824
Michael Kolbc38c6042011-04-27 10:46:06 -0700825 public void setFullscreen(boolean enabled) {
826 if (enabled) {
827 mActivity.getWindow().setFlags(
828 WindowManager.LayoutParams.FLAG_FULLSCREEN,
829 WindowManager.LayoutParams.FLAG_FULLSCREEN);
830 } else {
831 mActivity.getWindow().clearFlags(
832 WindowManager.LayoutParams.FLAG_FULLSCREEN);
833 }
834 }
835
Michael Kolb5a4372f2011-04-29 13:53:10 -0700836 protected Drawable getFaviconDrawable(Bitmap icon) {
837 Drawable[] array = new Drawable[3];
838 array[0] = new PaintDrawable(Color.BLACK);
839 PaintDrawable p = new PaintDrawable(Color.WHITE);
840 array[1] = p;
841 if (icon == null) {
842 array[2] = mGenericFavicon;
843 } else {
844 array[2] = new BitmapDrawable(icon);
845 }
846 LayerDrawable d = new LayerDrawable(array);
847 d.setLayerInset(1, 1, 1, 1, 1);
848 d.setLayerInset(2, 2, 2, 2, 2);
849 return d;
850 }
851
John Reck5d43ce82011-06-21 17:16:51 -0700852 public boolean isLoading() {
853 return mActiveTab != null ? mActiveTab.inPageLoad() : false;
854 }
855
856 /**
857 * Suggest to the UI that the title bar can be hidden. The UI will then
858 * decide whether or not to hide based off a number of factors, such
859 * as if the user is editing the URL bar or if the page is loading
860 */
861 public void suggestHideTitleBar() {
862 if (!isLoading() && !isEditingUrl()) {
863 hideTitleBar();
864 }
865 }
866
867 @Override
John Reckbf2ec202011-06-29 17:47:38 -0700868 public boolean onTouch(View v, MotionEvent event) {
869 switch (event.getAction()) {
870 case MotionEvent.ACTION_DOWN:
871 mInitialY = event.getY();
872 break;
873 case MotionEvent.ACTION_MOVE:
874 WebView web = (WebView) v;
875 if (!isTitleBarShowing()
876 && web.getVisibleTitleHeight() == 0
877 && event.getY() > (mInitialY + mTitlebarScrollTriggerSlop)) {
John Reck5d43ce82011-06-21 17:16:51 -0700878 mHandler.removeMessages(MSG_HIDE_TITLEBAR);
879 showTitleBar();
John Reckbf2ec202011-06-29 17:47:38 -0700880 } else if (event.getY() < mInitialY) {
881 mInitialY = event.getY();
882 }
883 break;
884 case MotionEvent.ACTION_CANCEL:
885 case MotionEvent.ACTION_UP:
886 if (isTitleBarShowing()) {
John Reck5d43ce82011-06-21 17:16:51 -0700887 Message msg = Message.obtain(mHandler, MSG_HIDE_TITLEBAR);
888 mHandler.sendMessageDelayed(msg, HIDE_TITLEBAR_DELAY);
John Reck5d43ce82011-06-21 17:16:51 -0700889 }
John Reckbf2ec202011-06-29 17:47:38 -0700890 break;
John Reck5d43ce82011-06-21 17:16:51 -0700891 }
John Reckbf2ec202011-06-29 17:47:38 -0700892 return false;
John Reck5d43ce82011-06-21 17:16:51 -0700893 }
894
895 private Handler mHandler = new Handler() {
896
897 @Override
898 public void handleMessage(Message msg) {
899 if (msg.what == MSG_HIDE_TITLEBAR) {
900 suggestHideTitleBar();
901 }
902 }
903 };
Michael Kolb8233fac2010-10-26 16:08:53 -0700904}