tabbed title bar work
bug # http://b/issue?id=2712871
added tab bar
added tab status callbacks to Tab and TabControl
added compact progress/stop/refresh button
added UrlInputView for auto-complete suggestions
modified BrowserProvider for url input suggestions
modified BrowserActivity to use TitleBarXLarge
Change-Id: I62db2be5b89f4c4f27c09dbc6fee7b3b0d5e91b5
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index 0d799a8..fd6d67b 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -16,108 +16,168 @@
package com.android.browser;
+import android.app.SearchManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.drawable.Animatable;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.widget.ImageView;
-import android.widget.ProgressBar;
+import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.common.speech.LoggingEvents;
+import com.android.browser.TabControl.TabChangeListener;
+import com.android.browser.UrlInputView.UrlInputListener;
+
+import java.util.HashMap;
+import java.util.Map;
/**
- * This class represents a title bar for a particular "tab" or "window" in the
- * browser.
+ * tabbed title bar for xlarge screen browser
*/
-public class TitleBarXLarge extends TitleBarBase {
- private Drawable mCircularProgress;
- private ProgressBar mHorizontalProgress;
- private Drawable mStopDrawable;
- private Drawable mReloadDrawable;
- private boolean mInLoad;
- private BrowserActivity mBrowserActivity;
+public class TitleBarXLarge extends TitleBarBase
+ implements TabChangeListener, UrlInputListener {
- private final View mBackButton;
- private final View mForwardButton;
- private final View mStar;
- private final View mMenu;
- private final ImageView mStopButton;
- private final TextView mTitle;
- private final View mAllButton;
+ private static final int PROGRESS_MAX = 100;
- public TitleBarXLarge(BrowserActivity context) {
+ private static final int TAB_WIDTH_SELECTED = 400;
+ private static final int TAB_WIDTH_UNSELECTED = 150;
+
+ private BrowserActivity mBrowserActivity;
+ private Drawable mStopDrawable;
+ private Drawable mReloadDrawable;
+ private Drawable mSelectedBackground;
+ private Drawable mUnselectedBackground;
+
+ private View mBackButton;
+ private View mForwardButton;
+ private View mStar;
+ private View mMenu;
+ private View mAllButton;
+ private TabScrollView mTabs;
+ private View mNewButton;
+ private TabControl mControl;
+ private UrlInputView mUrlView;
+
+ private boolean mIsInLandscape;
+ private Map<Tab, TabViewData> mTabMap;
+
+ private float mDensityScale;
+
+ public TitleBarXLarge(BrowserActivity context, TabControl tabcontrol) {
super(context);
- Resources resources = context.getResources();
- LayoutInflater factory = LayoutInflater.from(context);
- factory.inflate(R.layout.title_bar_xlarge, this);
+ mDensityScale = context.getResources().getDisplayMetrics().density;
+ mTabMap = new HashMap<Tab, TabViewData>();
mBrowserActivity = context;
-
- mTitle = (TextView) findViewById(R.id.title);
- mTitle.setCompoundDrawablePadding(5);
- mTitle.setLongClickable(true);
-
- mLockIcon = (ImageView) findViewById(R.id.lock);
- mFavicon = (ImageView) findViewById(R.id.favicon);
- mStopButton = (ImageView) findViewById(R.id.stop);
- mStopDrawable = mStopButton.getDrawable();
+ mControl = tabcontrol;
+ Resources resources = context.getResources();
+ mSelectedBackground = resources.getDrawable(R.drawable.tab_selected_bg);
+ mUnselectedBackground = resources.getDrawable(R.drawable.tab_unselected_bg);
+ mStopDrawable = resources.getDrawable(R.drawable.progress_stop);
mReloadDrawable = resources.getDrawable(R.drawable.ic_reload);
+ rebuildLayout(context, true);
+ // register the tab change listener
+ mControl.setOnTabChangeListener(this);
+ }
- mAllButton = (ImageView) findViewById(R.id.all_btn);
- mCircularProgress = (Drawable) resources.getDrawable(
- com.android.internal.R.drawable.search_spinner);
- DisplayMetrics metrics = resources.getDisplayMetrics();
- int iconDimension = (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 20f, metrics);
- mCircularProgress.setBounds(0, 0, iconDimension, iconDimension);
- mHorizontalProgress = (ProgressBar) findViewById(
- R.id.progress_horizontal);
- mHorizontalProgress.setProgressDrawable(
- resources.getDrawable(R.drawable.progress));
+ void rebuildLayout() {
+ rebuildLayout(mBrowserActivity, false);
+ }
- // FIXME: Change enabled states based on whether you can go
+ private void rebuildLayout(Context context, boolean rebuildData) {
+ removeAllViews();
+ LayoutInflater factory = LayoutInflater.from(context);
+ factory.inflate(R.layout.title_bar_tabbed, this);
+
+ mTabs = (TabScrollView) findViewById(R.id.tabs);
+ mNewButton = findViewById(R.id.newtab);
+ mUrlView = (UrlInputView) findViewById(R.id.editurl);
+ mAllButton = findViewById(R.id.all_btn);
+ // TODO: Change enabled states based on whether you can go
// back/forward. Probably should be done inside onPageStarted.
mBackButton = findViewById(R.id.back);
mForwardButton = findViewById(R.id.forward);
mStar = findViewById(R.id.star);
mMenu = findViewById(R.id.menu);
View.OnClickListener listener = new View.OnClickListener() {
- public void onClick(View v) {
- if (mBackButton == v) {
- mBrowserActivity.getTopWindow().goBack();
- } else if (mForwardButton == v) {
- mBrowserActivity.getTopWindow().goForward();
- } else if (mStar == v) {
- mBrowserActivity.promptAddOrInstallBookmark();
- } else if (mMenu == v) {
- mBrowserActivity.openOptionsMenu();
- } else if (mStopButton == v) {
- if (mInLoad) {
- mBrowserActivity.stopLoading();
- } else {
- mBrowserActivity.getTopWindow().reload();
- }
- } else if (mTitle == v) {
- mBrowserActivity.editUrl();
- } else if (mAllButton == v) {
- // FIXME: Show the new bookmarks/windows view.
- mBrowserActivity.bookmarksOrHistoryPicker(false);
- }
+ public void onClick(View v) {
+ if (mBackButton == v) {
+ mBrowserActivity.getTopWindow().goBack();
+ } else if (mForwardButton == v) {
+ mBrowserActivity.getTopWindow().goForward();
+ } else if (mStar == v) {
+ mBrowserActivity.promptAddOrInstallBookmark();
+ } else if (mMenu == v) {
+ mBrowserActivity.openOptionsMenu();
+ } else if (mAllButton == v) {
+ // TODO: Show the new bookmarks/windows view.
+ mBrowserActivity.bookmarksOrHistoryPicker(false);
+ } else if (mNewButton == v) {
+ mBrowserActivity.openTabToHomePage();
}
+ }
};
mBackButton.setOnClickListener(listener);
mForwardButton.setOnClickListener(listener);
mStar.setOnClickListener(listener);
- mStopButton.setOnClickListener(listener);
- mTitle.setOnClickListener(listener);
mAllButton.setOnClickListener(listener);
mMenu.setOnClickListener(listener);
+ mNewButton.setOnClickListener(listener);
+
+ mIsInLandscape = mBrowserActivity.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE;
+ mUrlView.setVisibility(mIsInLandscape ? View.GONE : View.VISIBLE);
+ mUrlView.setUrlInputListener(this);
+ buildTabs(rebuildData);
+ // ensure title bar state
+ onCurrentTab(mControl.getCurrentTab());
+ }
+
+ void showUrlEditor(TabViewData tabdata) {
+ mUrlView.setVisibility(View.VISIBLE);
+ if (mIsInLandscape) {
+ mTabs.setVisibility(View.GONE);
+ mUrlView.requestFocus();
+ mUrlView.forceIme();
+ }
+ }
+
+ void hideUrlEditor() {
+ Tab tab = mControl.getCurrentTab();
+ if (mIsInLandscape) {
+ mUrlView.setVisibility(View.GONE);
+ mTabs.setVisibility(View.VISIBLE);
+ } else {
+ // portrait mode
+ mUrlView.setText(tab.getWebView().getUrl());
+ }
+ tab.getWebView().requestFocus();
+ }
+
+
+ // UrlInputListener implementation
+
+ @Override
+ public void onAction(String text) {
+ hideUrlEditor();
+ Intent i = new Intent();
+ i.setAction(Intent.ACTION_SEARCH);
+ i.putExtra(SearchManager.QUERY, text);
+ mBrowserActivity.onNewIntent(i);
+ }
+
+ @Override
+ public void onDismiss() {
+ hideUrlEditor();
}
@Override
@@ -127,44 +187,321 @@
mBrowserActivity.onCreateContextMenu(menu, this, null);
}
- /**
- * Update the progress, from 0 to 100.
- */
- /* package */ void setProgress(int newProgress) {
- if (newProgress >= mHorizontalProgress.getMax()) {
- mTitle.setCompoundDrawables(null, null, null, null);
- ((Animatable) mCircularProgress).stop();
- mHorizontalProgress.setVisibility(View.GONE);
- mInLoad = false;
- mStopButton.setImageDrawable(mReloadDrawable);
- } else {
- mHorizontalProgress.setProgress(newProgress);
- if (!mInLoad && getWindowToken() != null) {
- // checking the window token lets us be sure that we
- // are attached to a window before starting the animation,
- // preventing a potential race condition
- // (fix for bug http://b/2115736)
- mTitle.setCompoundDrawables(null, null, mCircularProgress,
- null);
- ((Animatable) mCircularProgress).start();
- mHorizontalProgress.setVisibility(View.VISIBLE);
- mInLoad = true;
- mStopButton.setImageDrawable(mStopDrawable);
- }
- }
+ @Override
+ /* package */ void setLock(Drawable d) {
+ // TODO: handle in tab specific callback
+ }
+
+ @Override
+ /* package */ void setFavicon(Bitmap icon) {
+ // this is handled in the tab specific callback
}
/**
- * Update the text displayed in the title bar.
- * @param title String to display. If null, the loading string will be
- * shown.
+ * Update the progress, from 0 to 100.
*/
+ @Override
+ /* package */ void setProgress(int newProgress) {
+ // this is handled in tab specific callback
+ }
+
+ @Override
/* package */ void setDisplayTitle(String title) {
- if (title == null) {
- mTitle.setText(R.string.title_bar_loading);
+ // this is done in tab specific callback
+ }
+
+ private void buildTabs(boolean needsRebuilding) {
+ mTabs.clearTabs();
+ for (int i = 0; i < mControl.getTabCount(); i++) {
+ Tab tab = mControl.getTab(i);
+ TabViewData data = buildTab(needsRebuilding, tab);
+ TabView tv = buildView(data);
+ }
+ mTabs.setSelectedTab(mControl.getCurrentIndex());
+ }
+
+ private TabViewData buildTab(boolean needsRebuilding, Tab tab) {
+ TabViewData data = null;
+ if (needsRebuilding) {
+ data = new TabViewData(tab);
+ mTabMap.put(tab, data);
} else {
+ data = mTabMap.get(tab);
+ }
+ return data;
+ }
+
+ private TabView buildView(final TabViewData data) {
+ TabView tv = new TabView(mBrowserActivity, data);
+ tv.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mTabs.getSelectedTab() == v) {
+ showUrlEditor(data);
+ } else {
+ int ix = mControl.getTabIndex(data.mTab);
+ mTabs.setSelectedTab(ix);
+ mBrowserActivity.switchToTab(ix);
+ }
+ }
+ });
+ mTabs.addTab(tv);
+ return tv;
+ }
+
+ /**
+ * the views used in the tab bar
+ */
+ class TabView extends LinearLayout {
+
+ TabViewData mTabData;
+ View mTabContent;
+ TextView mTitle;
+ ImageView mIconView;
+ ImageView mLock;
+ CircularProgressView mStop;
+ ImageView mClose;
+ boolean mSelected;
+ boolean mInLoad;
+
+ /**
+ * @param context
+ */
+ public TabView(Context context, TabViewData tab) {
+ super(context);
+ mTabData = tab;
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ mTabContent = inflater.inflate(R.layout.tab_title, this);
+ mTitle = (TextView) mTabContent.findViewById(R.id.title);
+ mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
+ mLock = (ImageView) mTabContent.findViewById(R.id.lock);
+ mStop = (CircularProgressView) mTabContent.findViewById(R.id.stop);
+ mStop.setMaxProgress(PROGRESS_MAX);
+ mClose = (ImageView) mTabContent.findViewById(R.id.close);
+ mClose.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ closeTab();
+ }
+ });
+ mStop.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mInLoad) {
+ mBrowserActivity.stopLoading();
+ } else {
+ mBrowserActivity.getTopWindow().reload();
+ }
+ }
+ });
+ mSelected = false;
+ mInLoad = false;
+ // update the status
+ updateFromData();
+ }
+
+ private void updateFromData() {
+ mTabData.mTabView = this;
+ if (mTabData.mUrl != null) {
+ setDisplayTitle(mTabData.mUrl);
+ }
+ if (mTabData.mTitle != null) {
+ setDisplayTitle(mTabData.mTitle);
+ }
+ setProgress(mTabData.mProgress);
+ if (mTabData.mIcon != null) {
+ setFavicon(mTabData.mIcon);
+ }
+ if (mTabData.mLock != null) {
+ setLock(mTabData.mLock);
+ }
+ }
+
+ @Override
+ public void setSelected(boolean selected) {
+ mSelected = selected;
+ mStop.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+ mIconView.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+ super.setSelected(selected);
+ setBackgroundDrawable(selected ? mSelectedBackground
+ : mUnselectedBackground);
+ setLayoutParams(new LayoutParams(selected ?
+ (int) (TAB_WIDTH_SELECTED * mDensityScale)
+ : (int) (TAB_WIDTH_UNSELECTED * mDensityScale),
+ LayoutParams.WRAP_CONTENT));
+ }
+
+ void setDisplayTitle(String title) {
mTitle.setText(title);
}
+
+ void setFavicon(Drawable d) {
+ mIconView.setImageDrawable(d);
+ }
+
+ void setLock(Drawable d) {
+ if (null == d) {
+ mLock.setVisibility(View.GONE);
+ } else {
+ mLock.setImageDrawable(d);
+ mLock.setVisibility(View.VISIBLE);
+ }
+ }
+
+ void setTitleCompoundDrawables(Drawable left, Drawable top,
+ Drawable right, Drawable bottom) {
+ mTitle.setCompoundDrawables(left, top, right, bottom);
+ }
+
+ void setProgress(int newProgress) {
+ mStop.setProgress(newProgress);
+ if (newProgress >= PROGRESS_MAX) {
+ mInLoad = false;
+ mStop.setImageDrawable(mReloadDrawable);
+ } else {
+ if (!mInLoad && getWindowToken() != null) {
+ // checking the window token lets us be sure that we
+ // are attached to a window before starting the animation,
+ // preventing a potential race condition
+ // (fix for bug http://b/2115736)
+ mInLoad = true;
+ mStop.setImageDrawable(mStopDrawable);
+ }
+ }
+ }
+
+ private void closeTab() {
+ if (mTabData.mTab == mControl.getCurrentTab()) {
+ mBrowserActivity.closeCurrentWindow();
+ } else {
+ mBrowserActivity.closeTab(mTabData.mTab);
+ }
+ }
+
+ }
+
+ /**
+ * class to store tab state within the title bar
+ */
+ class TabViewData {
+
+ Tab mTab;
+ TabView mTabView;
+ int mProgress;
+ Drawable mIcon;
+ Drawable mLock;
+ String mTitle;
+ String mUrl;
+
+ TabViewData(Tab tab) {
+ mTab = tab;
+ }
+
+ void setUrlAndTitle(String url, String title) {
+ mUrl = url;
+ mTitle = title;
+ if (mTabView != null) {
+ if (title != null) {
+ mTabView.setDisplayTitle(title);
+ } else if (url != null) {
+ mTabView.setDisplayTitle(url);
+ }
+ }
+ }
+
+ void setProgress(int newProgress) {
+ mProgress = newProgress;
+ if (mTabView != null) {
+ mTabView.setProgress(mProgress);
+ }
+ }
+
+ void setFavicon(Bitmap icon) {
+ Drawable[] array = new Drawable[3];
+ array[0] = new PaintDrawable(Color.BLACK);
+ array[1] = new PaintDrawable(Color.WHITE);
+ if (icon == null) {
+ array[2] = mGenericFavicon;
+ } else {
+ array[2] = new BitmapDrawable(icon);
+ }
+ LayerDrawable d = new LayerDrawable(array);
+ d.setLayerInset(1, 1, 1, 1, 1);
+ d.setLayerInset(2, 2, 2, 2, 2);
+ mIcon = d;
+ if (mTabView != null) {
+ mTabView.setFavicon(mIcon);
+ }
+ }
+
+ }
+
+ // TabChangeListener implementation
+
+ @Override
+ public void onCurrentTab(Tab tab) {
+ mTabs.setSelectedTab(mControl.getCurrentIndex());
+ TabViewData tvd = mTabMap.get(tab);
+ if (tvd != null) {
+ if (tvd.mUrl != null) {
+ mUrlView.setText(tvd.mUrl);
+ }
+ setProgress(tvd.mProgress);
+ }
+ }
+
+ @Override
+ public void onFavicon(Tab tab, Bitmap favicon) {
+ TabViewData tvd = mTabMap.get(tab);
+ if (tvd != null) {
+ tvd.setFavicon(favicon);
+ }
+ }
+
+ @Override
+ public void onNewTab(Tab tab) {
+ TabViewData tvd = buildTab(true, tab);
+ buildView(tvd);
+ }
+
+ @Override
+ public void onProgress(Tab tab, int progress) {
+ TabViewData tvd = mTabMap.get(tab);
+ if (tvd != null) {
+ tvd.setProgress(progress);
+ }
+ if (tab == mControl.getCurrentTab()) {
+ setProgress(progress);
+ }
+ }
+
+ @Override
+ public void onRemoveTab(Tab tab) {
+ TabViewData tvd = mTabMap.get(tab);
+ TabView tv = tvd.mTabView;
+ if (tv != null) {
+ mTabs.removeTab(tv);
+ }
+ mTabMap.remove(tab);
+ }
+
+ @Override
+ public void onUrlAndTitle(Tab tab, String url, String title) {
+ TabViewData tvd = mTabMap.get(tab);
+ if (tvd != null) {
+ tvd.setUrlAndTitle(url, title);
+ }
+ if ((url != null) && (tab == mControl.getCurrentTab())) {
+ mUrlView.setText(url);
+ }
+ }
+
+ @Override
+ public void onPageFinished(Tab tab) {
+ }
+
+ @Override
+ public void onPageStarted(Tab tab) {
}
}