• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
PhoneUi(Activity browser, UiController controller)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
onDestroy()75     public void onDestroy() {
76         hideTitleBar();
77     }
78 
79     @Override
editUrl(boolean clearInput, boolean forceIME)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
onBackKey()90     public boolean onBackKey() {
91         if (showingNavScreen()) {
92             mNavScreen.close(mUiController.getTabControl().getCurrentPosition());
93             return true;
94         }
95         return super.onBackKey();
96     }
97 
showingNavScreen()98     private boolean showingNavScreen() {
99         return mNavScreen != null && mNavScreen.getVisibility() == View.VISIBLE;
100     }
101 
102     @Override
dispatchKey(int code, KeyEvent event)103     public boolean dispatchKey(int code, KeyEvent event) {
104         return false;
105     }
106 
107     @Override
onProgressChanged(Tab tab)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
handleMessage(Message msg)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
setActiveTab(final Tab tab)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
onPrepareOptionsMenu(Menu menu)167     public boolean onPrepareOptionsMenu(Menu menu) {
168         updateMenuState(mActiveTab, menu);
169         return true;
170     }
171 
172     @Override
updateMenuState(Tab tab, Menu menu)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
onOptionsItemSelected(MenuItem item)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
onContextMenuCreated(Menu menu)221     public void onContextMenuCreated(Menu menu) {
222         hideTitleBar();
223     }
224 
225     @Override
onContextMenuClosed(Menu menu, boolean inLoad)226     public void onContextMenuClosed(Menu menu, boolean inLoad) {
227         if (inLoad) {
228             showTitleBar();
229         }
230     }
231 
232     // action mode callbacks
233 
234     @Override
onActionModeStarted(ActionMode mode)235     public void onActionModeStarted(ActionMode mode) {
236         if (!isEditingUrl()) {
237             hideTitleBar();
238         } else {
239             mTitleBar.animate().translationY(mActionBarHeight);
240         }
241     }
242 
243     @Override
onActionModeFinished(boolean inLoad)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
isWebShowing()255     public boolean isWebShowing() {
256         return super.isWebShowing() && !showingNavScreen();
257     }
258 
259     @Override
showWeb(boolean animate)260     public void showWeb(boolean animate) {
261         super.showWeb(animate);
262         hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate);
263     }
264 
showNavScreen()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 
finishAnimationIn()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 
hideNavScreen(int position, boolean animate)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 
finishAnimateOut()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
needsRestoreAllTabs()442     public boolean needsRestoreAllTabs() {
443         return false;
444     }
445 
toggleNavScreen()446     public void toggleNavScreen() {
447         if (!showingNavScreen()) {
448             showNavScreen();
449         } else {
450             hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false);
451         }
452     }
453 
454     @Override
shouldCaptureThumbnails()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 
AnimScreen(Context ctx)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 
set(TitleBar tbar, WebView web)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 
safeCreateBitmap(int width, int height)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 
set(Bitmap image)526         public void set(Bitmap image) {
527             mTitle.setVisibility(View.GONE);
528             mContent.setImageBitmap(image);
529         }
530 
setScaleFactor(float sf)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 
getScaleFactor()538         private float getScaleFactor() {
539             return mScale;
540         }
541 
542     }
543 
544 }
545