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