1/*
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
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.content.res.Configuration;
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
26import android.graphics.Color;
27import android.graphics.drawable.BitmapDrawable;
28import android.graphics.drawable.Drawable;
29import android.graphics.drawable.LayerDrawable;
30import android.graphics.drawable.PaintDrawable;
31import android.os.Bundle;
32import android.os.Handler;
33import android.os.Message;
34import android.text.TextUtils;
35import android.view.Gravity;
36import android.view.LayoutInflater;
37import android.view.Menu;
38import android.view.MenuItem;
39import android.view.MotionEvent;
40import android.view.View;
41import android.view.View.OnClickListener;
42import android.view.ViewGroup;
43import android.view.ViewGroup.LayoutParams;
44import android.view.Window;
45import android.view.WindowManager;
46import android.view.inputmethod.InputMethodManager;
47import android.webkit.WebChromeClient;
48import android.webkit.WebView;
49import android.widget.FrameLayout;
50import android.widget.ImageButton;
51import android.widget.LinearLayout;
52import android.widget.Toast;
53
54import com.android.browser.Tab.SecurityState;
55import com.android.internal.view.menu.MenuBuilder;
56
57import java.util.List;
58
59/**
60 * UI interface definitions
61 */
62public abstract class BaseUi implements UI {
63
64    private static final String LOGTAG = "BaseUi";
65
66    protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS =
67        new FrameLayout.LayoutParams(
68        ViewGroup.LayoutParams.MATCH_PARENT,
69        ViewGroup.LayoutParams.MATCH_PARENT);
70
71    protected static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
72        new FrameLayout.LayoutParams(
73        ViewGroup.LayoutParams.MATCH_PARENT,
74        ViewGroup.LayoutParams.MATCH_PARENT,
75        Gravity.CENTER);
76
77    private static final int MSG_HIDE_TITLEBAR = 1;
78    public static final int HIDE_TITLEBAR_DELAY = 1500; // in ms
79
80    Activity mActivity;
81    UiController mUiController;
82    TabControl mTabControl;
83    protected Tab mActiveTab;
84    private InputMethodManager mInputManager;
85
86    private Drawable mLockIconSecure;
87    private Drawable mLockIconMixed;
88    protected Drawable mGenericFavicon;
89
90    protected FrameLayout mContentView;
91    protected FrameLayout mCustomViewContainer;
92    protected FrameLayout mFullscreenContainer;
93    private FrameLayout mFixedTitlebarContainer;
94
95    private View mCustomView;
96    private WebChromeClient.CustomViewCallback mCustomViewCallback;
97    private int mOriginalOrientation;
98
99    private LinearLayout mErrorConsoleContainer = null;
100
101    private UrlBarAutoShowManager mUrlBarAutoShowManager;
102
103    private Toast mStopToast;
104
105    // the default <video> poster
106    private Bitmap mDefaultVideoPoster;
107    // the video progress view
108    private View mVideoProgressView;
109
110    private boolean mActivityPaused;
111    protected boolean mUseQuickControls;
112    protected TitleBar mTitleBar;
113    private NavigationBarBase mNavigationBar;
114    protected PieControl mPieControl;
115    private boolean mBlockFocusAnimations;
116
117    public BaseUi(Activity browser, UiController controller) {
118        mActivity = browser;
119        mUiController = controller;
120        mTabControl = controller.getTabControl();
121        Resources res = mActivity.getResources();
122        mInputManager = (InputMethodManager)
123                browser.getSystemService(Activity.INPUT_METHOD_SERVICE);
124        mLockIconSecure = res.getDrawable(R.drawable.ic_secure_holo_dark);
125        mLockIconMixed = res.getDrawable(R.drawable.ic_secure_partial_holo_dark);
126        FrameLayout frameLayout = (FrameLayout) mActivity.getWindow()
127                .getDecorView().findViewById(android.R.id.content);
128        LayoutInflater.from(mActivity)
129                .inflate(R.layout.custom_screen, frameLayout);
130        mFixedTitlebarContainer = (FrameLayout) frameLayout.findViewById(
131                R.id.fixed_titlebar_container);
132        mContentView = (FrameLayout) frameLayout.findViewById(
133                R.id.main_content);
134        mCustomViewContainer = (FrameLayout) frameLayout.findViewById(
135                R.id.fullscreen_custom_content);
136        mErrorConsoleContainer = (LinearLayout) frameLayout
137                .findViewById(R.id.error_console);
138        setFullscreen(BrowserSettings.getInstance().useFullscreen());
139        mGenericFavicon = res.getDrawable(
140                R.drawable.app_web_browser_sm);
141        mTitleBar = new TitleBar(mActivity, mUiController, this,
142                mContentView);
143        mTitleBar.setProgress(100);
144        mNavigationBar = mTitleBar.getNavigationBar();
145        mUrlBarAutoShowManager = new UrlBarAutoShowManager(this);
146    }
147
148    private void cancelStopToast() {
149        if (mStopToast != null) {
150            mStopToast.cancel();
151            mStopToast = null;
152        }
153    }
154
155    // lifecycle
156
157    public void onPause() {
158        if (isCustomViewShowing()) {
159            onHideCustomView();
160        }
161        cancelStopToast();
162        mActivityPaused = true;
163    }
164
165    public void onResume() {
166        mActivityPaused = false;
167        // check if we exited without setting active tab
168        // b: 5188145
169        final Tab ct = mTabControl.getCurrentTab();
170        if (ct != null) {
171            setActiveTab(ct);
172        }
173        mTitleBar.onResume();
174    }
175
176    protected boolean isActivityPaused() {
177        return mActivityPaused;
178    }
179
180    public void onConfigurationChanged(Configuration config) {
181    }
182
183    public Activity getActivity() {
184        return mActivity;
185    }
186
187    // key handling
188
189    @Override
190    public boolean onBackKey() {
191        if (mCustomView != null) {
192            mUiController.hideCustomView();
193            return true;
194        }
195        return false;
196    }
197
198    @Override
199    public boolean onMenuKey() {
200        return false;
201    }
202
203    @Override
204    public void setUseQuickControls(boolean useQuickControls) {
205        mUseQuickControls = useQuickControls;
206        mTitleBar.setUseQuickControls(mUseQuickControls);
207        if (useQuickControls) {
208            mPieControl = new PieControl(mActivity, mUiController, this);
209            mPieControl.attachToContainer(mContentView);
210        } else {
211            if (mPieControl != null) {
212                mPieControl.removeFromContainer(mContentView);
213            }
214        }
215        updateUrlBarAutoShowManagerTarget();
216    }
217
218    // Tab callbacks
219    @Override
220    public void onTabDataChanged(Tab tab) {
221        setUrlTitle(tab);
222        setFavicon(tab);
223        updateLockIconToLatest(tab);
224        updateNavigationState(tab);
225        mTitleBar.onTabDataChanged(tab);
226        mNavigationBar.onTabDataChanged(tab);
227        onProgressChanged(tab);
228    }
229
230    @Override
231    public void onProgressChanged(Tab tab) {
232        int progress = tab.getLoadProgress();
233        if (tab.inForeground()) {
234            mTitleBar.setProgress(progress);
235        }
236    }
237
238    @Override
239    public void bookmarkedStatusHasChanged(Tab tab) {
240        if (tab.inForeground()) {
241            boolean isBookmark = tab.isBookmarkedSite();
242            mNavigationBar.setCurrentUrlIsBookmark(isBookmark);
243        }
244    }
245
246    @Override
247    public void onPageStopped(Tab tab) {
248        cancelStopToast();
249        if (tab.inForeground()) {
250            mStopToast = Toast
251                    .makeText(mActivity, R.string.stopping, Toast.LENGTH_SHORT);
252            mStopToast.show();
253        }
254    }
255
256    @Override
257    public boolean needsRestoreAllTabs() {
258        return true;
259    }
260
261    @Override
262    public void addTab(Tab tab) {
263    }
264
265    @Override
266    public void setActiveTab(final Tab tab) {
267        if (tab == null) return;
268        // block unnecessary focus change animations during tab switch
269        mBlockFocusAnimations = true;
270        mHandler.removeMessages(MSG_HIDE_TITLEBAR);
271        if ((tab != mActiveTab) && (mActiveTab != null)) {
272            removeTabFromContentView(mActiveTab);
273            WebView web = mActiveTab.getWebView();
274            if (web != null) {
275                web.setOnTouchListener(null);
276            }
277        }
278        mActiveTab = tab;
279        BrowserWebView web = (BrowserWebView) mActiveTab.getWebView();
280        updateUrlBarAutoShowManagerTarget();
281        attachTabToContentView(tab);
282        if (web != null) {
283            // Request focus on the top window.
284            if (mUseQuickControls) {
285                mPieControl.forceToTop(mContentView);
286                web.setTitleBar(null);
287                mTitleBar.hide();
288            } else {
289                web.setTitleBar(mTitleBar);
290                mTitleBar.onScrollChanged();
291            }
292        }
293        mTitleBar.bringToFront();
294        tab.getTopWindow().requestFocus();
295        setShouldShowErrorConsole(tab, mUiController.shouldShowErrorConsole());
296        onTabDataChanged(tab);
297        onProgressChanged(tab);
298        mNavigationBar.setIncognitoMode(tab.isPrivateBrowsingEnabled());
299        updateAutoLogin(tab, false);
300        mBlockFocusAnimations = false;
301    }
302
303    protected void updateUrlBarAutoShowManagerTarget() {
304        WebView web = mActiveTab != null ? mActiveTab.getWebView() : null;
305        if (!mUseQuickControls && web instanceof BrowserWebView) {
306            mUrlBarAutoShowManager.setTarget((BrowserWebView) web);
307        } else {
308            mUrlBarAutoShowManager.setTarget(null);
309        }
310    }
311
312    Tab getActiveTab() {
313        return mActiveTab;
314    }
315
316    @Override
317    public void updateTabs(List<Tab> tabs) {
318    }
319
320    @Override
321    public void removeTab(Tab tab) {
322        if (mActiveTab == tab) {
323            removeTabFromContentView(tab);
324            mActiveTab = null;
325        }
326    }
327
328    @Override
329    public void detachTab(Tab tab) {
330        removeTabFromContentView(tab);
331    }
332
333    @Override
334    public void attachTab(Tab tab) {
335        attachTabToContentView(tab);
336    }
337
338    protected void attachTabToContentView(Tab tab) {
339        if ((tab == null) || (tab.getWebView() == null)) {
340            return;
341        }
342        View container = tab.getViewContainer();
343        WebView mainView  = tab.getWebView();
344        // Attach the WebView to the container and then attach the
345        // container to the content view.
346        FrameLayout wrapper =
347                (FrameLayout) container.findViewById(R.id.webview_wrapper);
348        ViewGroup parent = (ViewGroup) mainView.getParent();
349        if (parent != wrapper) {
350            if (parent != null) {
351                parent.removeView(mainView);
352            }
353            wrapper.addView(mainView);
354        }
355        parent = (ViewGroup) container.getParent();
356        if (parent != mContentView) {
357            if (parent != null) {
358                parent.removeView(container);
359            }
360            mContentView.addView(container, COVER_SCREEN_PARAMS);
361        }
362        mUiController.attachSubWindow(tab);
363    }
364
365    private void removeTabFromContentView(Tab tab) {
366        hideTitleBar();
367        // Remove the container that contains the main WebView.
368        WebView mainView = tab.getWebView();
369        View container = tab.getViewContainer();
370        if (mainView == null) {
371            return;
372        }
373        // Remove the container from the content and then remove the
374        // WebView from the container. This will trigger a focus change
375        // needed by WebView.
376        FrameLayout wrapper =
377                (FrameLayout) container.findViewById(R.id.webview_wrapper);
378        wrapper.removeView(mainView);
379        mContentView.removeView(container);
380        mUiController.endActionMode();
381        mUiController.removeSubWindow(tab);
382        ErrorConsoleView errorConsole = tab.getErrorConsole(false);
383        if (errorConsole != null) {
384            mErrorConsoleContainer.removeView(errorConsole);
385        }
386    }
387
388    @Override
389    public void onSetWebView(Tab tab, WebView webView) {
390        View container = tab.getViewContainer();
391        if (container == null) {
392            // The tab consists of a container view, which contains the main
393            // WebView, as well as any other UI elements associated with the tab.
394            container = mActivity.getLayoutInflater().inflate(R.layout.tab,
395                    mContentView, false);
396            tab.setViewContainer(container);
397        }
398        if (tab.getWebView() != webView) {
399            // Just remove the old one.
400            FrameLayout wrapper =
401                    (FrameLayout) container.findViewById(R.id.webview_wrapper);
402            wrapper.removeView(tab.getWebView());
403        }
404    }
405
406    /**
407     * create a sub window container and webview for the tab
408     * Note: this methods operates through side-effects for now
409     * it sets both the subView and subViewContainer for the given tab
410     * @param tab tab to create the sub window for
411     * @param subView webview to be set as a subwindow for the tab
412     */
413    @Override
414    public void createSubWindow(Tab tab, WebView subView) {
415        View subViewContainer = mActivity.getLayoutInflater().inflate(
416                R.layout.browser_subwindow, null);
417        ViewGroup inner = (ViewGroup) subViewContainer
418                .findViewById(R.id.inner_container);
419        inner.addView(subView, new LayoutParams(LayoutParams.MATCH_PARENT,
420                LayoutParams.MATCH_PARENT));
421        final ImageButton cancel = (ImageButton) subViewContainer
422                .findViewById(R.id.subwindow_close);
423        final WebView cancelSubView = subView;
424        cancel.setOnClickListener(new OnClickListener() {
425            @Override
426            public void onClick(View v) {
427                ((BrowserWebView) cancelSubView).getWebChromeClient().onCloseWindow(cancelSubView);
428            }
429        });
430        tab.setSubWebView(subView);
431        tab.setSubViewContainer(subViewContainer);
432    }
433
434    /**
435     * Remove the sub window from the content view.
436     */
437    @Override
438    public void removeSubWindow(View subviewContainer) {
439        mContentView.removeView(subviewContainer);
440        mUiController.endActionMode();
441    }
442
443    /**
444     * Attach the sub window to the content view.
445     */
446    @Override
447    public void attachSubWindow(View container) {
448        if (container.getParent() != null) {
449            // already attached, remove first
450            ((ViewGroup) container.getParent()).removeView(container);
451        }
452        mContentView.addView(container, COVER_SCREEN_PARAMS);
453    }
454
455    protected void refreshWebView() {
456        WebView web = getWebView();
457        if (web != null) {
458            web.invalidate();
459        }
460    }
461
462    public void editUrl(boolean clearInput, boolean forceIME) {
463        if (mUiController.isInCustomActionMode()) {
464            mUiController.endActionMode();
465        }
466        showTitleBar();
467        if ((getActiveTab() != null) && !getActiveTab().isSnapshot()) {
468            mNavigationBar.startEditingUrl(clearInput, forceIME);
469        }
470    }
471
472    boolean canShowTitleBar() {
473        return !isTitleBarShowing()
474                && !isActivityPaused()
475                && (getActiveTab() != null)
476                && (getWebView() != null)
477                && !mUiController.isInCustomActionMode();
478    }
479
480    protected void showTitleBar() {
481        mHandler.removeMessages(MSG_HIDE_TITLEBAR);
482        if (canShowTitleBar()) {
483            mTitleBar.show();
484        }
485    }
486
487    protected void hideTitleBar() {
488        if (mTitleBar.isShowing()) {
489            mTitleBar.hide();
490        }
491    }
492
493    protected boolean isTitleBarShowing() {
494        return mTitleBar.isShowing();
495    }
496
497    public boolean isEditingUrl() {
498        return mTitleBar.isEditingUrl();
499    }
500
501    public void stopEditingUrl() {
502        mTitleBar.getNavigationBar().stopEditingUrl();
503    }
504
505    public TitleBar getTitleBar() {
506        return mTitleBar;
507    }
508
509    @Override
510    public void showComboView(ComboViews startingView, Bundle extras) {
511        Intent intent = new Intent(mActivity, ComboViewActivity.class);
512        intent.putExtra(ComboViewActivity.EXTRA_INITIAL_VIEW, startingView.name());
513        intent.putExtra(ComboViewActivity.EXTRA_COMBO_ARGS, extras);
514        Tab t = getActiveTab();
515        if (t != null) {
516            intent.putExtra(ComboViewActivity.EXTRA_CURRENT_URL, t.getUrl());
517        }
518        mActivity.startActivityForResult(intent, Controller.COMBO_VIEW);
519    }
520
521    @Override
522    public void showCustomView(View view, int requestedOrientation,
523            WebChromeClient.CustomViewCallback callback) {
524        // if a view already exists then immediately terminate the new one
525        if (mCustomView != null) {
526            callback.onCustomViewHidden();
527            return;
528        }
529
530        mOriginalOrientation = mActivity.getRequestedOrientation();
531        FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
532        mFullscreenContainer = new FullscreenHolder(mActivity);
533        mFullscreenContainer.addView(view, COVER_SCREEN_PARAMS);
534        decor.addView(mFullscreenContainer, COVER_SCREEN_PARAMS);
535        mCustomView = view;
536        setFullscreen(true);
537        ((BrowserWebView) getWebView()).setVisibility(View.INVISIBLE);
538        mCustomViewCallback = callback;
539        mActivity.setRequestedOrientation(requestedOrientation);
540    }
541
542    @Override
543    public void onHideCustomView() {
544        ((BrowserWebView) getWebView()).setVisibility(View.VISIBLE);
545        if (mCustomView == null)
546            return;
547        setFullscreen(false);
548        FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
549        decor.removeView(mFullscreenContainer);
550        mFullscreenContainer = null;
551        mCustomView = null;
552        mCustomViewCallback.onCustomViewHidden();
553        // Show the content view.
554        mActivity.setRequestedOrientation(mOriginalOrientation);
555    }
556
557    @Override
558    public boolean isCustomViewShowing() {
559        return mCustomView != null;
560    }
561
562    protected void dismissIME() {
563        if (mInputManager.isActive()) {
564            mInputManager.hideSoftInputFromWindow(mContentView.getWindowToken(),
565                    0);
566        }
567    }
568
569    @Override
570    public boolean isWebShowing() {
571        return mCustomView == null;
572    }
573
574    @Override
575    public void showAutoLogin(Tab tab) {
576        updateAutoLogin(tab, true);
577    }
578
579    @Override
580    public void hideAutoLogin(Tab tab) {
581        updateAutoLogin(tab, true);
582    }
583
584    // -------------------------------------------------------------------------
585
586    protected void updateNavigationState(Tab tab) {
587    }
588
589    protected void updateAutoLogin(Tab tab, boolean animate) {
590        mTitleBar.updateAutoLogin(tab, animate);
591    }
592
593    /**
594     * Update the lock icon to correspond to our latest state.
595     */
596    protected void updateLockIconToLatest(Tab t) {
597        if (t != null && t.inForeground()) {
598            updateLockIconImage(t.getSecurityState());
599        }
600    }
601
602    /**
603     * Updates the lock-icon image in the title-bar.
604     */
605    private void updateLockIconImage(SecurityState securityState) {
606        Drawable d = null;
607        if (securityState == SecurityState.SECURITY_STATE_SECURE) {
608            d = mLockIconSecure;
609        } else if (securityState == SecurityState.SECURITY_STATE_MIXED
610                || securityState == SecurityState.SECURITY_STATE_BAD_CERTIFICATE) {
611            // TODO: It would be good to have different icons for insecure vs mixed content.
612            // See http://b/5403800
613            d = mLockIconMixed;
614        }
615        mNavigationBar.setLock(d);
616    }
617
618    protected void setUrlTitle(Tab tab) {
619        String url = tab.getUrl();
620        String title = tab.getTitle();
621        if (TextUtils.isEmpty(title)) {
622            title = url;
623        }
624        if (tab.inForeground()) {
625            mNavigationBar.setDisplayTitle(url);
626        }
627    }
628
629    // Set the favicon in the title bar.
630    protected void setFavicon(Tab tab) {
631        if (tab.inForeground()) {
632            Bitmap icon = tab.getFavicon();
633            mNavigationBar.setFavicon(icon);
634        }
635    }
636
637    @Override
638    public void onActionModeFinished(boolean inLoad) {
639    }
640
641    // active tabs page
642
643    public void showActiveTabsPage() {
644    }
645
646    /**
647     * Remove the active tabs page.
648     */
649    public void removeActiveTabsPage() {
650    }
651
652    // menu handling callbacks
653
654    @Override
655    public boolean onPrepareOptionsMenu(Menu menu) {
656        return true;
657    }
658
659    @Override
660    public void updateMenuState(Tab tab, Menu menu) {
661    }
662
663    @Override
664    public void onOptionsMenuOpened() {
665    }
666
667    @Override
668    public void onExtendedMenuOpened() {
669    }
670
671    @Override
672    public boolean onOptionsItemSelected(MenuItem item) {
673        return false;
674    }
675
676    @Override
677    public void onOptionsMenuClosed(boolean inLoad) {
678    }
679
680    @Override
681    public void onExtendedMenuClosed(boolean inLoad) {
682    }
683
684    @Override
685    public void onContextMenuCreated(Menu menu) {
686    }
687
688    @Override
689    public void onContextMenuClosed(Menu menu, boolean inLoad) {
690    }
691
692    // error console
693
694    @Override
695    public void setShouldShowErrorConsole(Tab tab, boolean flag) {
696        if (tab == null) return;
697        ErrorConsoleView errorConsole = tab.getErrorConsole(true);
698        if (flag) {
699            // Setting the show state of the console will cause it's the layout
700            // to be inflated.
701            if (errorConsole.numberOfErrors() > 0) {
702                errorConsole.showConsole(ErrorConsoleView.SHOW_MINIMIZED);
703            } else {
704                errorConsole.showConsole(ErrorConsoleView.SHOW_NONE);
705            }
706            if (errorConsole.getParent() != null) {
707                mErrorConsoleContainer.removeView(errorConsole);
708            }
709            // Now we can add it to the main view.
710            mErrorConsoleContainer.addView(errorConsole,
711                    new LinearLayout.LayoutParams(
712                            ViewGroup.LayoutParams.MATCH_PARENT,
713                            ViewGroup.LayoutParams.WRAP_CONTENT));
714        } else {
715            mErrorConsoleContainer.removeView(errorConsole);
716        }
717    }
718
719    // -------------------------------------------------------------------------
720    // Helper function for WebChromeClient
721    // -------------------------------------------------------------------------
722
723    @Override
724    public Bitmap getDefaultVideoPoster() {
725        if (mDefaultVideoPoster == null) {
726            mDefaultVideoPoster = BitmapFactory.decodeResource(
727                    mActivity.getResources(), R.drawable.default_video_poster);
728        }
729        return mDefaultVideoPoster;
730    }
731
732    @Override
733    public View getVideoLoadingProgressView() {
734        if (mVideoProgressView == null) {
735            LayoutInflater inflater = LayoutInflater.from(mActivity);
736            mVideoProgressView = inflater.inflate(
737                    R.layout.video_loading_progress, null);
738        }
739        return mVideoProgressView;
740    }
741
742    @Override
743    public void showMaxTabsWarning() {
744        Toast warning = Toast.makeText(mActivity,
745                mActivity.getString(R.string.max_tabs_warning),
746                Toast.LENGTH_SHORT);
747        warning.show();
748    }
749
750    protected WebView getWebView() {
751        if (mActiveTab != null) {
752            return mActiveTab.getWebView();
753        } else {
754            return null;
755        }
756    }
757
758    protected Menu getMenu() {
759        MenuBuilder menu = new MenuBuilder(mActivity);
760        mActivity.getMenuInflater().inflate(R.menu.browser, menu);
761        return menu;
762    }
763
764    public void setFullscreen(boolean enabled) {
765        Window win = mActivity.getWindow();
766        WindowManager.LayoutParams winParams = win.getAttributes();
767        final int bits = WindowManager.LayoutParams.FLAG_FULLSCREEN;
768        if (enabled) {
769            winParams.flags |=  bits;
770        } else {
771            winParams.flags &= ~bits;
772            if (mCustomView != null) {
773                mCustomView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
774            } else {
775                mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
776            }
777        }
778        win.setAttributes(winParams);
779    }
780
781    public Drawable getFaviconDrawable(Bitmap icon) {
782        Drawable[] array = new Drawable[3];
783        array[0] = new PaintDrawable(Color.BLACK);
784        PaintDrawable p = new PaintDrawable(Color.WHITE);
785        array[1] = p;
786        if (icon == null) {
787            array[2] = mGenericFavicon;
788        } else {
789            array[2] = new BitmapDrawable(icon);
790        }
791        LayerDrawable d = new LayerDrawable(array);
792        d.setLayerInset(1, 1, 1, 1, 1);
793        d.setLayerInset(2, 2, 2, 2, 2);
794        return d;
795    }
796
797    public boolean isLoading() {
798        return mActiveTab != null ? mActiveTab.inPageLoad() : false;
799    }
800
801    /**
802     * Suggest to the UI that the title bar can be hidden. The UI will then
803     * decide whether or not to hide based off a number of factors, such
804     * as if the user is editing the URL bar or if the page is loading
805     */
806    public void suggestHideTitleBar() {
807        if (!isLoading() && !isEditingUrl() && !mTitleBar.wantsToBeVisible()
808                && !mNavigationBar.isMenuShowing()) {
809            hideTitleBar();
810        }
811    }
812
813    protected final void showTitleBarForDuration() {
814        showTitleBarForDuration(HIDE_TITLEBAR_DELAY);
815    }
816
817    protected final void showTitleBarForDuration(long duration) {
818        showTitleBar();
819        Message msg = Message.obtain(mHandler, MSG_HIDE_TITLEBAR);
820        mHandler.sendMessageDelayed(msg, duration);
821    }
822
823    protected Handler mHandler = new Handler() {
824
825        @Override
826        public void handleMessage(Message msg) {
827            if (msg.what == MSG_HIDE_TITLEBAR) {
828                suggestHideTitleBar();
829            }
830            BaseUi.this.handleMessage(msg);
831        }
832    };
833
834    protected void handleMessage(Message msg) {}
835
836    @Override
837    public void showWeb(boolean animate) {
838        mUiController.hideCustomView();
839    }
840
841    static class FullscreenHolder extends FrameLayout {
842
843        public FullscreenHolder(Context ctx) {
844            super(ctx);
845            setBackgroundColor(ctx.getResources().getColor(R.color.black));
846        }
847
848        @Override
849        public boolean onTouchEvent(MotionEvent evt) {
850            return true;
851        }
852
853    }
854
855    public void addFixedTitleBar(View view) {
856        mFixedTitlebarContainer.addView(view);
857    }
858
859    public void setContentViewMarginTop(int margin) {
860        LinearLayout.LayoutParams params =
861                (LinearLayout.LayoutParams) mContentView.getLayoutParams();
862        if (params.topMargin != margin) {
863            params.topMargin = margin;
864            mContentView.setLayoutParams(params);
865        }
866    }
867
868    @Override
869    public boolean blockFocusAnimations() {
870        return mBlockFocusAnimations;
871    }
872
873    @Override
874    public void onVoiceResult(String result) {
875        mNavigationBar.onVoiceResult(result);
876    }
877
878}
879