/*
* 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.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Build;
import android.os.Message;
import android.util.Log;
import android.util.TypedValue;
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.accessibility.AccessibilityEvent;
import android.webkit.WebView;
import android.widget.ImageView;
import com.android.browser.UrlInputView.StateListener;
/**
* Ui for regular phone screen sizes
*/
public class PhoneUi extends BaseUi {
private static final String LOGTAG = "PhoneUi";
private static final int MSG_INIT_NAVSCREEN = 100;
private NavScreen mNavScreen;
private AnimScreen mAnimScreen;
private NavigationBarPhone mNavigationBar;
private int mActionBarHeight;
boolean mAnimating;
boolean mShowNav = false;
/**
* @param browser
* @param controller
*/
public PhoneUi(Activity browser, UiController controller) {
super(browser, controller);
setUseQuickControls(BrowserSettings.getInstance().useQuickControls());
mNavigationBar = (NavigationBarPhone) mTitleBar.getNavigationBar();
TypedValue heightValue = new TypedValue();
browser.getTheme().resolveAttribute(
com.android.internal.R.attr.actionBarSize, heightValue, true);
mActionBarHeight = TypedValue.complexToDimensionPixelSize(heightValue.data,
browser.getResources().getDisplayMetrics());
}
@Override
public void onDestroy() {
hideTitleBar();
}
@Override
public void editUrl(boolean clearInput, boolean forceIME) {
if (mUseQuickControls) {
mTitleBar.setShowProgressOnly(false);
}
//Do nothing while at Nav show screen.
if (mShowNav) return;
super.editUrl(clearInput, forceIME);
}
@Override
public boolean onBackKey() {
if (showingNavScreen()) {
mNavScreen.close(mUiController.getTabControl().getCurrentPosition());
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 onProgressChanged(Tab tab) {
super.onProgressChanged(tab);
if (mNavScreen == null && getTitleBar().getHeight() > 0) {
mHandler.sendEmptyMessage(MSG_INIT_NAVSCREEN);
}
}
@Override
protected void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == MSG_INIT_NAVSCREEN) {
if (mNavScreen == null) {
mNavScreen = new NavScreen(mActivity, mUiController, this);
mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS);
mNavScreen.setVisibility(View.GONE);
}
if (mAnimScreen == null) {
mAnimScreen = new AnimScreen(mActivity);
// initialize bitmaps
mAnimScreen.set(getTitleBar(), getWebView());
}
}
}
@Override
public void setActiveTab(final Tab tab) {
mTitleBar.cancelTitleBarAnimation(true);
mTitleBar.setSkipTitleBarAnimations(true);
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.
if (mUseQuickControls) {
mPieControl.forceToTop(mContentView);
view.setTitleBar(null);
mTitleBar.setShowProgressOnly(true);
} else {
view.setTitleBar(mTitleBar);
}
// update nav bar state
mNavigationBar.onStateChanged(StateListener.STATE_NORMAL);
updateLockIconToLatest(tab);
mTitleBar.setSkipTitleBarAnimations(false);
}
// 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 abm = menu.findItem(R.id.add_bookmark_menu_id);
if (abm != null) {
abm.setVisible((tab != null) && !tab.isSnapshot() && !showingNavScreen());
}
MenuItem info = menu.findItem(R.id.page_info_menu_id);
if (info != null) {
info.setVisible(false);
}
MenuItem newtab = menu.findItem(R.id.new_tab_menu_id);
if (newtab != null && !mUseQuickControls) {
newtab.setVisible(false);
}
MenuItem closeOthers = menu.findItem(R.id.close_other_tabs_id);
if (closeOthers != null) {
boolean isLastTab = true;
if (tab != null) {
isLastTab = (mTabControl.getTabCount() <= 1);
}
closeOthers.setEnabled(!isLastTab);
}
if (showingNavScreen()) {
menu.setGroupVisible(R.id.LIVE_MENU, false);
menu.setGroupVisible(R.id.SNAPSHOT_MENU, false);
menu.setGroupVisible(R.id.NAV_MENU, false);
menu.setGroupVisible(R.id.COMBO_MENU, true);
}
}
@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) {
if (!isEditingUrl()) {
hideTitleBar();
} else {
mTitleBar.animate().translationY(mActionBarHeight);
}
}
@Override
public void onActionModeFinished(boolean inLoad) {
mTitleBar.animate().translationY(0);
if (inLoad) {
if (mUseQuickControls) {
mTitleBar.setShowProgressOnly(true);
}
showTitleBar();
}
}
@Override
public boolean isWebShowing() {
return super.isWebShowing() && !showingNavScreen();
}
@Override
public void showWeb(boolean animate) {
super.showWeb(animate);
hideNavScreen(mUiController.getTabControl().getCurrentPosition(), animate);
}
void showNavScreen() {
mShowNav = true;
mUiController.setBlockEvents(true);
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();
}
mActiveTab.capture();
if (mAnimScreen == null) {
mAnimScreen = new AnimScreen(mActivity);
} else {
mAnimScreen.mMain.setAlpha(1f);
mAnimScreen.mTitle.setAlpha(1f);
mAnimScreen.setScaleFactor(1f);
}
mAnimScreen.set(getTitleBar(), getWebView());
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 scaleFactor = width / (float) mContentView.getWidth();
detachTab(mActiveTab);
mContentView.setVisibility(View.GONE);
AnimatorSet set1 = new AnimatorSet();
AnimatorSet inanim = new AnimatorSet();
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 title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha",
1f, 0f);
ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
1f, scaleFactor);
ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain,
"alpha", 1f, 0f);
blend1.setDuration(100);
inanim.playTogether(tx, ty, tr, tb, sx, title);
inanim.setDuration(200);
set1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator anim) {
mCustomViewContainer.removeView(mAnimScreen.mMain);
finishAnimationIn();
mUiController.setBlockEvents(false);
}
});
set1.playSequentially(inanim, blend1);
set1.start();
}
private void finishAnimationIn() {
if (showingNavScreen()) {
// notify accessibility manager about the screen change
mNavScreen.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mTabControl.setOnThumbnailUpdatedListener(mNavScreen);
}
}
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;
}
mUiController.setBlockEvents(true);
mUiController.setActiveTab(tab);
mContentView.setVisibility(View.VISIBLE);
if (mAnimScreen == null) {
mAnimScreen = new AnimScreen(mActivity);
}
mAnimScreen.set(tab.getScreenshot());
if (mAnimScreen.mMain.getParent() == null) {
mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
}
mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
mContentView.getHeight());
mNavScreen.mScroller.finishScroller();
ImageView target = tabview.mImage;
int toLeft = 0;
int toTop = (tab.getWebView() != null) ? tab.getWebView().getVisibleTitleHeight() : 0;
int toRight = mContentView.getWidth();
int width = target.getDrawable().getIntrinsicWidth();
int height = target.getDrawable().getIntrinsicHeight();
int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.mScroller.getScrollX();
int fromTop = tabview.getTop() + target.getTop() - mNavScreen.mScroller.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);
AnimatorSet set1 = new AnimatorSet();
ObjectAnimator fade2 = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f);
ObjectAnimator fade1 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f);
set1.playTogether(fade1, fade2);
set1.setDuration(100);
AnimatorSet set2 = new AnimatorSet();
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);
ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f);
otheralpha.setDuration(100);
set2.playTogether(l, t, r, b, scale);
set2.setDuration(200);
AnimatorSet combo = new AnimatorSet();
combo.playSequentially(set1, set2, otheralpha);
combo.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator anim) {
mCustomViewContainer.removeView(mAnimScreen.mMain);
finishAnimateOut();
mUiController.setBlockEvents(false);
}
});
combo.start();
}
private void finishAnimateOut() {
mTabControl.setOnThumbnailUpdatedListener(null);
mNavScreen.setVisibility(View.GONE);
mCustomViewContainer.setAlpha(1f);
mCustomViewContainer.setVisibility(View.GONE);
}
@Override
public boolean needsRestoreAllTabs() {
return false;
}
public void toggleNavScreen() {
if (!showingNavScreen()) {
showNavScreen();
} else {
hideNavScreen(mUiController.getTabControl().getCurrentPosition(), false);
}
}
@Override
public boolean shouldCaptureThumbnails() {
return true;
}
static class AnimScreen {
private View mMain;
private ImageView mTitle;
private ImageView mContent;
private float mScale;
private Bitmap mTitleBarBitmap;
private Bitmap mContentBitmap;
public AnimScreen(Context ctx) {
mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen,
null);
mTitle = (ImageView) mMain.findViewById(R.id.title);
mContent = (ImageView) mMain.findViewById(R.id.content);
mContent.setScaleType(ImageView.ScaleType.MATRIX);
mContent.setImageMatrix(new Matrix());
mScale = 1.0f;
setScaleFactor(getScaleFactor());
}
public void set(TitleBar tbar, WebView web) {
if (tbar == null || web == null) {
return;
}
if (tbar.getWidth() > 0 && tbar.getEmbeddedHeight() > 0) {
if (mTitleBarBitmap == null
|| mTitleBarBitmap.getWidth() != tbar.getWidth()
|| mTitleBarBitmap.getHeight() != tbar.getEmbeddedHeight()) {
mTitleBarBitmap = safeCreateBitmap(tbar.getWidth(),
tbar.getEmbeddedHeight());
}
if (mTitleBarBitmap != null) {
Canvas c = new Canvas(mTitleBarBitmap);
tbar.draw(c);
c.setBitmap(null);
}
} else {
mTitleBarBitmap = null;
}
mTitle.setImageBitmap(mTitleBarBitmap);
mTitle.setVisibility(View.VISIBLE);
int h = web.getHeight() - tbar.getEmbeddedHeight();
if (mContentBitmap == null
|| mContentBitmap.getWidth() != web.getWidth()
|| mContentBitmap.getHeight() != h) {
mContentBitmap = safeCreateBitmap(web.getWidth(), h);
}
if (mContentBitmap != null) {
Canvas c = new Canvas(mContentBitmap);
int tx = web.getScrollX();
int ty = web.getScrollY();
c.translate(-tx, -ty - tbar.getEmbeddedHeight());
web.draw(c);
c.setBitmap(null);
}
mContent.setImageBitmap(mContentBitmap);
}
private Bitmap safeCreateBitmap(int width, int height) {
if (width <= 0 || height <= 0) {
Log.w(LOGTAG, "safeCreateBitmap failed! width: " + width
+ ", height: " + height);
return null;
}
return Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
}
public void set(Bitmap image) {
mTitle.setVisibility(View.GONE);
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;
}
}
}