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