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