Merge "Import revised translations."
diff --git a/res/drawable-hdpi/browsertab_add.png b/res/drawable-hdpi/browsertab_add.png
new file mode 100644
index 0000000..a48b0f8
--- /dev/null
+++ b/res/drawable-hdpi/browsertab_add.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_new_window.png b/res/drawable-hdpi/ic_menu_new_window.png
index fa544fc..fd85bb7 100644
--- a/res/drawable-hdpi/ic_menu_new_window.png
+++ b/res/drawable-hdpi/ic_menu_new_window.png
Binary files differ
diff --git a/res/drawable-mdpi/bg_browsertabs.png b/res/drawable-mdpi/bg_browsertabs.png
new file mode 100644
index 0000000..9d0ff07
--- /dev/null
+++ b/res/drawable-mdpi/bg_browsertabs.png
Binary files differ
diff --git a/res/drawable-mdpi/browsertab_add.png b/res/drawable-mdpi/browsertab_add.png
new file mode 100644
index 0000000..cb12775
--- /dev/null
+++ b/res/drawable-mdpi/browsertab_add.png
Binary files differ
diff --git a/res/drawable-mdpi/browsertab_inactive.png b/res/drawable-mdpi/browsertab_inactive.png
new file mode 100644
index 0000000..d441604
--- /dev/null
+++ b/res/drawable-mdpi/browsertab_inactive.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_new_window.png b/res/drawable-mdpi/ic_menu_new_window.png
index c767979..c495162 100644
--- a/res/drawable-mdpi/ic_menu_new_window.png
+++ b/res/drawable-mdpi/ic_menu_new_window.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_tab_close.png b/res/drawable-mdpi/ic_tab_close.png
index 2f23842..b86c714 100644
--- a/res/drawable-mdpi/ic_tab_close.png
+++ b/res/drawable-mdpi/ic_tab_close.png
Binary files differ
diff --git a/res/drawable-nodpi/bg_urlbar.png b/res/drawable-nodpi/bg_urlbar.png
new file mode 100644
index 0000000..ff173c4
--- /dev/null
+++ b/res/drawable-nodpi/bg_urlbar.png
Binary files differ
diff --git a/res/layout/tab_bar.xml b/res/layout/tab_bar.xml
index 2726055..e8f146c 100644
--- a/res/layout/tab_bar.xml
+++ b/res/layout/tab_bar.xml
@@ -14,20 +14,24 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabbarcontent"
android:layout_width="match_parent"
- android:layout_height="48dip"
+ android:layout_height="56dip"
android:orientation="horizontal"
+ android:paddingLeft="12dip"
+ android:paddingTop="12dip"
+ android:paddingRight="0dip"
+ android:paddingBottom="0dip"
style="@style/ActionBarStyle"
>
<com.android.browser.TabScrollView
android:id="@+id/tabs"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="44dip"
android:orientation="horizontal" />
<ImageButton
android:id="@+id/newtab"
android:src="@drawable/ic_menu_new_window"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="44dip"
style="@style/HoloButton"
- android:background="@drawable/browserbarbutton" />
+ android:background="@drawable/browsertab_add" />
</merge>
\ No newline at end of file
diff --git a/res/layout/tab_title.xml b/res/layout/tab_title.xml
index a2da03d..e4a4e58 100644
--- a/res/layout/tab_title.xml
+++ b/res/layout/tab_title.xml
@@ -15,8 +15,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:orientation="horizontal"
- android:background="@drawable/tab_background">
+ android:orientation="horizontal">
<ImageView
android:id="@+id/incognito"
android:layout_width="16dip"
@@ -56,6 +55,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
android:src="@drawable/ic_tab_close" />
</merge>
diff --git a/res/layout/url_bar.xml b/res/layout/url_bar.xml
index f695ae3..3636ca8 100644
--- a/res/layout/url_bar.xml
+++ b/res/layout/url_bar.xml
@@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="48dip"
android:orientation="horizontal"
- android:background="@drawable/urlbar_bg">
+ android:background="@drawable/bg_urlbar">
<ImageButton
android:id="@+id/back"
android:src="@drawable/ic_back_normal"
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index 952d97a..d87a347 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -43,9 +43,8 @@
<style name="ShortCutTheme" parent="@android:Theme.Holo">
</style>
<style name="ActionBarStyle">
- <item name="android:height">48dip</item>
- <item name="android:padding">0dip</item>
- <item name="android:background">@drawable/tabbar_bg</item>
+ <item name="android:height">56dip</item>
+ <item name="android:background">@drawable/bg_browsertabs</item>
<item name="android:displayOptions"></item>
</style>
<style name="ActionButton">
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index d51ab33..7cfa3f6 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -13,12 +13,14 @@
<resources
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- The width of a selected tab -->
- <dimen
- name="tab_width_selected">300dp</dimen>
+ <dimen name="tab_width_selected">280dp</dimen>
<!-- The width of an unselected tab -->
- <dimen
- name="tab_width_unselected">300dp</dimen>
-
+ <dimen name="tab_width_unselected">240dp</dimen>
+ <dimen name="tab_height">44dp</dimen>
+ <dimen name="tab_overlap">8dp</dimen>
+ <dimen name="tab_slice">18dp</dimen>
+ <dimen name="tab_padding">16dp</dimen>
+ <dimen name="max_tab_width">300dp</dimen>
<dimen name="bookmarkThumbnailWidth">90dip</dimen>
<dimen name="bookmarkThumbnailHeight">80dip</dimen>
<dimen name="add_bookmark_width">500dip</dimen>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 2864d47..e18676d 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -19,7 +19,7 @@
<!-- The maximum number of open tabs -->
<integer name="max_tabs">16</integer>
<!-- The duration of the tab animations in millisecs -->
- <integer name="tab_animation_duration">500</integer>
+ <integer name="tab_animation_duration">200</integer>
<integer name="max_width_crumb">200</integer>
<!-- The maximum number of most visited URLs in the history tab -->
<integer name="most_visits_limit">10</integer>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c6adaef..1c8b71c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -879,4 +879,8 @@
<!-- Menu item to share URL selection [CHAR LIMIT=30] -->
<string name="menu_share_url">Share</string>
+ <!-- Toast to inform the user that the maximum number of tabs has been
+ reached. [CHAR LIMIT=50] -->
+ <string name="max_tabs_warning">No more tabs available</string>
+
</resources>
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index b9ccd72..4fca79d 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -508,6 +508,13 @@
mContentView.addView(container, COVER_SCREEN_PARAMS);
}
+ int getTitleBarWidth() {
+ if (mTitleBar != null) {
+ return mTitleBar.getWidth();
+ }
+ return 0;
+ }
+
void showFakeTitleBar() {
if (!isFakeTitleBarShowing() && mActiveTabsPage == null &&
!mActivityPaused) {
@@ -932,4 +939,12 @@
return mVideoProgressView;
}
+ @Override
+ public void showMaxTabsWarning() {
+ Toast warning = Toast.makeText(mActivity,
+ mActivity.getString(R.string.max_tabs_warning),
+ Toast.LENGTH_SHORT);
+ warning.show();
+ }
+
}
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index e4b0982..0227621 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -195,6 +195,7 @@
// Checks to see when the bookmarks database has changed, and updates the
// Tabs' notion of whether they represent bookmarked sites.
private ContentObserver mBookmarksObserver;
+ private DataController mDataController;
private static class ClearThumbnails extends AsyncTask<File, Void, Void> {
@Override
@@ -213,6 +214,7 @@
public Controller(Activity browser) {
mActivity = browser;
mSettings = BrowserSettings.getInstance();
+ mDataController = DataController.getInstance(mActivity);
mTabControl = new TabControl(this);
mSettings.setController(this);
@@ -843,42 +845,7 @@
}
// Update the title in the history database if not in private browsing mode
if (!tab.isPrivateBrowsingEnabled()) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... unused) {
- // See if we can find the current url in our history
- // database and add the new title to it.
- String url = pageUrl;
- if (url.startsWith("http://www.")) {
- url = url.substring(11);
- } else if (url.startsWith("http://")) {
- url = url.substring(4);
- }
- // Escape wildcards for LIKE operator.
- url = url.replace("\\", "\\\\").replace("%", "\\%")
- .replace("_", "\\_");
- Cursor c = null;
- try {
- final ContentResolver cr =
- getActivity().getContentResolver();
- String selection = History.URL + " LIKE ? ESCAPE '\\'";
- String [] selectionArgs = new String[] { "%" + url };
- ContentValues values = new ContentValues();
- values.put(History.TITLE, title);
- cr.update(History.CONTENT_URI, values, selection,
- selectionArgs);
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "Tab onReceived title", e);
- } catch (SQLiteException ex) {
- Log.e(LOGTAG,
- "onReceivedTitle() caught SQLiteException: ",
- ex);
- } finally {
- if (c != null) c.close();
- }
- return null;
- }
- }.execute();
+ mDataController.updateHistoryTitle(pageUrl, title);
}
}
@@ -924,28 +891,7 @@
if (url.regionMatches(true, 0, "about:", 0, 6)) {
return;
}
- // remove "client" before updating it to the history so that it wont
- // show up in the auto-complete list.
- int index = url.indexOf("client=ms-");
- if (index > 0 && url.contains(".google.")) {
- int end = url.indexOf('&', index);
- if (end > 0) {
- url = url.substring(0, index)
- .concat(url.substring(end + 1));
- } else {
- // the url.charAt(index-1) should be either '?' or '&'
- url = url.substring(0, index-1);
- }
- }
- final ContentResolver cr = getActivity().getContentResolver();
- final String newUrl = url;
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... unused) {
- Browser.updateVisitedHistory(cr, newUrl, true);
- return null;
- }
- }.execute();
+ mDataController.updateVisitedHistory(url);
WebIconDatabase.getInstance().retainIconForPageUrl(url);
}
@@ -2107,9 +2053,19 @@
}
}
+ @Override
+ public Tab openTabToHomePage() {
+ // check for max tabs
+ if (mTabControl.canCreateNewTab()) {
+ return openTabAndShow(mSettings.getHomePage(), false, null);
+ } else {
+ mUi.showMaxTabsWarning();
+ return null;
+ }
+ }
+
// A wrapper function of {@link #openTabAndShow(UrlData, boolean, String)}
// that accepts url as string.
-
protected Tab openTabAndShow(String url, boolean closeOnExit, String appId) {
return openTabAndShow(new UrlData(url), closeOnExit, appId);
}
@@ -2166,8 +2122,10 @@
addTab(tab);
setActiveTab(tab);
return tab;
+ } else {
+ mUi.showMaxTabsWarning();
+ return null;
}
- return null;
}
/**
@@ -2191,11 +2149,6 @@
}
@Override
- public Tab openTabToHomePage() {
- return openTabAndShow(mSettings.getHomePage(), false, null);
- }
-
- @Override
public void closeCurrentTab() {
// hide combo view if open
removeComboView();
diff --git a/src/com/android/browser/DataController.java b/src/com/android/browser/DataController.java
new file mode 100644
index 0000000..be38d70
--- /dev/null
+++ b/src/com/android/browser/DataController.java
@@ -0,0 +1,118 @@
+/*
+ * 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.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.BrowserContract.History;
+
+public class DataController {
+ // Message IDs
+ private static final int HISTORY_UPDATE_VISITED = 100;
+ private static final int HISTORY_UPDATE_TITLE = 101;
+ private static DataController sInstance;
+
+ private Context mContext;
+ private Handler mHandler;
+
+ /* package */ static DataController getInstance(Context c) {
+ if (sInstance == null) {
+ sInstance = new DataController(c);
+ }
+ return sInstance;
+ }
+
+ private DataController(Context c) {
+ mContext = c.getApplicationContext();
+ HandlerThread thread = new HandlerThread("DataController");
+ thread.setDaemon(true);
+ thread.start();
+ mHandler = new DataControllerHandler(thread.getLooper());
+ }
+
+ public void updateVisitedHistory(String url) {
+ mHandler.obtainMessage(HISTORY_UPDATE_VISITED, url).sendToTarget();
+ }
+
+ public void updateHistoryTitle(String url, String title) {
+ mHandler.obtainMessage(HISTORY_UPDATE_TITLE, new String[] { url, title })
+ .sendToTarget();
+ }
+
+ class DataControllerHandler extends Handler {
+ public DataControllerHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case HISTORY_UPDATE_VISITED:
+ doUpdateVisitedHistory((String) msg.obj);
+ break;
+ case HISTORY_UPDATE_TITLE:
+ String[] args = (String[]) msg.obj;
+ doUpdateHistoryTitle(args[0], args[1]);
+ break;
+ }
+ }
+ }
+
+ private void doUpdateVisitedHistory(String url) {
+ ContentResolver cr = mContext.getContentResolver();
+ Cursor c = null;
+ try {
+ c = cr.query(History.CONTENT_URI, new String[] { History._ID, History.VISITS },
+ History.URL + "=?", new String[] { url }, null);
+ if (c.moveToFirst()) {
+ ContentValues values = new ContentValues();
+ values.put(History.VISITS, c.getInt(1) + 1);
+ values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
+ cr.update(ContentUris.withAppendedId(History.CONTENT_URI, c.getLong(0)),
+ values, null, null);
+ } else {
+ android.provider.Browser.truncateHistory(cr);
+ ContentValues values = new ContentValues();
+ values.put(History.URL, url);
+ values.put(History.VISITS, 1);
+ values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
+ values.put(History.TITLE, url);
+ values.put(History.DATE_CREATED, 0);
+ values.put(History.USER_ENTERED, 0);
+ cr.insert(History.CONTENT_URI, values);
+ }
+ } finally {
+ if (c != null) c.close();
+ }
+ }
+
+ private void doUpdateHistoryTitle(String url, String title) {
+ ContentResolver cr = mContext.getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put(History.TITLE, title);
+ cr.update(History.CONTENT_URI, values, History.URL + "=?",
+ new String[] { url });
+ }
+}
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index 040af81..0b47668 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -222,19 +222,6 @@
// But currently, we get the user-typed URL from search box as well.
url = UrlUtils.fixUrl(url);
url = UrlUtils.smartUrlFilter(url);
- final ContentResolver cr = mActivity.getContentResolver();
- final String newUrl = url;
- if (mTabControl == null
- || mTabControl.getCurrentWebView() == null
- || !mTabControl.getCurrentWebView().isPrivateBrowsingEnabled()) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... unused) {
- Browser.updateVisitedHistory(cr, newUrl, false);
- return null;
- }
- }.execute();
- }
String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&";
if (url.contains(searchSource)) {
String source = null;
@@ -311,7 +298,6 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... unused) {
- Browser.updateVisitedHistory(cr, newUrl, false);
Browser.addSearchUrl(cr, newUrl);
return null;
}
diff --git a/src/com/android/browser/ShortcutActivity.java b/src/com/android/browser/ShortcutActivity.java
index 33e192a..16a4cbe 100644
--- a/src/com/android/browser/ShortcutActivity.java
+++ b/src/com/android/browser/ShortcutActivity.java
@@ -40,6 +40,7 @@
mBookmarks.setEnableContextMenu(false);
mBookmarks.setBreadCrumbMaxVisible(2);
mBookmarks.setBreadCrumbUseBackButton(true);
+ mBookmarks.setCallbackListener(this);
View cancel = findViewById(R.id.cancel);
if (cancel != null) {
cancel.setOnClickListener(this);
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index 14b1845..4f179b0 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -22,7 +22,13 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -74,6 +80,17 @@
private Drawable mGenericFavicon;
private String mLoadingText;
+ private Drawable mActiveDrawable;
+ private Drawable mInactiveDrawable;
+
+ private Bitmap mShaderBuffer;
+ private Canvas mShaderCanvas;
+ private Paint mShaderPaint;
+ private int mTabHeight;
+ private int mTabOverlap;
+ private int mTabSliceWidth;
+ private int mTabPadding;
+
public TabBar(Activity activity, UiController controller, BaseUi ui) {
super(activity);
mActivity = activity;
@@ -83,16 +100,20 @@
Resources res = activity.getResources();
mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);
+ mActiveDrawable = res.getDrawable(R.drawable.bg_urlbar);
+ mInactiveDrawable = res.getDrawable(R.drawable.browsertab_inactive);
mTabMap = new HashMap<Tab, TabViewData>();
Resources resources = activity.getResources();
LayoutInflater factory = LayoutInflater.from(activity);
factory.inflate(R.layout.tab_bar, this);
+ setPadding(12, 12, 0, 0);
mTabs = (TabScrollView) findViewById(R.id.tabs);
mNewTab = (ImageButton) findViewById(R.id.newtab);
mNewTab.setOnClickListener(this);
mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
mLoadingText = res.getString(R.string.title_bar_loading);
+ setChildrenDrawingOrderEnabled(true);
// TODO: Change enabled states based on whether you can go
// back/forward. Probably should be done inside onPageStarted.
@@ -102,6 +123,22 @@
mUserRequestedUrlbar = false;
mTitleVisible = true;
mButtonWidth = -1;
+ // tab dimensions
+ mTabHeight = (int) res.getDimension(R.dimen.tab_height);
+ mTabOverlap = (int) res.getDimension(R.dimen.tab_overlap);
+ mTabSliceWidth = (int) res.getDimension(R.dimen.tab_slice);
+ mTabPadding = (int) res.getDimension(R.dimen.tab_padding);
+ int maxTabWidth = (int) res.getDimension(R.dimen.max_tab_width);
+ // shader initialization
+ mShaderBuffer = Bitmap.createBitmap(maxTabWidth, mTabHeight,
+ Bitmap.Config.ARGB_8888);
+ mShaderCanvas = new Canvas(mShaderBuffer);
+ mShaderPaint = new Paint();
+ BitmapShader shader = new BitmapShader(mShaderBuffer,
+ Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mShaderPaint.setShader(shader);
+ mShaderPaint.setStyle(Paint.Style.FILL);
+ mShaderPaint.setAntiAlias(true);
}
void updateTabs(List<Tab> tabs) {
@@ -115,17 +152,31 @@
}
@Override
+ protected void onMeasure(int hspec, int vspec) {
+ super.onMeasure(hspec, vspec);
+ int w = getMeasuredWidth();
+ // adjust for new tab overlap
+ w -= mTabOverlap;
+ setMeasuredDimension(w, getMeasuredHeight());
+ }
+
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ // use paddingLeft and paddingTop
+ int pl = getPaddingLeft();
+ int pt = getPaddingTop();
if (mButtonWidth == -1) {
- mButtonWidth = mNewTab.getMeasuredWidth();
+ mButtonWidth = mNewTab.getMeasuredWidth() - mTabOverlap;
}
int sw = mTabs.getMeasuredWidth();
- int w = right-left;
+ int w = right - left - pl;
if (w-sw < mButtonWidth) {
sw = w - mButtonWidth;
}
- mTabs.layout(0, 0, sw, bottom-top );
- mNewTab.layout(sw, 0, sw+mButtonWidth, bottom-top);
+ mTabs.layout(pl, pt, pl + sw, bottom - top);
+ // adjust for overlap
+ mNewTab.layout(pl + sw - mTabOverlap, pt,
+ pl + sw + mButtonWidth - mTabOverlap, bottom - top);
}
public void onClick(View view) {
@@ -212,6 +263,12 @@
return tv;
}
+ @Override
+ protected int getChildDrawingOrder(int count, int i) {
+ // reverse
+ return count - 1 - i;
+ }
+
/**
* View used in the tab bar
*/
@@ -226,16 +283,21 @@
ImageView mClose;
boolean mSelected;
boolean mInLoad;
+ Path mPath;
+ int[] mWindowPos;
/**
* @param context
*/
public TabView(Context context, TabViewData tab) {
super(context);
+ setWillNotDraw(false);
+ mPath = new Path();
+ mWindowPos = new int[2];
mTabData = tab;
setGravity(Gravity.CENTER_VERTICAL);
setOrientation(LinearLayout.HORIZONTAL);
- setBackgroundResource(R.drawable.tab_background);
+ setPadding(0, 0, mTabPadding, 0);
LayoutInflater inflater = LayoutInflater.from(getContext());
mTabContent = inflater.inflate(R.layout.tab_title, this, true);
mTitle = (TextView) mTabContent.findViewById(R.id.title);
@@ -286,11 +348,11 @@
mTitle.setTextAppearance(mActivity, mSelected ?
R.style.TabTitleSelected : R.style.TabTitleUnselected);
setHorizontalFadingEdgeEnabled(!mSelected);
- setFadingEdgeLength(50);
super.setActivated(selected);
- setLayoutParams(new LayoutParams(selected ?
- mTabWidthSelected : mTabWidthUnselected,
- LayoutParams.MATCH_PARENT));
+ LayoutParams lp = (LinearLayout.LayoutParams) getLayoutParams();
+ lp.width = selected ? mTabWidthSelected : mTabWidthUnselected;
+ lp.height = LayoutParams.MATCH_PARENT;
+ setLayoutParams(lp);
}
void setDisplayTitle(String title) {
@@ -328,6 +390,42 @@
}
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ setTabPath(mPath, 0, 0, r - l, b - t);
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ int state = canvas.save();
+ int[] pos = new int[2];
+ getLocationInWindow(mWindowPos);
+ Drawable drawable = mSelected ? mActiveDrawable : mInactiveDrawable;
+ drawable.setBounds(0, 0, mUi.getTitleBarWidth(), getHeight());
+ drawClipped(canvas, drawable, mPath, mWindowPos[0]);
+ canvas.restoreToCount(state);
+ super.dispatchDraw(canvas);
+ }
+
+ private void drawClipped(Canvas canvas, Drawable drawable,
+ Path clipPath, int left) {
+ mShaderCanvas.drawColor(Color.TRANSPARENT);
+ mShaderCanvas.translate(-left, 0);
+ drawable.draw(mShaderCanvas);
+ canvas.drawPath(clipPath, mShaderPaint);
+ mShaderCanvas.translate(left, 0);
+ }
+
+ private void setTabPath(Path path, int l, int t, int r, int b) {
+ path.reset();
+ path.moveTo(l, b);
+ path.lineTo(l, t);
+ path.lineTo(r - mTabSliceWidth, t);
+ path.lineTo(r, b);
+ path.close();
+ }
+
}
/**
diff --git a/src/com/android/browser/TabScrollView.java b/src/com/android/browser/TabScrollView.java
index fbb40aa..04ed5a3 100644
--- a/src/com/android/browser/TabScrollView.java
+++ b/src/com/android/browser/TabScrollView.java
@@ -17,10 +17,8 @@
package com.android.browser;
import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -41,6 +39,7 @@
private Drawable mArrowLeft;
private Drawable mArrowRight;
private int mAnimationDuration;
+ private int mTabOverlap;
/**
* @param context
@@ -73,8 +72,10 @@
mContext = ctx;
mAnimationDuration = ctx.getResources().getInteger(
R.integer.tab_animation_duration);
+ mTabOverlap = (int) ctx.getResources().getDimension(R.dimen.tab_overlap);
setHorizontalScrollBarEnabled(false);
- mContentView = new LinearLayout(mContext);
+ setOverScrollMode(OVER_SCROLL_NEVER);
+ mContentView = new TabLayout(mContext);
mContentView.setOrientation(LinearLayout.HORIZONTAL);
mContentView.setLayoutParams(
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
@@ -211,4 +212,49 @@
return getScrollX();
}
+ class TabLayout extends LinearLayout {
+
+ public TabLayout(Context context) {
+ super(context);
+ setChildrenDrawingOrderEnabled(true);
+ }
+
+ @Override
+ protected void onMeasure(int hspec, int vspec) {
+ super.onMeasure(hspec, vspec);
+ int w = getMeasuredWidth();
+ w -= Math.max(0, mContentView.getChildCount() - 1) * mTabOverlap;
+ setMeasuredDimension(w, getMeasuredHeight());
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (getChildCount() > 1) {
+ int nextLeft = getChildAt(0).getRight() - mTabOverlap;
+ for (int i = 1; i < getChildCount(); i++) {
+ View tab = getChildAt(i);
+ int w = tab.getRight() - tab.getLeft();
+ tab.layout(nextLeft, tab.getTop(), nextLeft + w, tab.getBottom());
+ nextLeft += w - mTabOverlap;
+ }
+ }
+ }
+
+ @Override
+ protected int getChildDrawingOrder(int count, int i) {
+ int next = -1;
+ if ((i == (count - 1)) && (mSelected >= 0)) {
+ next = mSelected;
+ } else {
+ next = count - i - 1;
+ if (next <= mSelected) {
+ next--;
+ }
+ }
+ return next;
+ }
+
+ }
+
}
diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java
index 2bfec44..b56ba30 100644
--- a/src/com/android/browser/UI.java
+++ b/src/com/android/browser/UI.java
@@ -131,4 +131,7 @@
View getVideoLoadingProgressView();
void bookmarkedStatusHasChanged(Tab tab);
+
+ void showMaxTabsWarning();
+
}
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index 8d9f1fe..8137d55 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -622,12 +622,6 @@
}
case BOOKMARKS_FOLDER: {
- // Don't allow selections to be applied to the default folder
- if (!TextUtils.isEmpty(selection) || selectionArgs != null) {
- throw new UnsupportedOperationException(
- "selections aren't supported on this URI");
- }
-
// Look for an account
boolean useAccount = false;
String accountType = uri.getQueryParameter(Bookmarks.PARAM_ACCOUNT_TYPE);
@@ -649,37 +643,49 @@
}
if (!useAccount) {
qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
- query = qb.buildQuery(projection,
- Bookmarks.PARENT + "=? AND " + Bookmarks.IS_DELETED + "=0",
- null, null, null, sortOrder, null);
-
+ String where = Bookmarks.PARENT + "=? AND " + Bookmarks.IS_DELETED + "=0";
+ where = DatabaseUtils.concatenateWhere(where, selection);
args = new String[] { Long.toString(FIXED_ID_ROOT) };
+ if (selectionArgs != null) {
+ args = DatabaseUtils.appendSelectionArgs(args, selectionArgs);
+ }
+ query = qb.buildQuery(projection, where, null, null, sortOrder, null);
} else {
qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
+ String where = Bookmarks.ACCOUNT_TYPE + "=? AND " +
+ Bookmarks.ACCOUNT_NAME + "=? " +
+ "AND parent = " +
+ "(SELECT _id FROM " + TABLE_BOOKMARKS + " WHERE " +
+ ChromeSyncColumns.SERVER_UNIQUE + "=" +
+ "'" + ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR + "' " +
+ "AND account_type = ? AND account_name = ?) " +
+ "AND " + Bookmarks.IS_DELETED + "=0";
+ where = DatabaseUtils.concatenateWhere(where, selection);
String bookmarksBarQuery = qb.buildQuery(projection,
- Bookmarks.ACCOUNT_TYPE + "=? AND " + Bookmarks.ACCOUNT_NAME + "=? " +
- "AND parent = " +
- "(SELECT _id FROM " + TABLE_BOOKMARKS + " WHERE " +
- ChromeSyncColumns.SERVER_UNIQUE + "=" +
- "'" + ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR + "' " +
- "AND account_type = ? AND account_name = ?) " +
- "AND " + Bookmarks.IS_DELETED + "=0",
- null, null, null, null, null);
+ where, null, null, null, null);
+ args = new String[] {accountType, accountName,
+ accountType, accountName};
+ if (selectionArgs != null) {
+ args = DatabaseUtils.appendSelectionArgs(args, selectionArgs);
+ }
+ where = Bookmarks.ACCOUNT_TYPE + "=? AND " + Bookmarks.ACCOUNT_NAME + "=?" +
+ " AND " + ChromeSyncColumns.SERVER_UNIQUE + "=?";
+ where = DatabaseUtils.concatenateWhere(where, selection);
qb.setProjectionMap(OTHER_BOOKMARKS_PROJECTION_MAP);
String otherBookmarksQuery = qb.buildQuery(projection,
- Bookmarks.ACCOUNT_TYPE + "=? AND " + Bookmarks.ACCOUNT_NAME + "=?" +
- " AND " + ChromeSyncColumns.SERVER_UNIQUE + "=?",
- null, null, null, null, null);
+ where, null, null, null, null);
query = qb.buildUnionQuery(
new String[] { bookmarksBarQuery, otherBookmarksQuery },
sortOrder, limit);
- args = new String[] {
- accountType, accountName, accountType, accountName,
+ args = DatabaseUtils.appendSelectionArgs(args, new String[] {
accountType, accountName, ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS,
- };
+ });
+ if (selectionArgs != null) {
+ args = DatabaseUtils.appendSelectionArgs(args, selectionArgs);
+ }
}
Cursor cursor = db.rawQuery(query, args);
@@ -697,6 +703,7 @@
// fall through
}
case HISTORY: {
+ filterSearchClient(selectionArgs);
if (sortOrder == null) {
sortOrder = DEFAULT_SORT_HISTORY;
}
@@ -803,6 +810,7 @@
// fall through
}
case HISTORY: {
+ filterSearchClient(selectionArgs);
return db.delete(TABLE_HISTORY, selection, selectionArgs);
}
@@ -877,6 +885,9 @@
if (!values.containsKey(History.DATE_CREATED)) {
values.put(History.DATE_CREATED, System.currentTimeMillis());
}
+ String url = values.getAsString(History.URL);
+ url = filterSearchClient(url);
+ values.put(History.URL, url);
// Extract out the image values so they can be inserted into the images table
ContentValues imageValues = extractImageValues(values,
@@ -917,6 +928,32 @@
}
}
+ private void filterSearchClient(String[] selectionArgs) {
+ if (selectionArgs != null) {
+ for (int i = 0; i < selectionArgs.length; i++) {
+ selectionArgs[i] = filterSearchClient(selectionArgs[i]);
+ }
+ }
+ }
+
+ // Filters out the client=ms- param for search urls
+ private String filterSearchClient(String url) {
+ // remove "client" before updating it to the history so that it wont
+ // show up in the auto-complete list.
+ int index = url.indexOf("client=ms-");
+ if (index > 0 && url.contains(".google.")) {
+ int end = url.indexOf('&', index);
+ if (end > 0) {
+ url = url.substring(0, index)
+ .concat(url.substring(end + 1));
+ } else {
+ // the url.charAt(index-1) should be either '?' or '&'
+ url = url.substring(0, index-1);
+ }
+ }
+ return url;
+ }
+
/**
* Searches are unique, so perform an UPSERT manually since SQLite doesn't support them.
*/
@@ -1086,6 +1123,7 @@
int updateHistoryInTransaction(ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ filterSearchClient(selectionArgs);
Cursor cursor = query(History.CONTENT_URI,
new String[] { History._ID, History.URL },
selection, selectionArgs, null);
@@ -1095,7 +1133,8 @@
boolean updatingUrl = values.containsKey(History.URL);
String url = null;
if (updatingUrl) {
- url = values.getAsString(History.URL);
+ url = filterSearchClient(values.getAsString(History.URL));
+ values.put(History.URL, url);
}
ContentValues imageValues = extractImageValues(values, url);