Home | History | Annotate | Download | only in browser
      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 
     17 package com.android.browser;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.AnimatorSet;
     22 import android.animation.ObjectAnimator;
     23 import android.app.Activity;
     24 import android.content.Context;
     25 import android.graphics.Bitmap;
     26 import android.graphics.Canvas;
     27 import android.graphics.Matrix;
     28 import android.os.Message;
     29 import android.util.Log;
     30 import android.util.TypedValue;
     31 import android.view.ActionMode;
     32 import android.view.KeyEvent;
     33 import android.view.LayoutInflater;
     34 import android.view.Menu;
     35 import android.view.MenuItem;
     36 import android.view.View;
     37 import android.view.accessibility.AccessibilityEvent;
     38 import android.webkit.WebView;
     39 import android.widget.ImageView;
     40 
     41 import com.android.browser.UrlInputView.StateListener;
     42 
     43 /**
     44  * Ui for regular phone screen sizes
     45  */
     46 public class PhoneUi extends BaseUi {
     47 
     48     private static final String LOGTAG = "PhoneUi";
     49     private static final int MSG_INIT_NAVSCREEN = 100;
     50 
     51     private NavScreen mNavScreen;
     52     private AnimScreen mAnimScreen;
     53     private NavigationBarPhone mNavigationBar;
     54     private int mActionBarHeight;
     55 
     56     boolean mAnimating;
     57     boolean mShowNav = false;
     58 
     59     /**
     60      * @param browser
     61      * @param controller
     62      */
     63     public PhoneUi(Activity browser, UiController controller) {
     64         super(browser, controller);
     65         setUseQuickControls(BrowserSettings.getInstance().useQuickControls());
     66         mNavigationBar = (NavigationBarPhone) mTitleBar.getNavigationBar();
     67         TypedValue heightValue = new TypedValue();
     68         browser.getTheme().resolveAttribute(
     69                 com.android.internal.R.attr.actionBarSize, heightValue, true);
     70         mActionBarHeight = TypedValue.complexToDimensionPixelSize(heightValue.data,
     71                 browser.getResources().getDisplayMetrics());
     72     }
     73 
     74     @Override
     75     public void onDestroy() {
     76         hideTitleBar();
     77     }
     78 
     79     @Override
     80     public void editUrl(boolean clearInput, boolean forceIME) {
     81         if (mUseQuickControls) {
     82             mTitleBar.setShowProgressOnly(false);
     83         }
     84         //Do nothing while at Nav show screen.
     85         if (mShowNav) return;
     86         super.editUrl(clearInput, forceIME);
     87     }
     88 
     89     @Override
     90     public boolean onBackKey() {
     91         if (showingNavScreen()) {
     92             mNavScreen.close(mUiController.getTabControl().getCurrentPosition());
     93             return true;
     94         }
     95         return super.onBackKey();
     96     }
     97 
     98     private boolean showingNavScreen() {
     99         return mNavScreen != null && mNavScreen.getVisibility() == View.VISIBLE;
    100     }
    101 
    102     @Override
    103     public boolean dispatchKey(int code, KeyEvent event) {
    104         return false;
    105     }
    106 
    107     @Override
    108     public void onProgressChanged(Tab tab) {
    109         super.onProgressChanged(tab);
    110         if (mNavScreen == null && getTitleBar().getHeight() > 0) {
    111             mHandler.sendEmptyMessage(MSG_INIT_NAVSCREEN);
    112         }
    113     }
    114 
    115     @Override
    116     protected void handleMessage(Message msg) {
    117         super.handleMessage(msg);
    118         if (msg.what == MSG_INIT_NAVSCREEN) {
    119             if (mNavScreen == null) {
    120                 mNavScreen = new NavScreen(mActivity, mUiController, this);
    121                 mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS);
    122                 mNavScreen.setVisibility(View.GONE);
    123             }
    124             if (mAnimScreen == null) {
    125                 mAnimScreen = new AnimScreen(mActivity);
    126                 // initialize bitmaps
    127                 mAnimScreen.set(getTitleBar(), getWebView());
    128             }
    129         }
    130     }
    131 
    132     @Override
    133     public void setActiveTab(final Tab tab) {
    134         mTitleBar.cancelTitleBarAnimation(true);
    135         mTitleBar.setSkipTitleBarAnimations(true);
    136         super.setActiveTab(tab);
    137 
    138         //if at Nav screen show, detach tab like what showNavScreen() do.
    139         if (mShowNav) {
    140             detachTab(mActiveTab);
    141         }
    142 
    143         BrowserWebView view = (BrowserWebView) tab.getWebView();
    144         // TabControl.setCurrentTab has been called before this,
    145         // so the tab is guaranteed to have a webview
    146         if (view == null) {
    147             Log.e(LOGTAG, "active tab with no webview detected");
    148             return;
    149         }
    150         // Request focus on the top window.
    151         if (mUseQuickControls) {
    152             mPieControl.forceToTop(mContentView);
    153             view.setTitleBar(null);
    154             mTitleBar.setShowProgressOnly(true);
    155         } else {
    156             view.setTitleBar(mTitleBar);
    157         }
    158         // update nav bar state
    159         mNavigationBar.onStateChanged(StateListener.STATE_NORMAL);
    160         updateLockIconToLatest(tab);
    161         mTitleBar.setSkipTitleBarAnimations(false);
    162     }
    163 
    164     // menu handling callbacks
    165 
    166     @Override
    167     public boolean onPrepareOptionsMenu(Menu menu) {
    168         updateMenuState(mActiveTab, menu);
    169         return true;
    170     }
    171 
    172     @Override
    173     public void updateMenuState(Tab tab, Menu menu) {
    174         MenuItem bm = menu.findItem(R.id.bookmarks_menu_id);
    175         if (bm != null) {
    176             bm.setVisible(!showingNavScreen());
    177         }
    178         MenuItem abm = menu.findItem(R.id.add_bookmark_menu_id);
    179         if (abm != null) {
    180             abm.setVisible((tab != null) && !tab.isSnapshot() && !showingNavScreen());
    181         }
    182         MenuItem info = menu.findItem(R.id.page_info_menu_id);
    183         if (info != null) {
    184             info.setVisible(false);
    185         }
    186         MenuItem newtab = menu.findItem(R.id.new_tab_menu_id);
    187         if (newtab != null && !mUseQuickControls) {
    188             newtab.setVisible(false);
    189         }
    190         MenuItem incognito = menu.findItem(R.id.incognito_menu_id);
    191         if (incognito != null) {
    192             incognito.setVisible(showingNavScreen() || mUseQuickControls);
    193         }
    194         MenuItem closeOthers = menu.findItem(R.id.close_other_tabs_id);
    195         if (closeOthers != null) {
    196             boolean isLastTab = true;
    197             if (tab != null) {
    198                 isLastTab = (mTabControl.getTabCount() <= 1);
    199             }
    200             closeOthers.setEnabled(!isLastTab);
    201         }
    202         if (showingNavScreen()) {
    203             menu.setGroupVisible(R.id.LIVE_MENU, false);
    204             menu.setGroupVisible(R.id.SNAPSHOT_MENU, false);
    205             menu.setGroupVisible(R.id.NAV_MENU, false);
    206             menu.setGroupVisible(R.id.COMBO_MENU, true);
    207         }
    208     }
    209 
    210     @Override
    211     public boolean onOptionsItemSelected(MenuItem item) {
    212         if (showingNavScreen()
    213                 && (item.getItemId() != R.id.history_menu_id)
    214                 && (item.getItemId() != R.id.snapshots_menu_id)) {
    215             hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false);
    216         }
    217         return false;
    218     }
    219 
    220     @Override
    221     public void onContextMenuCreated(Menu menu) {
    222         hideTitleBar();
    223     }
    224 
    225     @Override
    226     public void onContextMenuClosed(Menu menu, boolean inLoad) {
    227         if (inLoad) {
    228             showTitleBar();
    229         }
    230     }
    231 
    232     // action mode callbacks
    233 
    234     @Override
    235     public void onActionModeStarted(ActionMode mode) {
    236         if (!isEditingUrl()) {
    237             hideTitleBar();
    238         } else {
    239             mTitleBar.animate().translationY(mActionBarHeight);
    240         }
    241     }
    242 
    243     @Override
    244     public void onActionModeFinished(boolean inLoad) {
    245         mTitleBar.animate().translationY(0);
    246         if (inLoad) {
    247             if (mUseQuickControls) {
    248                 mTitleBar.setShowProgressOnly(true);
    249             }
    250             showTitleBar();
    251         }
    252     }
    253 
    254     @Override
    255     public boolean isWebShowing() {
    256         return super.isWebShowing() && !showingNavScreen();
    257     }
    258 
    259     @Override
    260     public void showWeb(boolean animate) {
    261         super.showWeb(animate);
    262         hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate);
    263     }
    264 
    265     void showNavScreen() {
    266         mShowNav = true;
    267         mUiController.setBlockEvents(true);
    268         if (mNavScreen == null) {
    269             mNavScreen = new NavScreen(mActivity, mUiController, this);
    270             mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS);
    271         } else {
    272             mNavScreen.setVisibility(View.VISIBLE);
    273             mNavScreen.setAlpha(1f);
    274             mNavScreen.refreshAdapter();
    275         }
    276         mActiveTab.capture();
    277         if (mAnimScreen == null) {
    278             mAnimScreen = new AnimScreen(mActivity);
    279         } else {
    280             mAnimScreen.mMain.setAlpha(1f);
    281             mAnimScreen.mTitle.setAlpha(1f);
    282             mAnimScreen.setScaleFactor(1f);
    283         }
    284         mAnimScreen.set(getTitleBar(), getWebView());
    285         if (mAnimScreen.mMain.getParent() == null) {
    286             mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
    287         }
    288         mCustomViewContainer.setVisibility(View.VISIBLE);
    289         mCustomViewContainer.bringToFront();
    290         mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
    291                 mContentView.getHeight());
    292         int fromLeft = 0;
    293         int fromTop = getTitleBar().getHeight();
    294         int fromRight = mContentView.getWidth();
    295         int fromBottom = mContentView.getHeight();
    296         int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width);
    297         int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height);
    298         int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight);
    299         int toLeft = (mContentView.getWidth() - width) / 2;
    300         int toTop = ((fromBottom - (ntth + height)) / 2 + ntth);
    301         int toRight = toLeft + width;
    302         int toBottom = toTop + height;
    303         float scaleFactor = width / (float) mContentView.getWidth();
    304         detachTab(mActiveTab);
    305         mContentView.setVisibility(View.GONE);
    306         AnimatorSet set1 = new AnimatorSet();
    307         AnimatorSet inanim = new AnimatorSet();
    308         ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left",
    309                 fromLeft, toLeft);
    310         ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top",
    311                 fromTop, toTop);
    312         ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right",
    313                 fromRight, toRight);
    314         ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom",
    315                 fromBottom, toBottom);
    316         ObjectAnimator title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha",
    317                 1f, 0f);
    318         ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
    319                 1f, scaleFactor);
    320         ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain,
    321                 "alpha", 1f, 0f);
    322         blend1.setDuration(100);
    323 
    324         inanim.playTogether(tx, ty, tr, tb, sx, title);
    325         inanim.setDuration(200);
    326         set1.addListener(new AnimatorListenerAdapter() {
    327             @Override
    328             public void onAnimationEnd(Animator anim) {
    329                 mCustomViewContainer.removeView(mAnimScreen.mMain);
    330                 finishAnimationIn();
    331                 mUiController.setBlockEvents(false);
    332             }
    333         });
    334         set1.playSequentially(inanim, blend1);
    335         set1.start();
    336     }
    337 
    338     private void finishAnimationIn() {
    339         if (showingNavScreen()) {
    340             // notify accessibility manager about the screen change
    341             mNavScreen.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    342             mTabControl.setOnThumbnailUpdatedListener(mNavScreen);
    343         }
    344     }
    345 
    346     void hideNavScreen(int position, boolean animate) {
    347         mShowNav = false;
    348         if (!showingNavScreen()) return;
    349         final Tab tab = mUiController.getTabControl().getTab(position);
    350         if ((tab == null) || !animate) {
    351             if (tab != null) {
    352                 setActiveTab(tab);
    353             } else if (mTabControl.getTabCount() > 0) {
    354                 // use a fallback tab
    355                 setActiveTab(mTabControl.getCurrentTab());
    356             }
    357             mContentView.setVisibility(View.VISIBLE);
    358             finishAnimateOut();
    359             return;
    360         }
    361         NavTabView tabview = (NavTabView) mNavScreen.getTabView(position);
    362         if (tabview == null) {
    363             if (mTabControl.getTabCount() > 0) {
    364                 // use a fallback tab
    365                 setActiveTab(mTabControl.getCurrentTab());
    366             }
    367             mContentView.setVisibility(View.VISIBLE);
    368             finishAnimateOut();
    369             return;
    370         }
    371         mUiController.setBlockEvents(true);
    372         mUiController.setActiveTab(tab);
    373         mContentView.setVisibility(View.VISIBLE);
    374         if (mAnimScreen == null) {
    375             mAnimScreen = new AnimScreen(mActivity);
    376         }
    377         mAnimScreen.set(tab.getScreenshot());
    378         if (mAnimScreen.mMain.getParent() == null) {
    379             mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
    380         }
    381         mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
    382                 mContentView.getHeight());
    383         mNavScreen.mScroller.finishScroller();
    384         ImageView target = tabview.mImage;
    385         int toLeft = 0;
    386         int toTop = (tab.getWebView() != null) ? tab.getWebView().getVisibleTitleHeight() : 0;
    387         int toRight = mContentView.getWidth();
    388         int width = target.getDrawable().getIntrinsicWidth();
    389         int height = target.getDrawable().getIntrinsicHeight();
    390         int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.mScroller.getScrollX();
    391         int fromTop = tabview.getTop() + target.getTop() - mNavScreen.mScroller.getScrollY();
    392         int fromRight = fromLeft + width;
    393         int fromBottom = fromTop + height;
    394         float scaleFactor = mContentView.getWidth() / (float) width;
    395         int toBottom = toTop + (int) (height * scaleFactor);
    396         mAnimScreen.mContent.setLeft(fromLeft);
    397         mAnimScreen.mContent.setTop(fromTop);
    398         mAnimScreen.mContent.setRight(fromRight);
    399         mAnimScreen.mContent.setBottom(fromBottom);
    400         mAnimScreen.setScaleFactor(1f);
    401         AnimatorSet set1 = new AnimatorSet();
    402         ObjectAnimator fade2 = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f);
    403         ObjectAnimator fade1 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f);
    404         set1.playTogether(fade1, fade2);
    405         set1.setDuration(100);
    406         AnimatorSet set2 = new AnimatorSet();
    407         ObjectAnimator l = ObjectAnimator.ofInt(mAnimScreen.mContent, "left",
    408                 fromLeft, toLeft);
    409         ObjectAnimator t = ObjectAnimator.ofInt(mAnimScreen.mContent, "top",
    410                 fromTop, toTop);
    411         ObjectAnimator r = ObjectAnimator.ofInt(mAnimScreen.mContent, "right",
    412                 fromRight, toRight);
    413         ObjectAnimator b = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom",
    414                 fromBottom, toBottom);
    415         ObjectAnimator scale = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
    416                 1f, scaleFactor);
    417         ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f);
    418         otheralpha.setDuration(100);
    419         set2.playTogether(l, t, r, b, scale);
    420         set2.setDuration(200);
    421         AnimatorSet combo = new AnimatorSet();
    422         combo.playSequentially(set1, set2, otheralpha);
    423         combo.addListener(new AnimatorListenerAdapter() {
    424             @Override
    425             public void onAnimationEnd(Animator anim) {
    426                 mCustomViewContainer.removeView(mAnimScreen.mMain);
    427                 finishAnimateOut();
    428                 mUiController.setBlockEvents(false);
    429             }
    430         });
    431         combo.start();
    432     }
    433 
    434     private void finishAnimateOut() {
    435         mTabControl.setOnThumbnailUpdatedListener(null);
    436         mNavScreen.setVisibility(View.GONE);
    437         mCustomViewContainer.setAlpha(1f);
    438         mCustomViewContainer.setVisibility(View.GONE);
    439     }
    440 
    441     @Override
    442     public boolean needsRestoreAllTabs() {
    443         return false;
    444     }
    445 
    446     public void toggleNavScreen() {
    447         if (!showingNavScreen()) {
    448             showNavScreen();
    449         } else {
    450             hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false);
    451         }
    452     }
    453 
    454     @Override
    455     public boolean shouldCaptureThumbnails() {
    456         return true;
    457     }
    458 
    459     static class AnimScreen {
    460 
    461         private View mMain;
    462         private ImageView mTitle;
    463         private ImageView mContent;
    464         private float mScale;
    465         private Bitmap mTitleBarBitmap;
    466         private Bitmap mContentBitmap;
    467 
    468         public AnimScreen(Context ctx) {
    469             mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen,
    470                     null);
    471             mTitle = (ImageView) mMain.findViewById(R.id.title);
    472             mContent = (ImageView) mMain.findViewById(R.id.content);
    473             mContent.setScaleType(ImageView.ScaleType.MATRIX);
    474             mContent.setImageMatrix(new Matrix());
    475             mScale = 1.0f;
    476             setScaleFactor(getScaleFactor());
    477         }
    478 
    479         public void set(TitleBar tbar, WebView web) {
    480             if (tbar == null || web == null) {
    481                 return;
    482             }
    483             if (tbar.getWidth() > 0 && tbar.getEmbeddedHeight() > 0) {
    484                 if (mTitleBarBitmap == null
    485                         || mTitleBarBitmap.getWidth() != tbar.getWidth()
    486                         || mTitleBarBitmap.getHeight() != tbar.getEmbeddedHeight()) {
    487                     mTitleBarBitmap = safeCreateBitmap(tbar.getWidth(),
    488                             tbar.getEmbeddedHeight());
    489                 }
    490                 if (mTitleBarBitmap != null) {
    491                     Canvas c = new Canvas(mTitleBarBitmap);
    492                     tbar.draw(c);
    493                     c.setBitmap(null);
    494                 }
    495             } else {
    496                 mTitleBarBitmap = null;
    497             }
    498             mTitle.setImageBitmap(mTitleBarBitmap);
    499             mTitle.setVisibility(View.VISIBLE);
    500             int h = web.getHeight() - tbar.getEmbeddedHeight();
    501             if (mContentBitmap == null
    502                     || mContentBitmap.getWidth() != web.getWidth()
    503                     || mContentBitmap.getHeight() != h) {
    504                 mContentBitmap = safeCreateBitmap(web.getWidth(), h);
    505             }
    506             if (mContentBitmap != null) {
    507                 Canvas c = new Canvas(mContentBitmap);
    508                 int tx = web.getScrollX();
    509                 int ty = web.getScrollY();
    510                 c.translate(-tx, -ty - tbar.getEmbeddedHeight());
    511                 web.draw(c);
    512                 c.setBitmap(null);
    513             }
    514             mContent.setImageBitmap(mContentBitmap);
    515         }
    516 
    517         private Bitmap safeCreateBitmap(int width, int height) {
    518             if (width <= 0 || height <= 0) {
    519                 Log.w(LOGTAG, "safeCreateBitmap failed! width: " + width
    520                         + ", height: " + height);
    521                 return null;
    522             }
    523             return Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    524         }
    525 
    526         public void set(Bitmap image) {
    527             mTitle.setVisibility(View.GONE);
    528             mContent.setImageBitmap(image);
    529         }
    530 
    531         private void setScaleFactor(float sf) {
    532             mScale = sf;
    533             Matrix m = new Matrix();
    534             m.postScale(sf,sf);
    535             mContent.setImageMatrix(m);
    536         }
    537 
    538         private float getScaleFactor() {
    539             return mScale;
    540         }
    541 
    542     }
    543 
    544 }
    545