summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/drawable/progress_stop.pngbin0 -> 767 bytes
-rw-r--r--res/drawable/tab_selected_bg.9.pngbin0 -> 411 bytes
-rw-r--r--res/drawable/tab_unselected.xml22
-rw-r--r--res/drawable/tab_unselected_bg.9.pngbin0 -> 330 bytes
-rw-r--r--res/drawable/textfield_nostroke.xml22
-rw-r--r--res/layout-land/title_bar_tabbed.xml87
-rw-r--r--res/layout/simple_dropdown_item_2line.xml60
-rw-r--r--res/layout/tab_title.xml54
-rw-r--r--res/layout/title_bar_tabbed.xml97
-rw-r--r--res/layout/title_bar_xlarge.xml118
-rw-r--r--src/com/android/browser/BrowserActivity.java17
-rw-r--r--src/com/android/browser/BrowserBookmarksPage.java53
-rw-r--r--src/com/android/browser/BrowserProvider.java63
-rw-r--r--src/com/android/browser/CircularProgressView.java140
-rw-r--r--src/com/android/browser/Tab.java48
-rw-r--r--src/com/android/browser/TabControl.java49
-rw-r--r--src/com/android/browser/TabScrollView.java136
-rw-r--r--src/com/android/browser/TitleBarBase.java2
-rw-r--r--src/com/android/browser/TitleBarXLarge.java531
-rw-r--r--src/com/android/browser/UrlInputView.java206
20 files changed, 1444 insertions, 261 deletions
diff --git a/res/drawable/progress_stop.png b/res/drawable/progress_stop.png
new file mode 100644
index 0000000..a85f987
--- /dev/null
+++ b/res/drawable/progress_stop.png
Binary files differ
diff --git a/res/drawable/tab_selected_bg.9.png b/res/drawable/tab_selected_bg.9.png
new file mode 100644
index 0000000..5e6b1ed
--- /dev/null
+++ b/res/drawable/tab_selected_bg.9.png
Binary files differ
diff --git a/res/drawable/tab_unselected.xml b/res/drawable/tab_unselected.xml
new file mode 100644
index 0000000..1f22ae1
--- /dev/null
+++ b/res/drawable/tab_unselected.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#00000000"/>
+ <stroke android:width="3dp" android:color="#ff404040"/>
+ <padding android:left="9dp" android:top="9dp"
+ android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/drawable/tab_unselected_bg.9.png b/res/drawable/tab_unselected_bg.9.png
new file mode 100644
index 0000000..c19443a
--- /dev/null
+++ b/res/drawable/tab_unselected_bg.9.png
Binary files differ
diff --git a/res/drawable/textfield_nostroke.xml b/res/drawable/textfield_nostroke.xml
new file mode 100644
index 0000000..2945056
--- /dev/null
+++ b/res/drawable/textfield_nostroke.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#ffd0d0d0"/>
+ <stroke android:width="1dp" android:color="#ff94b73f"/>
+ <padding android:left="9dp" android:top="9dp"
+ android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/layout-land/title_bar_tabbed.xml b/res/layout-land/title_bar_tabbed.xml
new file mode 100644
index 0000000..853dbeb
--- /dev/null
+++ b/res/layout-land/title_bar_tabbed.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ Copyright 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tabbedtitleland"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="6dip"
+ android:paddingRight="6dip"
+ android:background="#ffdddddd">
+ <ImageButton
+ android:id="@+id/back"
+ android:src="@drawable/ic_arrow_left"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/forward"
+ android:src="@drawable/ic_arrow_right"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/star"
+ android:src="@drawable/ic_star"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <com.android.browser.TabScrollView
+ android:id="@+id/tabs"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" />
+ <com.android.browser.UrlInputView
+ android:id="@+id/editurl"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/black"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:lines="1"
+ android:scrollHorizontally="true"
+ android:visibility="gone"
+ android:background="@drawable/textfield_stroke"
+ android:inputType="textUri"
+ android:imeOptions="actionGo" />
+ <ImageButton
+ android:id="@+id/newtab"
+ android:src="@drawable/ic_menu_new_window"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/menu"
+ android:src="@drawable/ic_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/all_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:scaleType="center"
+ android:background="@drawable/browserbarbutton"
+ android:src="@drawable/ic_pages" />
+</LinearLayout>
diff --git a/res/layout/simple_dropdown_item_2line.xml b/res/layout/simple_dropdown_item_2line.xml
new file mode 100644
index 0000000..8b955ec
--- /dev/null
+++ b/res/layout/simple_dropdown_item_2line.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:baselineAligned="false">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/icon1"
+ android:scaleType="center"
+ android:paddingLeft="2dip"
+ android:paddingRight="2dip" />
+ <TwoLineListItem
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:mode="twoLine">
+ <TextView
+ android:id="@android:id/text1"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@android:id/text2"
+ style="?android:attr/dropDownItemStyle"
+ android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ android:textColor="#323232"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_alignLeft="@android:id/text1" />
+ </TwoLineListItem>
+</LinearLayout>
diff --git a/res/layout/tab_title.xml b/res/layout/tab_title.xml
new file mode 100644
index 0000000..28b553d
--- /dev/null
+++ b/res/layout/tab_title.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ Copyright 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/favicon"
+ android:layout_width="20dip"
+ android:layout_height="20dip"
+ android:layout_marginLeft="3dip" />
+ <ImageView
+ android:id="@+id/lock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:visibility="gone" />
+ <TextView
+ android:id="@+id/title"
+ android:layout_height="wrap_content"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_marginLeft="3dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/black"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end" />
+ <com.android.browser.CircularProgressView
+ android:id="@+id/stop"
+ android:layout_width="36dip"
+ android:layout_height="36dip"
+ android:background="@null"
+ android:src="@drawable/progress_stop" />
+ <ImageView
+ android:id="@+id/close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:src="@drawable/btn_close_window" />
+</LinearLayout>
diff --git a/res/layout/title_bar_tabbed.xml b/res/layout/title_bar_tabbed.xml
new file mode 100644
index 0000000..fc786e0
--- /dev/null
+++ b/res/layout/title_bar_tabbed.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ Copyright 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.
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tabbedtitleport"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="#ffdddddd">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <com.android.browser.TabScrollView
+ android:id="@+id/tabs"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ 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:background="@drawable/browserbarbutton" />
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/urlbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="6dip"
+ android:paddingRight="6dip">
+ <ImageButton
+ android:id="@+id/back"
+ android:src="@drawable/ic_arrow_left"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/forward"
+ android:src="@drawable/ic_arrow_right"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/star"
+ android:src="@drawable/ic_star"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <com.android.browser.UrlInputView
+ android:id="@+id/editurl"
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/black"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:lines="1"
+ android:scrollHorizontally="true"
+ android:visibility="gone"
+ android:background="@drawable/textfield_nostroke"
+ android:inputType="textUri"
+ android:imeOptions="actionGo" />
+ <ImageButton
+ android:id="@+id/menu"
+ android:src="@drawable/ic_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="6dip"
+ android:background="@drawable/browserbarbutton" />
+ <ImageButton
+ android:id="@+id/all_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:scaleType="center"
+ android:background="@drawable/browserbarbutton"
+ android:src="@drawable/ic_pages" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/title_bar_xlarge.xml b/res/layout/title_bar_xlarge.xml
deleted file mode 100644
index 3070b8b..0000000
--- a/res/layout/title_bar_xlarge.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:background="#ffdddddd" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingLeft="6dip"
- android:paddingRight="6dip"
- >
- <ImageButton android:id="@+id/back"
- android:src="@drawable/ic_arrow_left"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginRight="6dip"
- android:background="@drawable/browserbarbutton"
- />
- <ImageButton android:id="@+id/forward"
- android:src="@drawable/ic_arrow_right"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginRight="6dip"
- android:background="@drawable/browserbarbutton"
- />
- <ImageButton android:id="@+id/star"
- android:src="@drawable/ic_star"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginRight="6dip"
- android:background="@drawable/browserbarbutton"
- />
-
- <LinearLayout android:id="@+id/title_bg"
- android:background="@drawable/textfield_stroke"
- android:layout_width="0dip"
- android:layout_weight="1.0"
- android:layout_height="wrap_content"
- android:layout_marginRight="6dip"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- >
- <ImageView android:id="@+id/favicon"
- android:layout_width="20dip"
- android:layout_height="20dip"
- android:layout_marginLeft="3dip"
- />
- <ImageView android:id="@+id/lock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="6dip"
- android:visibility="gone"
- />
- <TextView
- android:id="@+id/title"
- android:layout_height="wrap_content"
- android:layout_width="0dip"
- android:layout_weight="1.0"
- android:layout_marginLeft="3dip"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/black"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="end"
- />
- </LinearLayout>
- <ImageButton android:id="@+id/stop"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginRight="6dip"
- android:src="@drawable/ic_stop"
- android:background="@drawable/browserbarbutton"
- />
- <ImageButton android:id="@+id/menu"
- android:src="@drawable/ic_menu"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginRight="6dip"
- android:background="@drawable/browserbarbutton"
- />
- <ImageButton
- android:id="@+id/all_btn"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:scaleType="center"
- android:background="@drawable/browserbarbutton"
- android:src="@drawable/ic_pages"
- />
- </LinearLayout>
-
- <!-- Should show translucent over the webpage -->
- <ProgressBar android:id="@+id/progress_horizontal"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="14dip"
- android:max="100"
- />
-
-</LinearLayout>
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index ad82fd0..8afd3b4 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -121,9 +121,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.Vector;
public class BrowserActivity extends Activity
implements View.OnCreateContextMenuListener, DownloadListener {
@@ -214,8 +214,12 @@ public class BrowserActivity extends Activity
& Configuration.SCREENLAYOUT_SIZE_MASK)
== Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ // Create the tab control and our initial tab
+ mTabControl = new TabControl(this);
+
+
if (mXLargeScreenSize) {
- mTitleBar = new TitleBarXLarge(this);
+ mTitleBar = new TitleBarXLarge(this, mTabControl);
LinearLayout layout = (LinearLayout) mBrowserFrameLayout.
findViewById(R.id.vertical_layout);
layout.addView(mTitleBar, 0, new LinearLayout.LayoutParams(
@@ -230,8 +234,6 @@ public class BrowserActivity extends Activity
mFakeTitleBar = new TitleBar(this);
}
- // Create the tab control and our initial tab
- mTabControl = new TabControl(this);
// Open the icon database and retain all the bookmark urls for favicons
retainIconsOnStartup();
@@ -851,6 +853,12 @@ public class BrowserActivity extends Activity
return true;
}
+ private void rebuildTitleBar() {
+ if (mXLargeScreenSize) {
+ ((TitleBarXLarge) mTitleBar).rebuildLayout();
+ }
+ }
+
private void showFakeTitleBar() {
if (mXLargeScreenSize) return;
if (mFakeTitleBar.getParent() == null && mActiveTabsPage == null
@@ -1060,6 +1068,7 @@ public class BrowserActivity extends Activity
showHttpAuthentication(mHttpAuthHandler, null, null, title,
name, password, focusId);
}
+ rebuildTitleBar();
}
@Override
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index 320c438..6af14e8 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -23,16 +23,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
@@ -53,6 +43,7 @@ import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.Toast;
+import android.widget.AdapterView.OnItemClickListener;
/*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
/**
@@ -269,13 +260,14 @@ public class BrowserBookmarksPage extends Activity implements
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... unused) {
- BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
- BrowserBookmarksPage.this,
- url,
- title,
- thumbnail,
- createShortcut,
- mostVisited);
+ BrowserBookmarksAdapter adapter =
+ new BrowserBookmarksAdapter(
+ BrowserBookmarksPage.this,
+ url,
+ title,
+ thumbnail,
+ createShortcut,
+ mostVisited);
mHandler.obtainMessage(ADAPTER_CREATED, adapter).sendToTarget();
return null;
}
@@ -352,7 +344,7 @@ public class BrowserBookmarksPage extends Activity implements
}
listView.setDrawSelectorOnTop(false);
listView.setVerticalScrollBarEnabled(true);
- listView.setOnItemClickListener(mListener);
+ listView.setOnItemClickListener(mListListener);
if (mMostVisited) {
listView.setEmptyView(mEmptyView);
}
@@ -416,7 +408,29 @@ public class BrowserBookmarksPage extends Activity implements
}
};
- private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
+ private OnItemClickListener mListener = new OnItemClickListener() {
+ public void onItemClick(AdapterView parent, View v, int position, long id) {
+ // It is possible that the view has been canceled when we get to
+ // this point as back has a higher priority
+ if (mCanceled) {
+ android.util.Log.e(LOGTAG, "item clicked when dismissing");
+ return;
+ }
+ if (!mCreateShortcut) {
+ if (0 == position && !mMostVisited) {
+ // XXX: Work-around for a framework issue.
+ mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
+ } else {
+ loadUrl(position);
+ }
+ } else {
+ setResultToParent(RESULT_OK, createShortcutIntent(position));
+ finish();
+ }
+ }
+ };
+
+ private OnItemClickListener mListListener = new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
// It is possible that the view has been canceled when we get to
// this point as back has a higher priority
@@ -658,4 +672,5 @@ public class BrowserBookmarksPage extends Activity implements
resultCode, data);
}
}
+
}
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index 1eec52b..7064180 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -29,8 +29,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.UriMatcher;
import android.content.SharedPreferences.Editor;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
import android.database.AbstractCursor;
import android.database.ContentObserver;
import android.database.Cursor;
@@ -47,8 +46,6 @@ import android.speech.RecognizerResultsIntent;
import android.text.TextUtils;
import android.util.Log;
import android.util.Patterns;
-import android.util.TypedValue;
-
import java.io.File;
import java.io.FilenameFilter;
@@ -91,6 +88,17 @@ public class BrowserProvider extends ContentProvider {
private static final int SUGGEST_COLUMN_QUERY_ID = 8;
private static final int SUGGEST_COLUMN_INTENT_EXTRA_DATA = 9;
+ // how many suggestions will be shown in dropdown
+ // 0..SHORT: filled by browser db
+ private static final int MAX_SUGGEST_SHORT_SMALL = 3;
+ // SHORT..LONG: filled by search suggestions
+ private static final int MAX_SUGGEST_LONG_SMALL = 6;
+
+ // large screen size shows more
+ private static final int MAX_SUGGEST_SHORT_LARGE = 6;
+ private static final int MAX_SUGGEST_LONG_LARGE = 9;
+
+
// shared suggestion columns
private static final String[] COLUMNS = new String[] {
"_id",
@@ -104,10 +112,6 @@ public class BrowserProvider extends ContentProvider {
SearchManager.SUGGEST_COLUMN_QUERY,
SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA};
- private static final int MAX_SUGGESTION_SHORT_ENTRIES = 3;
- private static final int MAX_SUGGESTION_LONG_ENTRIES = 6;
- private static final String MAX_SUGGESTION_LONG_ENTRIES_STRING =
- Integer.valueOf(MAX_SUGGESTION_LONG_ENTRIES).toString();
// make sure that these match the index of TABLE_NAMES
private static final int URI_MATCH_BOOKMARKS = 0;
@@ -167,6 +171,9 @@ public class BrowserProvider extends ContentProvider {
private SearchManager mSearchManager;
+ private int mMaxSuggestionShortSize;
+ private int mMaxSuggestionLongSize;
+
public BrowserProvider() {
}
@@ -350,6 +357,20 @@ public class BrowserProvider extends ContentProvider {
@Override
public boolean onCreate() {
final Context context = getContext();
+ boolean xlargeScreenSize = (context.getResources().getConfiguration().screenLayout
+ & Configuration.SCREENLAYOUT_SIZE_MASK)
+ == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ boolean isPortrait = (context.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT);
+
+
+ if (xlargeScreenSize && isPortrait) {
+ mMaxSuggestionLongSize = MAX_SUGGEST_LONG_LARGE;
+ mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_LARGE;
+ } else {
+ mMaxSuggestionLongSize = MAX_SUGGEST_LONG_SMALL;
+ mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_SMALL;
+ }
mOpenHelper = new DatabaseHelper(context);
mBackupManager = new BackupManager(context);
// we added "picasa web album" into default bookmarks for version 19.
@@ -467,8 +488,8 @@ public class BrowserProvider extends ContentProvider {
mSuggestCursor = sc;
mHistoryCount = hc != null ? hc.getCount() : 0;
mSuggestionCount = sc != null ? sc.getCount() : 0;
- if (mSuggestionCount > (MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount)) {
- mSuggestionCount = MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount;
+ if (mSuggestionCount > (mMaxSuggestionLongSize - mHistoryCount)) {
+ mSuggestionCount = mMaxSuggestionLongSize - mHistoryCount;
}
mString = string;
mIncludeWebSearch = string.length() > 0;
@@ -682,6 +703,7 @@ public class BrowserProvider extends ContentProvider {
}
// TODO Temporary change, finalize after jq's changes go in
+ @Override
public void deactivate() {
if (mHistoryCursor != null) {
mHistoryCursor.deactivate();
@@ -692,12 +714,14 @@ public class BrowserProvider extends ContentProvider {
super.deactivate();
}
+ @Override
public boolean requery() {
return (mHistoryCursor != null ? mHistoryCursor.requery() : false) |
(mSuggestCursor != null ? mSuggestCursor.requery() : false);
}
// TODO Temporary change, finalize after jq's changes go in
+ @Override
public void close() {
super.close();
if (mHistoryCursor != null) {
@@ -762,12 +786,15 @@ public class BrowserProvider extends ContentProvider {
public ResultsCursor(ArrayList<String> results) {
mResults = results;
}
+ @Override
public int getCount() { return mResults.size(); }
+ @Override
public String[] getColumnNames() {
return RESULTS_COLUMNS;
}
+ @Override
public String getString(int column) {
switch (column) {
case RESULT_ACTION_ID:
@@ -789,24 +816,30 @@ public class BrowserProvider extends ContentProvider {
return null;
}
}
+ @Override
public short getShort(int column) {
throw new UnsupportedOperationException();
}
+ @Override
public int getInt(int column) {
throw new UnsupportedOperationException();
}
+ @Override
public long getLong(int column) {
if ((mPos != -1) && column == 0) {
return mPos; // use row# as the _id
}
throw new UnsupportedOperationException();
}
+ @Override
public float getFloat(int column) {
throw new UnsupportedOperationException();
}
+ @Override
public double getDouble(int column) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean isNull(int column) {
throw new UnsupportedOperationException();
}
@@ -868,7 +901,7 @@ public class BrowserProvider extends ContentProvider {
Cursor c = db.query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
- ORDER_BY, MAX_SUGGESTION_LONG_ENTRIES_STRING);
+ ORDER_BY, Integer.toString(mMaxSuggestionLongSize));
if (match == URI_MATCH_BOOKMARKS_SUGGEST
|| Patterns.WEB_URL.matcher(selectionArgs[0]).matches()) {
@@ -877,7 +910,7 @@ public class BrowserProvider extends ContentProvider {
// get Google suggest if there is still space in the list
if (myArgs != null && myArgs.length > 1
&& mSearchableInfo != null
- && c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) {
+ && c.getCount() < (mMaxSuggestionShortSize - 1)) {
Cursor sc = mSearchManager.getSuggestions(mSearchableInfo, selectionArgs[0]);
return new MySuggestionCursor(c, sc, selectionArgs[0]);
}
@@ -1120,4 +1153,10 @@ public class BrowserProvider extends ContentProvider {
}
}
+ public static Cursor getBookmarksSuggestions(ContentResolver cr, String constraint) {
+ Uri uri = Uri.parse("content://browser/" + SearchManager.SUGGEST_URI_PATH_QUERY);
+ return cr.query(uri, SUGGEST_PROJECTION, SUGGEST_SELECTION,
+ new String[] { constraint }, ORDER_BY);
+ }
+
}
diff --git a/src/com/android/browser/CircularProgressView.java b/src/com/android/browser/CircularProgressView.java
new file mode 100644
index 0000000..48f293a
--- /dev/null
+++ b/src/com/android/browser/CircularProgressView.java
@@ -0,0 +1,140 @@
+
+/*
+ * 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.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+/**
+ *
+ */
+public class CircularProgressView extends ImageButton {
+
+ private static final int[] ALPHAS = {
+ 64, 96, 128, 160, 192, 192, 160, 128, 96, 64
+ };
+
+ // 100 ms delay between frames, 10fps
+ private static int ALPHA_REFRESH_DELAY = 100;
+
+ private int mEndAngle;
+ private int mProgress;
+ private Paint mPaint;
+ private int mAlpha;
+ private boolean mAnimated;
+ private RectF mRect;
+ private int mMaxProgress;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public CircularProgressView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public CircularProgressView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ /**
+ * @param context
+ */
+ public CircularProgressView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ private void init(Context ctx) {
+ mEndAngle = 0;
+ mProgress = 0;
+ mMaxProgress = 100;
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setColor(Color.BLACK);
+ mRect = new RectF();
+ }
+
+ void setMaxProgress(int max) {
+ mMaxProgress = max;
+ }
+
+ private synchronized boolean isAnimated() {
+ return mAnimated;
+ }
+
+ private synchronized void setAnimated(boolean animated) {
+ mAnimated = animated;
+ }
+
+ void setProgress(int progress) {
+ mProgress = progress;
+ mEndAngle = 360 * progress / mMaxProgress;
+ invalidate();
+ if (!isAnimated() && (progress > 0) && (progress < mMaxProgress)) {
+ setAnimated(true);
+ mAlpha = 0;
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (isAnimated()) {
+ mAlpha = (mAlpha + 1) % ALPHAS.length;
+ mPaint.setAlpha(ALPHAS[mAlpha]);
+ invalidate();
+ postDelayed(this, ALPHA_REFRESH_DELAY);
+ }
+ }
+ });
+ } else if ((progress <= 0) || (progress >= mMaxProgress)) {
+ setAnimated(false);
+ }
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ int w = getWidth();
+ int h = getHeight();
+ float cx = w * 0.5f;
+ float cy = h * 0.5f;
+ mRect.set(0, 0, w, h);
+ if ((mProgress > 0) && (mProgress < mMaxProgress)) {
+ Path p = new Path();
+ p.moveTo(cx, cy);
+ p.lineTo(cx, 0);
+ p.arcTo(mRect, 270, mEndAngle);
+ p.lineTo(cx, cy);
+ int state = canvas.save();
+ canvas.drawPath(p, mPaint);
+ canvas.restoreToCount(state);
+ }
+ super.onDraw(canvas);
+ }
+
+}
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 6b74a6c..1d9482b 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -16,21 +16,13 @@
package com.android.browser;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Vector;
-
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
+import android.content.DialogInterface.OnCancelListener;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
@@ -71,8 +63,17 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.browser.TabControl.TabChangeListener;
import com.android.common.speech.LoggingEvents;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Vector;
+
/**
* Class for maintaining Tabs with a main WebView and a subwindow.
*/
@@ -502,6 +503,9 @@ class Tab {
if (mInForeground) {
mActivity.onPageStarted(view, url, favicon);
}
+ if (getTabChangeListener() != null) {
+ getTabChangeListener().onPageStarted(Tab.this);
+ }
}
@Override
@@ -523,6 +527,9 @@ class Tab {
if (mInForeground) {
mActivity.onPageFinished(view, url);
}
+ if (getTabChangeListener() != null) {
+ getTabChangeListener().onPageFinished(Tab.this);
+ }
}
// return true if want to hijack the url to let another app to handle it
@@ -672,6 +679,7 @@ class Tab {
final ContentResolver cr = mActivity.getContentResolver();
final String newUrl = url;
new AsyncTask<Void, Void, Void>() {
+ @Override
protected Void doInBackground(Void... unused) {
Browser.updateVisitedHistory(cr, newUrl, true);
return null;
@@ -948,6 +956,9 @@ class Tab {
if (mInForeground) {
mActivity.onProgressChanged(view, newProgress);
}
+ if (getTabChangeListener() != null) {
+ getTabChangeListener().onProgress(Tab.this, newProgress);
+ }
}
@Override
@@ -957,11 +968,16 @@ class Tab {
// here, if url is null, we want to reset the title
mActivity.setUrlTitle(pageUrl, title);
}
+ TabChangeListener tcl = getTabChangeListener();
+ if (tcl != null) {
+ tcl.onUrlAndTitle(Tab.this, pageUrl,title);
+ }
if (pageUrl == null || pageUrl.length()
>= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
return;
}
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.
@@ -1020,6 +1036,9 @@ class Tab {
if (mInForeground) {
mActivity.setFavicon(icon);
}
+ if (getTabChangeListener() != null) {
+ getTabChangeListener().onFavicon(Tab.this, icon);
+ }
}
@Override
@@ -1208,10 +1227,12 @@ class Tab {
@Override
public void getVisitedHistory(final ValueCallback<String[]> callback) {
AsyncTask<Void, Void, String[]> task = new AsyncTask<Void, Void, String[]>() {
+ @Override
public String[] doInBackground(Void... unused) {
return Browser.getVisitedHistory(mActivity
.getContentResolver());
}
+ @Override
public void onPostExecute(String[] result) {
callback.onReceiveValue(result);
};
@@ -1990,4 +2011,13 @@ class Tab {
LinearLayout parent = (LinearLayout) dialog.getParent();
if (parent != null) parent.removeView(dialog);
}
+
+ /**
+ * always get the TabChangeListener form the tab control
+ * @return the TabControl change listener
+ */
+ private TabChangeListener getTabChangeListener() {
+ return mActivity.getTabControl().getTabChangeListener();
+ }
+
}
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index afd4ea8..0fbdd7a 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -132,7 +132,7 @@ class TabControl {
int getCurrentIndex() {
return mCurrentTab;
}
-
+
/**
* Given a Tab, find it's index
* @param Tab to find
@@ -167,6 +167,9 @@ class TabControl {
mTabs.add(t);
// Initially put the tab in the background.
t.putInBackground();
+ if (mTabChangeListener != null) {
+ mTabChangeListener.onNewTab(t);
+ }
return t;
}
@@ -231,6 +234,9 @@ class TabControl {
// Remove it from the queue of viewed tabs.
mTabQueue.remove(t);
+ if (mTabChangeListener != null) {
+ mTabChangeListener.onRemoveTab(t);
+ }
return true;
}
@@ -617,6 +623,47 @@ class TabControl {
mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
}
}
+ if (mTabChangeListener != null) {
+ mTabChangeListener.onCurrentTab(newTab);
+ }
return true;
}
+
+ interface TabChangeListener {
+
+ public void onNewTab(Tab tab);
+
+ public void onRemoveTab(Tab tab);
+
+ public void onCurrentTab(Tab tab);
+
+ public void onProgress(Tab tab, int progress);
+
+ public void onUrlAndTitle(Tab tab, String url, String title);
+
+ public void onFavicon(Tab tab, Bitmap favicon);
+
+ public void onPageStarted(Tab tab);
+
+ public void onPageFinished(Tab tab);
+
+ }
+
+ private TabChangeListener mTabChangeListener;
+
+ /**
+ * register the TabChangeListener with the tab control
+ * @param listener
+ */
+ void setOnTabChangeListener(TabChangeListener listener) {
+ mTabChangeListener = listener;
+ }
+
+ /**
+ * get the current TabChangeListener (used by the tabs)
+ */
+ TabChangeListener getTabChangeListener() {
+ return mTabChangeListener;
+ }
+
}
diff --git a/src/com/android/browser/TabScrollView.java b/src/com/android/browser/TabScrollView.java
new file mode 100644
index 0000000..6d8b91b
--- /dev/null
+++ b/src/com/android/browser/TabScrollView.java
@@ -0,0 +1,136 @@
+/*
+ * 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.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+
+/**
+ * custom view for displaying tabs in the tabbed title bar
+ */
+public class TabScrollView extends HorizontalScrollView {
+
+ private Context mContext;
+
+ private LinearLayout mContentView;
+
+ private int mSelected;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public TabScrollView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public TabScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ /**
+ * @param context
+ */
+ public TabScrollView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ private void init(Context ctx) {
+ mContext = ctx;
+ setHorizontalScrollBarEnabled(false);
+ mContentView = new LinearLayout(mContext);
+ mContentView.setOrientation(LinearLayout.HORIZONTAL);
+ mContentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT));
+ addView(mContentView);
+ mSelected = -1;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ ensureChildVisible(getSelectedTab());
+ }
+
+ void setSelectedTab(int position) {
+ View v = getSelectedTab();
+ if (v != null) {
+ v.setSelected(false);
+ }
+ mSelected = position;
+ v = getSelectedTab();
+ if (v != null) {
+ v.setSelected(true);
+ }
+ requestLayout();
+ }
+
+ View getSelectedTab() {
+ if ((mSelected >= 0) && (mSelected < mContentView.getChildCount())) {
+ return mContentView.getChildAt(mSelected);
+ } else {
+ return null;
+ }
+ }
+
+ void clearTabs() {
+ mContentView.removeAllViews();
+ }
+
+ void addTab(View tab) {
+ mContentView.addView(tab);
+ tab.setSelected(false);
+ }
+
+ void addTab(View tab, int pos) {
+ mContentView.addView(tab, pos);
+ tab.setSelected(false);
+ }
+
+ void removeTab(View tab) {
+ mContentView.removeView(tab);
+ }
+
+ void ensureChildVisible(View child) {
+ if (child != null) {
+ int childl = child.getLeft();
+ int childr = childl + child.getWidth();
+ int viewl = getScrollX();
+ int viewr = viewl + getWidth();
+ if (childl < viewl) {
+ // need scrolling to left
+ scrollTo(childl, 0);
+ } else if (childr > viewr) {
+ // need scrolling to right
+ scrollTo(childr - viewr + viewl, 0);
+ }
+ }
+ }
+
+
+}
diff --git a/src/com/android/browser/TitleBarBase.java b/src/com/android/browser/TitleBarBase.java
index 3d234e8..7016dc0 100644
--- a/src/com/android/browser/TitleBarBase.java
+++ b/src/com/android/browser/TitleBarBase.java
@@ -35,7 +35,7 @@ public class TitleBarBase extends LinearLayout {
protected ImageView mFavicon;
protected ImageView mLockIcon;
- private Drawable mGenericFavicon;
+ protected Drawable mGenericFavicon;
public TitleBarBase(Context context) {
super(context, null);
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;
-
- 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;
-
- public TitleBarXLarge(BrowserActivity context) {
+public class TitleBarXLarge extends TitleBarBase
+ implements TabChangeListener, UrlInputListener {
+
+ private static final int PROGRESS_MAX = 100;
+
+ 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;
+ 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);
+ }
- mTitle = (TextView) findViewById(R.id.title);
- mTitle.setCompoundDrawablePadding(5);
- mTitle.setLongClickable(true);
+ void rebuildLayout() {
+ rebuildLayout(mBrowserActivity, false);
+ }
- mLockIcon = (ImageView) findViewById(R.id.lock);
- mFavicon = (ImageView) findViewById(R.id.favicon);
- mStopButton = (ImageView) findViewById(R.id.stop);
- mStopDrawable = mStopButton.getDrawable();
- mReloadDrawable = resources.getDrawable(R.drawable.ic_reload);
+ private void rebuildLayout(Context context, boolean rebuildData) {
+ removeAllViews();
+ LayoutInflater factory = LayoutInflater.from(context);
+ factory.inflate(R.layout.title_bar_tabbed, 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));
-
- // FIXME: Change enabled states based on whether you can go
+ 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 @@ public class TitleBarXLarge extends TitleBarBase {
mBrowserActivity.onCreateContextMenu(menu, this, null);
}
+ @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 progress, from 0 to 100.
*/
+ @Override
/* 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);
+ // this is handled in tab specific callback
+ }
+
+ @Override
+ /* package */ void setDisplayTitle(String title) {
+ // 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 {
- 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);
- }
+ 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;
}
/**
- * Update the text displayed in the title bar.
- * @param title String to display. If null, the loading string will be
- * shown.
+ * the views used in the tab bar
*/
- /* package */ void setDisplayTitle(String title) {
- if (title == null) {
- mTitle.setText(R.string.title_bar_loading);
- } else {
+ 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) {
}
}
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
new file mode 100644
index 0000000..3841257
--- /dev/null
+++ b/src/com/android/browser/UrlInputView.java
@@ -0,0 +1,206 @@
+/*
+ * 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.app.SearchManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.AutoCompleteTextView;
+import android.widget.CursorAdapter;
+import android.widget.Filterable;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * url/search input view
+ * handling suggestions
+ */
+public class UrlInputView extends AutoCompleteTextView {
+
+ private UrlInputListener mListener;
+ private InputMethodManager mInputManager;
+ private SuggestionsAdapter mAdapter;
+ private Drawable mFocusDrawable;
+ private Drawable mNoFocusDrawable;
+
+
+ public UrlInputView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ public UrlInputView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public UrlInputView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ private void init(Context ctx) {
+ mFocusDrawable = ctx.getResources().getDrawable(R.drawable.textfield_stroke);
+ mNoFocusDrawable = ctx.getResources().getDrawable(R.drawable.textfield_nostroke);
+ mInputManager = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
+ setOnEditorActionListener(new OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ finishInput(getText().toString());
+ return true;
+ }
+ });
+ setOnFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ setBackgroundDrawable(hasFocus ? mFocusDrawable : mNoFocusDrawable);
+ }
+ });
+ final ContentResolver cr = mContext.getContentResolver();
+ mAdapter = new SuggestionsAdapter(mContext,
+ BrowserProvider.getBookmarksSuggestions(cr, null));
+ setAdapter(mAdapter);
+ setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ String url = mAdapter.getViewString(view);
+ finishInput(url);
+ }
+ });
+ setSelectAllOnFocus(true);
+ }
+
+ public void setUrlInputListener(UrlInputListener listener) {
+ mListener = listener;
+ }
+
+ public void forceIme() {
+ mInputManager.showSoftInput(this, 0);
+ }
+
+ private void finishInput(String url) {
+ this.dismissDropDown();
+ mInputManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ if (url == null) {
+ mListener.onDismiss();
+ } else {
+ mListener.onAction(url);
+ }
+
+ }
+
+ @Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent evt) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ // catch back key in order to do slightly more cleanup than usual
+ finishInput(null);
+ return true;
+ }
+ return super.onKeyPreIme(keyCode, evt);
+ }
+
+ interface UrlInputListener {
+
+ public void onDismiss();
+
+ public void onAction(String text);
+
+ }
+
+ /**
+ * adapter used by suggestion dropdown
+ */
+ class SuggestionsAdapter extends CursorAdapter implements Filterable {
+
+ private Cursor mLastCursor;
+ private ContentResolver mContent;
+ private int mIndexText1;
+ private int mIndexText2;
+ private int mIndexIcon;
+
+ public SuggestionsAdapter(Context context, Cursor c) {
+ super(context, c);
+ mContent = context.getContentResolver();
+ mIndexText1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
+ mIndexText2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
+ mIndexIcon = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
+ }
+
+ public String getViewString(View view) {
+ TextView tv2 = (TextView) view.findViewById(android.R.id.text2);
+ if (tv2.getText().length() > 0) {
+ return tv2.getText().toString();
+ } else {
+ TextView tv1 = (TextView) view.findViewById(android.R.id.text1);
+ return tv1.getText().toString();
+ }
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final View view = inflater.inflate(
+ R.layout.simple_dropdown_item_2line, parent, false);
+ bindView(view, context, cursor);
+ return view;
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ TextView tv1 = (TextView) view.findViewById(android.R.id.text1);
+ TextView tv2 = (TextView) view.findViewById(android.R.id.text2);
+ ImageView ic1 = (ImageView) view.findViewById(R.id.icon1);
+ tv1.setText(cursor.getString(mIndexText1));
+ String url = cursor.getString(mIndexText2);
+ tv2.setText((url != null) ? url : "");
+ // assume an id
+ try {
+ int id = Integer.parseInt(cursor.getString(mIndexIcon));
+ Drawable d = context.getResources().getDrawable(id);
+ ic1.setImageDrawable(d);
+ } catch (NumberFormatException nfx) {
+ }
+ }
+
+ @Override
+ public String convertToString(Cursor cursor) {
+ return cursor.getString(mIndexText1);
+ }
+
+ @Override
+ public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+ if (getFilterQueryProvider() != null) {
+ return getFilterQueryProvider().runQuery(constraint);
+ }
+ mLastCursor = BrowserProvider.getBookmarksSuggestions(mContent,
+ (constraint != null) ? constraint.toString() : null);
+ return mLastCursor;
+ }
+
+ }
+
+}