| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.browser; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.animation.AnimatorSet; |
| import android.animation.ObjectAnimator; |
| import android.app.ActionBar; |
| import android.app.Activity; |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.graphics.Matrix; |
| import android.os.Bundle; |
| import android.util.Log; |
| import android.view.ActionMode; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.Menu; |
| import android.view.MenuItem; |
| import android.view.View; |
| import android.view.ViewStub; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.animation.DecelerateInterpolator; |
| |
| import org.codeaurora.swe.WebView; |
| |
| import android.widget.ImageView; |
| |
| import com.android.browser.UrlInputView.StateListener; |
| |
| import org.codeaurora.net.NetworkServices; |
| |
| /** |
| * Ui for regular phone screen sizes |
| */ |
| public class PhoneUi extends BaseUi { |
| |
| private static final String LOGTAG = "PhoneUi"; |
| |
| private NavScreen mNavScreen; |
| private AnimScreen mAnimScreen; |
| private final NavigationBarPhone mNavigationBar; |
| private boolean mNavScreenRequested = false; |
| |
| boolean mShowNav = false; |
| private ComboView mComboView; |
| |
| |
| /** |
| * @param browser |
| * @param controller |
| */ |
| public PhoneUi(Activity browser, UiController controller) { |
| super(browser, controller); |
| mNavigationBar = (NavigationBarPhone) mTitleBar.getNavigationBar(); |
| } |
| |
| @Override |
| public void onDestroy() { |
| hideTitleBar(); |
| // Free the allocated memory for GC to clear it from the heap. |
| mAnimScreen = null; |
| } |
| |
| @Override |
| public void editUrl(boolean clearInput, boolean forceIME) { |
| //Do nothing while at Nav show screen. |
| if (mShowNav) return; |
| super.editUrl(clearInput, forceIME); |
| } |
| |
| @Override |
| public void showComboView(ComboViews startingView, Bundle extras) { |
| |
| if (mComboView == null) { |
| if (mNavScreen != null) { |
| mNavScreen.setVisibility(View.GONE); |
| } |
| ViewStub stub = (ViewStub) mActivity.getWindow(). |
| getDecorView().findViewById(R.id.combo_view_stub); |
| mComboView = (ComboView) stub.inflate(); |
| mComboView.setVisibility(View.GONE); |
| mComboView.setupViews(mActivity); |
| } |
| |
| Bundle b = new Bundle(); |
| b.putString(ComboViewActivity.EXTRA_INITIAL_VIEW, startingView.name()); |
| b.putBundle(ComboViewActivity.EXTRA_COMBO_ARGS, extras); |
| Tab t = getActiveTab(); |
| if (t != null) { |
| b.putString(ComboViewActivity.EXTRA_CURRENT_URL, t.getUrl()); |
| } |
| |
| mComboView.showViews(mActivity, b); |
| } |
| |
| @Override |
| public void hideComboView() { |
| mComboView.hideViews(); |
| } |
| |
| @Override |
| public boolean onBackKey() { |
| if (showingNavScreen()) { |
| mNavScreen.close(mUiController.getTabControl().getCurrentPosition()); |
| return true; |
| } |
| if (isComboViewShowing()) { |
| hideComboView(); |
| return true; |
| } |
| return super.onBackKey(); |
| } |
| |
| private boolean showingNavScreen() { |
| return mNavScreen != null && mNavScreen.getVisibility() == View.VISIBLE; |
| } |
| |
| @Override |
| public boolean dispatchKey(int code, KeyEvent event) { |
| return false; |
| } |
| |
| @Override |
| public void setActiveTab(final Tab tab) { |
| super.setActiveTab(tab); |
| |
| //if at Nav screen show, detach tab like what showNavScreen() do. |
| if (mShowNav) { |
| detachTab(mActiveTab); |
| } |
| |
| BrowserWebView view = (BrowserWebView) tab.getWebView(); |
| // TabControl.setCurrentTab has been called before this, |
| // so the tab is guaranteed to have a webview |
| if (view == null) { |
| Log.e(LOGTAG, "active tab with no webview detected"); |
| return; |
| } |
| // Request focus on the top window. |
| view.setTitleBar(mTitleBar); |
| |
| // update nav bar state |
| mNavigationBar.onStateChanged(StateListener.STATE_NORMAL); |
| } |
| |
| // menu handling callbacks |
| |
| @Override |
| public boolean onPrepareOptionsMenu(Menu menu) { |
| updateMenuState(mActiveTab, menu); |
| return true; |
| } |
| |
| @Override |
| public void updateMenuState(Tab tab, Menu menu) { |
| MenuItem bm = menu.findItem(R.id.bookmarks_menu_id); |
| if (bm != null) { |
| bm.setVisible(!showingNavScreen()); |
| } |
| MenuItem info = menu.findItem(R.id.page_info_menu_id); |
| if (info != null) { |
| info.setVisible(false); |
| } |
| |
| if (showingNavScreen()) { |
| setMenuItemVisibility(menu, R.id.history_menu_id, false); |
| setMenuItemVisibility(menu, R.id.find_menu_id, false); |
| menu.setGroupVisible(R.id.LIVE_MENU, false); |
| setMenuItemVisibility(menu, R.id.save_snapshot_menu_id, false); |
| menu.setGroupVisible(R.id.SNAPSHOT_MENU, false); |
| menu.setGroupVisible(R.id.NAV_MENU, false); |
| } |
| |
| if (isComboViewShowing()) { |
| menu.setGroupVisible(R.id.MAIN_MENU, false); |
| menu.setGroupEnabled(R.id.MAIN_MENU, false); |
| menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false); |
| } |
| |
| } |
| |
| @Override |
| public boolean onOptionsItemSelected(MenuItem item) { |
| if (showingNavScreen() |
| && (item.getItemId() != R.id.history_menu_id) |
| && (item.getItemId() != R.id.snapshots_menu_id)) { |
| hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); |
| } |
| return false; |
| } |
| |
| @Override |
| public void onContextMenuCreated(Menu menu) { |
| hideTitleBar(); |
| } |
| |
| @Override |
| public void onContextMenuClosed(Menu menu, boolean inLoad) { |
| if (inLoad) { |
| showTitleBar(); |
| } |
| } |
| |
| // action mode callbacks |
| |
| @Override |
| public void onActionModeStarted(ActionMode mode) { |
| super.onActionModeStarted(mode); |
| if (!isEditingUrl()) { |
| mTitleBar.setVisibility(View.GONE); |
| } |
| |
| ActionBar actionBar = mActivity.getActionBar(); |
| if (actionBar != null) { |
| actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); |
| actionBar.hide(); |
| } |
| } |
| |
| @Override |
| public void onActionModeFinished(boolean inLoad) { |
| super.onActionModeFinished(inLoad); |
| mTitleBar.setVisibility(View.VISIBLE); |
| } |
| |
| @Override |
| public boolean isWebShowing() { |
| return super.isWebShowing() && !showingNavScreen() && !isComboViewShowing(); |
| } |
| |
| @Override |
| public boolean isComboViewShowing() { |
| return mComboView != null && mComboView.getVisibility() == View.VISIBLE; |
| } |
| |
| @Override |
| public void showWeb(boolean animate) { |
| super.showWeb(animate); |
| hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate); |
| } |
| |
| //Unblock touch events |
| private void unblockEvents() { |
| mUiController.setBlockEvents(false); |
| } |
| //Block touch events |
| private void blockEvents() { |
| mUiController.setBlockEvents(true); |
| } |
| |
| @Override |
| public void cancelNavScreenRequest() { |
| mNavScreenRequested = false; |
| } |
| |
| void showNavScreen() { |
| blockEvents(); |
| mNavScreenRequested = true; |
| mTabControl.setOnThumbnailUpdatedListener( |
| new TabControl.OnThumbnailUpdatedListener() { |
| @Override |
| public void onThumbnailUpdated(Tab t) { |
| mTabControl.setOnThumbnailUpdatedListener(null); |
| |
| // Discard the callback if the req is interrupted |
| if (!mNavScreenRequested) { |
| unblockEvents(); |
| return; |
| } |
| |
| Bitmap bm = t.getScreenshot(); |
| Bitmap sbm; |
| WebView webView = getWebView(); |
| if (webView != null) { |
| int view_width = webView.getWidth(); |
| int capture_width = mActivity.getResources().getDimensionPixelSize( |
| R.dimen.tab_thumbnail_width); |
| |
| float scale = (float) view_width / capture_width; |
| |
| //Upscale the low-res bitmap to the needed size |
| Matrix m = new Matrix(); |
| m.postScale(scale, scale); |
| sbm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), |
| bm.getHeight(), m, false); |
| } else { |
| sbm = bm; |
| } |
| |
| onShowNavScreenContinue(sbm); |
| } |
| }); |
| if (!BrowserSettings.getInstance().isPowerSaveModeEnabled()) { |
| //Notify about anticipated network activity |
| NetworkServices.hintUpcomingUserActivity(); |
| } |
| mActiveTab.capture(); |
| } |
| |
| void onShowNavScreenContinue(Bitmap viewportBitmap) { |
| dismissIME(); |
| mShowNav = true; |
| mNavScreenRequested = false; |
| if (mNavScreen == null) { |
| mNavScreen = new NavScreen(mActivity, mUiController, this); |
| mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS); |
| } else { |
| mNavScreen.setVisibility(View.VISIBLE); |
| mNavScreen.setAlpha(1f); |
| mNavScreen.refreshAdapter(); |
| } |
| if (mAnimScreen == null) { |
| mAnimScreen = new AnimScreen(mActivity); |
| } else { |
| mAnimScreen.mMain.setAlpha(1f); |
| mAnimScreen.setScaleFactor(1f); |
| } |
| mAnimScreen.set(getTitleBar(), viewportBitmap); |
| if (mAnimScreen.mMain.getParent() == null) { |
| mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); |
| } |
| mCustomViewContainer.setVisibility(View.VISIBLE); |
| mCustomViewContainer.bringToFront(); |
| mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), |
| mContentView.getHeight()); |
| int fromLeft = 0; |
| int fromTop = getTitleBar().getHeight(); |
| int fromRight = mContentView.getWidth(); |
| int fromBottom = mContentView.getHeight(); |
| int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width); |
| int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height); |
| int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight); |
| int toLeft = (mContentView.getWidth() - width) / 2; |
| int toTop = ((fromBottom - (ntth + height)) / 2 + ntth); |
| int toRight = toLeft + width; |
| int toBottom = toTop + height; |
| float toScaleFactor = width / (float) mContentView.getWidth(); |
| ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", fromLeft, toLeft); |
| ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", fromTop, toTop); |
| ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", fromRight, toRight); |
| ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", |
| fromBottom, toBottom); |
| ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 1f, toScaleFactor); |
| ObjectAnimator navTabsIn = mNavScreen.createToolbarInAnimator(); |
| mAnimScreen.mContent.layout(fromLeft, fromTop, fromRight, fromBottom); |
| mAnimScreen.setScaleFactor(1f); |
| |
| AnimatorSet inanim = new AnimatorSet(); |
| inanim.playTogether(tx, ty, tr, tb, sx, navTabsIn); |
| inanim.setInterpolator(new DecelerateInterpolator()); |
| inanim.setDuration(200); |
| |
| ObjectAnimator disappear = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 1f, 0f); |
| disappear.setInterpolator(new DecelerateInterpolator()); |
| disappear.setDuration(100); |
| |
| AnimatorSet set1 = new AnimatorSet(); |
| set1.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationStart(Animator animation) { |
| mContentView.setVisibility(View.GONE); |
| } |
| @Override |
| public void onAnimationEnd(Animator anim) { |
| mCustomViewContainer.removeView(mAnimScreen.mMain); |
| finishAnimationIn(); |
| unblockEvents(); |
| } |
| }); |
| set1.playSequentially(inanim, disappear); |
| set1.start(); |
| unblockEvents(); |
| } |
| |
| private void finishAnimationIn() { |
| if (showingNavScreen()) { |
| // notify accessibility manager about the screen change |
| mNavScreen.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
| } |
| } |
| |
| void hideNavScreen(int position, boolean animate) { |
| |
| mShowNav = false; |
| if (!showingNavScreen()) return; |
| final Tab tab = mUiController.getTabControl().getTab(position); |
| if ((tab == null) || !animate) { |
| if (tab != null) { |
| setActiveTab(tab); |
| } else if (mTabControl.getTabCount() > 0) { |
| // use a fallback tab |
| setActiveTab(mTabControl.getCurrentTab()); |
| } |
| mContentView.setVisibility(View.VISIBLE); |
| finishAnimateOut(); |
| return; |
| } |
| NavTabView tabview = (NavTabView) mNavScreen.getTabView(position); |
| if (tabview == null) { |
| if (mTabControl.getTabCount() > 0) { |
| // use a fallback tab |
| setActiveTab(mTabControl.getCurrentTab()); |
| } |
| mContentView.setVisibility(View.VISIBLE); |
| finishAnimateOut(); |
| return; |
| } |
| blockEvents(); |
| mUiController.setActiveTab(tab); |
| mContentView.setVisibility(View.VISIBLE); |
| if (mAnimScreen == null) { |
| mAnimScreen = new AnimScreen(mActivity); |
| } |
| ImageView target = tabview.mImage; |
| int width = target.getDrawable().getIntrinsicWidth(); |
| int height = target.getDrawable().getIntrinsicHeight(); |
| Bitmap bm = tab.getScreenshot(); |
| if (bm == null) |
| bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); |
| mAnimScreen.set(bm); |
| if (mAnimScreen.mMain.getParent() == null) { |
| mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); |
| } |
| mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(), |
| mContentView.getHeight()); |
| mNavScreen.getScroller().finishScroller(); |
| int toLeft = 0; |
| int toTop = mTitleBar.calculateEmbeddedHeight(); |
| int toRight = mContentView.getWidth(); |
| int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.getScroller().getScrollX(); |
| int fromTop = tabview.getTop() + target.getTop() - mNavScreen.getScroller().getScrollY(); |
| int fromRight = fromLeft + width; |
| int fromBottom = fromTop + height; |
| float scaleFactor = mContentView.getWidth() / (float) width; |
| int toBottom = toTop + (int) (height * scaleFactor); |
| mAnimScreen.mContent.setLeft(fromLeft); |
| mAnimScreen.mContent.setTop(fromTop); |
| mAnimScreen.mContent.setRight(fromRight); |
| mAnimScreen.mContent.setBottom(fromBottom); |
| mAnimScreen.setScaleFactor(1f); |
| //ObjectAnimator fade2 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f); |
| //fade2.setDuration(100); |
| AnimatorSet set = new AnimatorSet(); |
| ObjectAnimator animAppear = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f); |
| animAppear.setDuration(100); |
| ObjectAnimator l = ObjectAnimator.ofInt(mAnimScreen.mContent, "left", fromLeft, toLeft); |
| ObjectAnimator t = ObjectAnimator.ofInt(mAnimScreen.mContent, "top", fromTop, toTop); |
| ObjectAnimator r = ObjectAnimator.ofInt(mAnimScreen.mContent, "right", fromRight, toRight); |
| ObjectAnimator b = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom", |
| fromBottom, toBottom); |
| ObjectAnimator scale = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor", 1f, scaleFactor); |
| set.playTogether(animAppear, l, t, r, b, scale); |
| set.setInterpolator(new DecelerateInterpolator()); |
| set.setDuration(200); |
| set.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator anim) { |
| checkTabReady(); |
| } |
| }); |
| set.start(); |
| } |
| |
| |
| private int mNumTries = 0; |
| private void checkTabReady() { |
| boolean isready = true; |
| boolean zeroTries = mNumTries == 0; |
| Tab tab = mUiController.getTabControl().getCurrentTab(); |
| BrowserWebView webview = null; |
| if (tab == null) |
| isready = false; |
| else { |
| webview = (BrowserWebView)tab.getWebView(); |
| if (webview == null) { |
| isready = false; |
| } else { |
| isready = webview.isReady(); |
| } |
| } |
| // Post only when not ready and not crashed |
| if (!isready && mNumTries++ < 150) { |
| mCustomViewContainer.postDelayed(new Runnable() { |
| public void run() { |
| checkTabReady(); |
| } |
| }, 17); //WebView is not ready. check again in for next frame. |
| return; |
| } |
| mNumTries = 0; |
| final boolean hasCrashed = (webview == null) ? false :false; |
| // fast path: don't wait if we've been ready for a while |
| if (zeroTries) { |
| fadeOutCustomViewContainer(); |
| return; |
| } |
| mCustomViewContainer.postDelayed(new Runnable() { |
| public void run() { |
| fadeOutCustomViewContainer(); |
| } |
| }, 32); //WebView is ready, but give it extra 2 frame's time to display and finish the swaps |
| } |
| |
| private void fadeOutCustomViewContainer() { |
| ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f); |
| otheralpha.setDuration(100); |
| otheralpha.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator anim) { |
| mCustomViewContainer.removeView(mAnimScreen.mMain); |
| finishAnimateOut(); |
| unblockEvents(); |
| } |
| }); |
| otheralpha.setInterpolator(new DecelerateInterpolator()); |
| otheralpha.start(); |
| } |
| |
| private void finishAnimateOut() { |
| if (mNavScreen != null) { |
| mNavScreen.setVisibility(View.GONE); |
| } |
| mCustomViewContainer.setAlpha(1f); |
| mCustomViewContainer.setVisibility(View.GONE); |
| mAnimScreen.set(null); |
| } |
| |
| @Override |
| public boolean needsRestoreAllTabs() { |
| return false; |
| } |
| |
| public void toggleNavScreen() { |
| if (!showingNavScreen()) { |
| showNavScreen(); |
| } else { |
| hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false); |
| } |
| } |
| |
| static class AnimScreen { |
| |
| private View mMain; |
| private ImageView mContent; |
| private float mScale; |
| |
| public AnimScreen(Context ctx) { |
| mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen, null); |
| mMain.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| // just eat clicks when this view is visible |
| } |
| }); |
| mContent = (ImageView) mMain.findViewById(R.id.anim_screen_content); |
| mContent.setScaleType(ImageView.ScaleType.MATRIX); |
| mContent.setImageMatrix(new Matrix()); |
| mScale = 1.0f; |
| setScaleFactor(getScaleFactor()); |
| } |
| |
| public void set(TitleBar tbar, Bitmap viewportBitmap) { |
| if (tbar == null) { |
| return; |
| } |
| mContent.setImageBitmap(viewportBitmap); |
| } |
| |
| public void set(Bitmap image) { |
| mContent.setImageBitmap(image); |
| } |
| |
| private void setScaleFactor(float sf) { |
| mScale = sf; |
| Matrix m = new Matrix(); |
| m.postScale(sf, sf); |
| mContent.setImageMatrix(m); |
| } |
| |
| private float getScaleFactor() { |
| return mScale; |
| } |
| |
| } |
| |
| } |