Merge change 646
* changes:
Use ViewStub for setEmptyView (bug 1803058)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c67cc97..ace5750 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -176,6 +176,19 @@
android:theme="@android:style/Theme.Dialog">
</activity>
+ <activity android:name="BookmarkSearch"
+ android:label="@string/bookmarks_search"
+ android:stateNotNeeded="true"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:excludeFromRecents="true">
+ <intent-filter>
+ <action android:name="android.intent.action.SEARCH" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="android.app.searchable"
+ android:resource="@xml/bookmarks_searchable" />
+ </activity>
+
<service android:name="GearsDialogService"
android:process=":dialog"
android:exported="false">
diff --git a/res/drawable/ic_search_category_bookmark.png b/res/drawable/ic_search_category_bookmark.png
index 08b5e74..45755ff 100755
--- a/res/drawable/ic_search_category_bookmark.png
+++ b/res/drawable/ic_search_category_bookmark.png
Binary files differ
diff --git a/res/drawable/ic_search_category_history.png b/res/drawable/ic_search_category_history.png
index 894c254..e5c45f7 100755
--- a/res/drawable/ic_search_category_history.png
+++ b/res/drawable/ic_search_category_history.png
Binary files differ
diff --git a/res/drawable/ic_search_category_suggest.png b/res/drawable/ic_search_category_suggest.png
index ada07e6..a4ed7aa 100755
--- a/res/drawable/ic_search_category_suggest.png
+++ b/res/drawable/ic_search_category_suggest.png
Binary files differ
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index fd9e65c..95dcec0 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -18,7 +18,7 @@
<string name="application_name">"瀏覽器"</string>
<string name="tab_bookmarks">"書籤"</string>
<string name="tab_most_visited">"常用網頁"</string>
- <string name="tab_history">"紀錄"</string>
+ <string name="tab_history">"記錄"</string>
<string name="added_to_bookmarks">"已加入書籤"</string>
<string name="removed_from_bookmarks">"已自書籤中移除"</string>
<string name="sign_in_to">"登入到 <xliff:g id="HOSTNAME">%s1</xliff:g>「<xliff:g id="REALM">%s2</xliff:g>」"</string>
@@ -27,10 +27,12 @@
<string name="action">"登入"</string>
<string name="cancel">"取消"</string>
<string name="ok">"確定"</string>
- <!-- no translation found for matches_found:zero (6242659159545399963) -->
- <!-- no translation found for matches_found:one (4352019729062956802) -->
- <!-- no translation found for matches_found:few (5544267486978946555) -->
- <!-- no translation found for matches_found:other (6616125067364315405) -->
+ <plurals name="matches_found">
+ <item quantity="zero">"沒有相配項"</item>
+ <item quantity="one">"1 個相配項"</item>
+ <item quantity="few">"<xliff:g id="NUMBER">%d</xliff:g> 個相配項"</item>
+ <item quantity="other">"<xliff:g id="NUMBER">%d</xliff:g> 個相配項"</item>
+ </plurals>
<string name="page_info">"頁面資訊"</string>
<string name="page_info_view">"檢視頁面資訊"</string>
<string name="page_info_address">"位址:"</string>
@@ -67,16 +69,16 @@
<string name="create_shortcut_bookmark">"新增捷徑至首頁"</string>
<string name="open_bookmark">"開啟"</string>
<string name="remove_bookmark">"刪除書籤"</string>
- <string name="remove_history_item">"從紀錄中移除"</string>
- <string name="bookmark_saved">"儲存至書籤。"</string>
- <string name="bookmark_needs_title">"請輸入書籤名字。"</string>
+ <string name="remove_history_item">"從記錄中移除"</string>
+ <string name="bookmark_saved">"已儲存至書籤。"</string>
+ <string name="bookmark_needs_title">"請輸入書籤名稱。"</string>
<string name="bookmark_needs_url">"請選取書籤位置。"</string>
<string name="empty_bookmark">"無法建立空白書籤。"</string>
<string name="bookmark_url_not_valid">"網址無效。"</string>
<string name="delete_bookmark">"刪除"</string>
- <string name="bookmark_page">"最後瀏覽的書籤頁面"</string>
+ <string name="bookmark_page">"將最後瀏覽的網頁加入書籤"</string>
<string name="current_page">"來源 "</string>
- <string name="delete_bookmark_warning">"<xliff:g id="BOOKMARK">%s</xliff:g>"</string>
+ <string name="delete_bookmark_warning">"刪除「<xliff:g id="BOOKMARK">%s</xliff:g>」書籤?"</string>
<string name="open_in_new_window">"在新視窗開啟"</string>
<string name="new_window">"新視窗"</string>
<string name="goto_dot">"前往"</string>
@@ -88,16 +90,16 @@
<string name="tab_picker_view_tab">"檢視"</string>
<string name="tab_picker_new_tab">"新視窗"</string>
<string name="tab_picker_remove_tab">"關閉"</string>
- <string name="tab_picker_bookmark">"書籤"</string>
+ <string name="tab_picker_bookmark">"加入書籤"</string>
<string name="tab_picker_send_url">"分享連結"</string>
<string name="bookmarks">"書籤"</string>
<string name="shortcut_bookmark">"書籤"</string>
- <string name="history">"紀錄"</string>
+ <string name="history">"記錄"</string>
<string name="menu_view_download">"下載"</string>
<string name="share_page">"分享網頁"</string>
<string name="contextmenu_openlink">"開啟"</string>
<string name="contextmenu_openlink_newwindow">"在新視窗開啟"</string>
- <string name="contextmenu_bookmark_thislink">"書籤連結"</string>
+ <string name="contextmenu_bookmark_thislink">"將連結加入書籤"</string>
<string name="contextmenu_savelink">"儲存連結"</string>
<string name="contextmenu_sharelink">"分享連結"</string>
<string name="contextmenu_copy">"複製"</string>
@@ -105,7 +107,7 @@
<string name="contextmenu_download_image">"儲存圖片"</string>
<string name="contextmenu_view_image">"檢視圖片"</string>
<string name="contextmenu_dial_dot">"撥打…"</string>
- <string name="contextmenu_add_contact">"新增連絡人"</string>
+ <string name="contextmenu_add_contact">"新增聯絡人"</string>
<string name="contextmenu_send_mail">"傳送電子郵件"</string>
<string name="contextmenu_map">"地圖"</string>
<string name="clear">"清除"</string>
@@ -114,14 +116,14 @@
<string name="menu_preferences">"設定"</string>
<string name="pref_content_title">"頁面內容設定"</string>
<string name="pref_content_load_images">"載入圖片"</string>
- <string name="pref_content_load_images_summary">"在網頁上顯示圖片"</string>
- <string name="pref_content_block_popups">"阻擋快顯視窗"</string>
+ <string name="pref_content_load_images_summary">"顯示網頁上的圖片"</string>
+ <string name="pref_content_block_popups">"封鎖快顯視窗"</string>
<string name="pref_content_javascript">"啟用 JavaScript"</string>
- <string name="pref_content_open_in_background">"在背景開啟"</string>
- <string name="pref_content_open_in_background_summary">"新分頁開在目前頁面後面"</string>
+ <string name="pref_content_open_in_background">"在背景中開啟"</string>
+ <string name="pref_content_open_in_background_summary">"在目前頁面後面開啟新分頁"</string>
<string name="pref_content_homepage">"設定首頁"</string>
<string name="pref_content_autofit">"自動調整頁面"</string>
- <string name="pref_content_autofit_summary">"將網頁調整至適合螢幕大小"</string>
+ <string name="pref_content_autofit_summary">"將網頁調整至適合螢幕的大小"</string>
<string name="pref_privacy_title">"隱私設定"</string>
<string name="pref_privacy_clear_cache">"清除快取"</string>
<string name="pref_privacy_clear_cache_summary">"刪除所有快取頁面內容"</string>
@@ -129,19 +131,19 @@
<string name="pref_privacy_clear_cookies">"清除所有 cookie"</string>
<string name="pref_privacy_clear_cookies_summary">"清除所有 cookie"</string>
<string name="pref_privacy_clear_cookies_dlg">"所有 cookie 會被清除。"</string>
- <string name="pref_privacy_clear_history">"清除紀錄"</string>
+ <string name="pref_privacy_clear_history">"清除記錄"</string>
<string name="pref_privacy_clear_history_summary">"清除瀏覽記錄"</string>
- <string name="pref_privacy_clear_history_dlg">"瀏覽記錄會被清除。"</string>
- <string name="pref_privacy_clear_form_data">"清除表單資訊"</string>
+ <string name="pref_privacy_clear_history_dlg">"瀏覽記錄將被清除。"</string>
+ <string name="pref_privacy_clear_form_data">"清除表單資料"</string>
<string name="pref_privacy_clear_form_data_summary">"清除所有表單"</string>
<string name="pref_privacy_clear_form_data_dlg">"所有儲存的資料會被清除。"</string>
<string name="pref_privacy_clear_passwords">"清除密碼"</string>
- <string name="pref_privacy_clear_passwords_summary">"清除所有儲存密碼"</string>
+ <string name="pref_privacy_clear_passwords_summary">"清除所有儲存的密碼"</string>
<string name="pref_privacy_clear_passwords_dlg">"所有儲存密碼會被清除"</string>
<string name="pref_security_title">"安全性設定"</string>
<string name="pref_security_remember_passwords">"記住密碼"</string>
<string name="pref_security_remember_passwords_summary">"儲存網站使用者名稱與密碼"</string>
- <string name="pref_security_save_form_data">"儲存表單資訊"</string>
+ <string name="pref_security_save_form_data">"儲存表單資料"</string>
<string name="pref_security_save_form_data_summary">"儲存輸入的表單資料"</string>
<string name="pref_security_show_security_warning">"顯示安全性警告"</string>
<string name="pref_security_show_security_warning_summary">"當網站安全性有問題時,顯示警告訊息"</string>
@@ -149,25 +151,25 @@
<string name="pref_security_accept_cookies_summary">"允許網站存取 cookie"</string>
<string name="pref_text_size">"設定文字大小"</string>
<string-array name="pref_text_size_choices">
- <item>"極小"</item>
+ <item>"最小"</item>
<item>"小"</item>
- <item>"一般"</item>
+ <item>"適中"</item>
<item>"大"</item>
- <item>"特大"</item>
+ <item>"最大"</item>
</string-array>
<string name="pref_text_size_dialogtitle">"文字大小"</string>
<string name="pref_extras_title">"進階設定"</string>
- <string name="pref_extras_gears_enable">"啟用裝置"</string>
+ <string name="pref_extras_gears_enable">"啟用 Gears"</string>
<string name="pref_extras_gears_enable_summary">"可擴充瀏覽器功能的應用程式"</string>
- <string name="pref_extras_gears_settings">"裝置設定"</string>
+ <string name="pref_extras_gears_settings">"Gears 設定"</string>
<string name="pref_plugin_installed">"外掛程式清單"</string>
<string name="pref_plugin_installed_empty_list">"未安裝外掛程式。"</string>
<string name="pref_extras_gears_settings_summary">"可擴充瀏覽器功能的應用程式"</string>
- <string name="pref_extras_reset_default">"回復初始設定"</string>
- <string name="pref_extras_reset_default_summary">"清除瀏覽器所有資料,並回復初始設定"</string>
- <string name="pref_extras_reset_default_dlg">"瀏覽器所有資料會被清除, 並回復初始設定。"</string>
- <string name="pref_extras_reset_default_dlg_title">"回復初始設定"</string>
- <string name="pref_development_title">"除錯"</string>
+ <string name="pref_extras_reset_default">"還原至初始設定"</string>
+ <string name="pref_extras_reset_default_summary">"清除瀏覽器所有資料,並還原至初始設定"</string>
+ <string name="pref_extras_reset_default_dlg">"瀏覽器所有資料會被清除, 並還原至初始設定。"</string>
+ <string name="pref_extras_reset_default_dlg_title">"還原至初始設定"</string>
+ <string name="pref_development_title">"偵錯"</string>
<string name="pref_default_text_encoding">"設定文字編碼"</string>
<string-array name="pref_default_text_encoding_choices">
<item>"Latin-1 (ISO-8859-1)"</item>
@@ -183,10 +185,10 @@
<string name="browserFrameNetworkErrorLabel">"資料連線問題"</string>
<string name="browserFrameFileErrorLabel">"檔案有問題"</string>
<string name="browserFrameFormResubmitLabel">"確認"</string>
- <string name="browserFrameFormResubmitMessage">"您正在瀏覽的頁面包含已傳送的 (「POSTDATA」),若重新送出資料,此頁表單中的資料會重複 (例如:搜尋結果、線上購物狀態)。"</string>
+ <string name="browserFrameFormResubmitMessage">"您想瀏覽的頁面包含已傳送的 (「POSTDATA」),如重新送出資料,此頁表單上執行的操作將會重複 (包括搜尋或線上購物等)。"</string>
<string name="loadSuspendedTitle">"沒有網路連線"</string>
<string name="loadSuspended">"連線恢復後,此頁面會繼續載入。"</string>
- <string name="clear_history">"清除紀錄"</string>
+ <string name="clear_history">"清除記錄"</string>
<string name="browser_history">"最近瀏覽的頁面"</string>
<string name="empty_history">"瀏覽記錄是空的。"</string>
<string name="add_new_bookmark">"加入書籤…"</string>
@@ -196,7 +198,7 @@
<string name="attention">"注意"</string>
<string name="popup_window_attempt">"此網站試圖開啟快顯視窗。"</string>
<string name="allow">"允許"</string>
- <string name="block">"阻擋"</string>
+ <string name="block">"封鎖"</string>
<string name="too_many_windows_dialog_title">"已達視窗數量限制"</string>
<string name="too_many_windows_dialog_message">"已達最大視窗數量限制,無法開啟新視窗。"</string>
<string name="too_many_subwindows_dialog_title">"已開啟快顯視窗"</string>
@@ -218,7 +220,7 @@
<string name="download_no_sdcard_dlg_title">"沒有 SD 卡"</string>
<string name="download_no_sdcard_dlg_msg">"需要 SD 卡下載 <xliff:g id="FILENAME">%s</xliff:g>。"</string>
<string name="download_sdcard_busy_dlg_title">"無法使用 SD 卡"</string>
- <string name="download_sdcard_busy_dlg_msg">"SD 記憶卡忙碌中。若要允許下載,請選取通知區域中的 [停用 USB 儲存裝置]。"</string>
+ <string name="download_sdcard_busy_dlg_msg">"SD 記憶卡忙碌。如要允許下載,請選取通知中的 [停用 USB 儲存裝置]。"</string>
<string name="download_no_application">"找不到可以開啟這個檔案的應用程式。"</string>
<string name="retry">"重試"</string>
<string name="no_downloads">"下載記錄是空的。"</string>
@@ -238,7 +240,7 @@
<string name="permlab_readHistoryBookmarks">"讀取瀏覽器的瀏覽記錄和書籤"</string>
<string name="permdesc_readHistoryBookmarks">"允許應用程式讀取瀏覽器造訪過的所有 URL 和瀏覽器所有的書籤。"</string>
<string name="permlab_writeHistoryBookmarks">"寫入瀏覽器的瀏覽記錄和書籤"</string>
- <string name="permdesc_writeHistoryBookmarks">"允許應用程式修改儲存在電話上的瀏覽器記錄或書籤。惡意應用程式可能會使用此選項來清除或修改您瀏覽器的資料。"</string>
+ <string name="permdesc_writeHistoryBookmarks">"允許應用程式修改儲存在電話上的瀏覽記錄或書籤。請注意:惡意應用程式可能會使用此選項來清除或修改您瀏覽器的資料。"</string>
<string name="query_data_prompt">"允許儲存"</string>
<string name="query_data_message">"此網站要在您的手機上儲存資訊。"</string>
<string name="location_prompt">"存取您的位置資訊"</string>
@@ -248,7 +250,7 @@
<string name="settings_message">"下表列出您為每個想要使用 Gears 之網站所授予的權限。"</string>
<string name="filepicker_message">"檔案挑選程式"</string>
<string name="image_message">"選擇的影像"</string>
- <string name="settings_title">"裝置設定"</string>
+ <string name="settings_title">"Gears 設定"</string>
<string name="privacy_policy">"讀取網站的隱私權政策,以瞭解網站將如何使用您的位置資訊。"</string>
<string name="settings_storage_title">"允許本機儲存"</string>
<string name="settings_storage_subtitle_on">"此網站可以在您的手機上儲存資訊"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 82e4602..77464d7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -38,6 +38,8 @@
<string name="password">Password</string>
<!-- The label on the "sign in" button -->
<string name="action">Sign in</string>
+ <!-- The name of the bookmarks and history search suggestion source. -->
+ <string name="bookmarks_search">Bookmarks & history</string>
<!-- Label for a cancel button. It is used for multiple cancel buttons in different contexts -->
<string name="cancel">Cancel</string>
diff --git a/res/xml/bookmarks_searchable.xml b/res/xml/bookmarks_searchable.xml
new file mode 100644
index 0000000..bc6ac93
--- /dev/null
+++ b/res/xml/bookmarks_searchable.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+ android:label="@string/bookmarks_search"
+ android:searchButtonText="@string/search_button_text"
+ android:searchMode="queryRewriteFromData"
+ android:inputType="textUri"
+ android:imeOptions="actionGo"
+
+ android:includeInGlobalSearch="true"
+ android:searchSuggestAuthority="browser"
+ android:searchSuggestPath="bookmarks"
+ android:searchSuggestSelection="url LIKE ?"
+ android:searchSuggestIntentAction="android.intent.action.VIEW"
+/>
diff --git a/src/com/android/browser/BookmarkSearch.java b/src/com/android/browser/BookmarkSearch.java
new file mode 100644
index 0000000..4d3ca0f
--- /dev/null
+++ b/src/com/android/browser/BookmarkSearch.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 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.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * This activity is never started from the browser. Its purpose is to provide bookmark suggestions
+ * to global search (through its searchable meta-data), and to handle the intents produced
+ * by clicking such suggestions.
+ */
+public class BookmarkSearch extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+ if (intent != null) {
+ String action = intent.getAction();
+ if (Intent.ACTION_VIEW.equals(action)) {
+ intent.setClass(this, BrowserActivity.class);
+ startActivity(intent);
+ }
+ }
+ finish();
+ }
+
+}
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index db4f634..bd68109 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -115,6 +115,7 @@
import android.webkit.WebChromeClient;
import android.webkit.WebHistoryItem;
import android.webkit.WebIconDatabase;
+import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
@@ -2136,6 +2137,9 @@
.setVisibility(View.VISIBLE);
}
mContentView.removeView(mTabOverview);
+ // Clear all the data for tab picker so next time it will be
+ // recreated.
+ mTabControl.wipeAllPickerData();
mTabOverview.clear();
mTabOverview = null;
mTabListener = null;
@@ -3429,6 +3433,34 @@
public void onReceivedIcon(WebView view, Bitmap icon) {
updateIcon(view.getUrl(), icon);
}
+
+ /**
+ * The origin has exceeded it's database quota.
+ * @param url the URL that exceeded the quota
+ * @param databaseIdentifier the identifier of the database on
+ * which the transaction that caused the quota overflow was run
+ * @param currentQuota the current quota for the origin.
+ * @param quotaUpdater The callback to run when a decision to allow or
+ * deny quota has been made. Don't forget to call this!
+ */
+ @Override
+ public void onExceededDatabaseQuota(String url,
+ String databaseIdentifier, long currentQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ if(LOGV_ENABLED) {
+ Log.v(LOGTAG,
+ "BrowserActivity received onExceededDatabaseQuota for "
+ + url +
+ ":"
+ + databaseIdentifier +
+ "(current quota: "
+ + currentQuota +
+ ")");
+ }
+ // Give the origin an extra megabyte to play with.
+ // TODO: This should show a prompt to the user, really :)
+ quotaUpdater.updateQuota(currentQuota + 1024 * 1024);
+ }
};
/**
@@ -4207,10 +4239,6 @@
}
}
- // Clear all the data for tab picker so next time it will be
- // recreated.
- mTabControl.wipeAllPickerData();
-
// NEW_TAB means that the "New Tab" cell was clicked on.
if (index == ImageGrid.NEW_TAB) {
openTabAndShow(mSettings.getHomePage(), null, false, null);
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index ce156a7..8c30873 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -17,14 +17,11 @@
package com.android.browser;
import com.google.android.providers.GoogleSettings.Partner;
-import java.util.Date;
-import android.app.ISearchManager;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentUris;
-import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -33,17 +30,16 @@
import android.content.SharedPreferences.Editor;
import android.database.AbstractCursor;
import android.database.Cursor;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Browser;
-import android.util.Log;
import android.server.search.SearchableInfo;
import android.text.util.Regex;
+import android.util.Log;
+
+import java.util.Date;
public class BrowserProvider extends ContentProvider {
@@ -97,6 +93,7 @@
private static final int URI_MATCH_SEARCHES_ID = 11;
//
private static final int URI_MATCH_SUGGEST = 20;
+ private static final int URI_MATCH_BOOKMARKS_SUGGEST = 21;
private static final UriMatcher URI_MATCHER;
@@ -112,6 +109,9 @@
URI_MATCH_SEARCHES_ID);
URI_MATCHER.addURI("browser", SearchManager.SUGGEST_URI_PATH_QUERY,
URI_MATCH_SUGGEST);
+ URI_MATCHER.addURI("browser",
+ TABLE_NAMES[URI_MATCH_BOOKMARKS] + "/" + SearchManager.SUGGEST_URI_PATH_QUERY,
+ URI_MATCH_BOOKMARKS_SUGGEST);
}
// 1 -> 2 add cache table
@@ -473,7 +473,7 @@
throw new IllegalArgumentException("Unknown URL");
}
- if (match == URI_MATCH_SUGGEST) {
+ if (match == URI_MATCH_SUGGEST || match == URI_MATCH_BOOKMARKS_SUGGEST) {
String suggestSelection;
String [] myArgs;
if (selectionArgs[0] == null || selectionArgs[0].equals("")) {
@@ -501,49 +501,22 @@
ORDER_BY,
(new Integer(MAX_SUGGESTION_LONG_ENTRIES)).toString());
- if (Regex.WEB_URL_PATTERN.matcher(selectionArgs[0]).matches()) {
+ if (match == URI_MATCH_BOOKMARKS_SUGGEST
+ || Regex.WEB_URL_PATTERN.matcher(selectionArgs[0]).matches()) {
return new MySuggestionCursor(c, null, "");
} else {
// get Google suggest if there is still space in the list
if (myArgs != null && myArgs.length > 1
&& c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) {
- ISearchManager sm = ISearchManager.Stub
- .asInterface(ServiceManager
- .getService(Context.SEARCH_SERVICE));
- SearchableInfo si = null;
- try {
- // use the global search to get Google suggest provider
- si = sm.getSearchableInfo(new ComponentName(
- getContext(), "com.android.browser"), true);
-
- // similar to the getSuggestions() in SearchDialog.java
- StringBuilder uriStr = new StringBuilder("content://");
- uriStr.append(si.getSuggestAuthority());
- // if content path provided, insert it now
- final String contentPath = si.getSuggestPath();
- if (contentPath != null) {
- uriStr.append('/');
- uriStr.append(contentPath);
- }
- // append standard suggestion query path
- uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY);
- // inject query, either as selection args or inline
- String[] selArgs = null;
- if (si.getSuggestSelection() != null) {
- selArgs = new String[] {selectionArgs[0]};
- } else {
- uriStr.append('/');
- uriStr.append(Uri.encode(selectionArgs[0]));
- }
-
- // finally, make the query
- Cursor sc = getContext().getContentResolver().query(
- Uri.parse(uriStr.toString()), null,
- si.getSuggestSelection(), selArgs, null);
-
- return new MySuggestionCursor(c, sc, selectionArgs[0]);
- } catch (RemoteException e) {
- }
+ // TODO: This shouldn't be hard-coded. Instead, it should use the
+ // default web search provider. But the API for that is not implemented yet.
+ ComponentName googleSearchComponent =
+ new ComponentName("com.android.googlesearch",
+ "com.android.googlesearch.GoogleSearch");
+ SearchableInfo si =
+ SearchManager.getSearchableInfo(googleSearchComponent, false);
+ Cursor sc = SearchManager.getSuggestions(getContext(), si, selectionArgs[0]);
+ return new MySuggestionCursor(c, sc, selectionArgs[0]);
}
return new MySuggestionCursor(c, null, selectionArgs[0]);
}
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index e47ed60..95ed17b 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -74,6 +74,8 @@
private boolean autoFitPage = true;
private boolean landscapeOnly = false;
private boolean showDebugSettings = false;
+ private String databasePath; // default value set in loadFromDb()
+ private boolean databaseEnabled = true;
// The Browser always enables Application Caches.
private boolean appCacheEnabled = true;
private String appCachePath; // default value set in loadFromDb().
@@ -185,6 +187,10 @@
s.setSupportMultipleWindows(true);
// Turn off file access
s.setAllowFileAccess(false);
+
+ s.setDatabasePath(b.databasePath);
+ s.setDatabaseEnabled(b.databaseEnabled);
+
// Turn on Application Caches.
s.setAppCachePath(b.appCachePath);
s.setAppCacheEnabled(b.appCacheEnabled);
@@ -209,6 +215,8 @@
pluginsPath = ctx.getDir("plugins", 0).getPath();
// Set the default value for the Application Caches path.
appCachePath = ctx.getDir("appcache", 0).getPath();
+ // Set the default value for the Database path.
+ databasePath = ctx.getDir("databases", 0).getPath();
homeUrl = DEFAULT_HOME_URL +
Partner.getString(ctx.getContentResolver(), Partner.CLIENT_ID);
@@ -232,6 +240,8 @@
pluginsEnabled = p.getBoolean("enable_plugins",
pluginsEnabled);
pluginsPath = p.getString("plugins_path", pluginsPath);
+ databasePath = p.getString("database_path", databasePath);
+ databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
appCacheEnabled = p.getBoolean("enable_appcache",
appCacheEnabled);
appCachePath = p.getString("appcache_path", appCachePath);
diff --git a/src/com/android/browser/FakeWebView.java b/src/com/android/browser/FakeWebView.java
index 633b799..da5ef5f 100644
--- a/src/com/android/browser/FakeWebView.java
+++ b/src/com/android/browser/FakeWebView.java
@@ -33,17 +33,9 @@
* overrides ImageView so it can be used for the new tab image as well.
*/
public class FakeWebView extends ImageView {
- private TabControl.Tab mTab;
- private Picture mPicture;
+ private TabControl.PickerData mPickerData;
private boolean mUsesResource;
- private class Listener implements WebView.PictureListener {
- public void onNewPicture(WebView view, Picture p) {
- FakeWebView.this.mPicture = p;
- FakeWebView.this.invalidate();
- }
- };
-
public FakeWebView(Context context) {
this(context, null);
}
@@ -68,17 +60,21 @@
// would be nice to know if the picture is empty so we can avoid
// drawing white.
canvas.drawColor(Color.WHITE);
- if (mTab != null) {
- final WebView w = mTab.getTopWindow();
- if (w != null) {
- if (mPicture != null) {
- canvas.save();
- float scale = getWidth() * w.getScale() / w.getWidth();
- canvas.scale(scale, scale);
- canvas.translate(-w.getScrollX(), -w.getScrollY());
- canvas.drawPicture(mPicture);
- canvas.restore();
+ if (mPickerData != null) {
+ final Picture p = mPickerData.mPicture;
+ if (p != null) {
+ canvas.save();
+ float scale = getWidth() * mPickerData.mScale
+ / mPickerData.mWidth;
+ // Check for NaN and infinity.
+ if (Float.isNaN(scale) || Float.isInfinite(scale)) {
+ scale = 1.0f;
}
+ canvas.scale(scale, scale);
+ canvas.translate(-mPickerData.mScrollX,
+ -mPickerData.mScrollY);
+ canvas.drawPicture(p);
+ canvas.restore();
}
}
}
@@ -87,25 +83,24 @@
@Override
public void setImageResource(int resId) {
mUsesResource = true;
- mTab = null;
+ mPickerData = null;
super.setImageResource(resId);
}
/**
* Set a WebView for this FakeWebView to represent.
- * @param v WebView whose picture and other data will be used in onDraw.
+ * @param t The tab whose picture and other data will be used in onDraw.
*/
public void setTab(TabControl.Tab t) {
mUsesResource = false;
- mTab = t;
- if (t != null && t.getWebView() != null) {
- Listener l = new Listener();
- if (t.getSubWebView() != null) {
- t.getSubWebView().setPictureListener(l);
- } else {
- t.getWebView().setPictureListener(l);
- }
- mPicture = mTab.getTopWindow().capturePicture();
+ if (mPickerData != null) {
+ // Clear the old tab's view first
+ mPickerData.mFakeWebView = null;
+ }
+ mPickerData = null;
+ if (t != null && t.getPickerData() != null) {
+ mPickerData = t.getPickerData();
+ mPickerData.mFakeWebView = this;
}
}
}
diff --git a/src/com/android/browser/ImageAdapter.java b/src/com/android/browser/ImageAdapter.java
index e957143..f95753a 100644
--- a/src/com/android/browser/ImageAdapter.java
+++ b/src/com/android/browser/ImageAdapter.java
@@ -27,7 +27,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
-import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
@@ -73,22 +72,10 @@
* Clear the internal WebViews and remove their picture listeners.
*/
public void clear() {
- for (TabControl.Tab t : mItems) {
- clearPictureListeners(t);
- }
mItems.clear();
notifyObservers();
}
- private void clearPictureListeners(TabControl.Tab t) {
- if (t.getWebView() != null) {
- t.getWebView().setPictureListener(null);
- if (t.getSubWebView() != null) {
- t.getSubWebView().setPictureListener(null);
- }
- }
- }
-
/**
* Add a new window web page to the grid
*
@@ -113,7 +100,7 @@
*/
public void remove(int index) {
if (index >= 0 && index < mItems.size()) {
- clearPictureListeners(mItems.remove(index));
+ mItems.remove(index);
notifyObservers();
mMaxedOut = false;
}
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index cfe63a6..9de0198 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -17,6 +17,7 @@
package com.android.browser;
import android.content.Context;
+import android.graphics.Picture;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Message;
@@ -39,6 +40,7 @@
import android.widget.ImageButton;
import java.io.File;
+import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Vector;
@@ -142,10 +144,24 @@
}
}
+ // Extra saved information for displaying the tab in the picker.
+ public static class PickerData {
+ String mUrl;
+ String mTitle;
+ float mScale;
+ int mScrollX;
+ int mScrollY;
+ int mWidth;
+ Picture mPicture;
+ // This can be null. When a new picture comes in, this view should be
+ // invalidated to show the new picture.
+ FakeWebView mFakeWebView;
+ }
+
/**
* Private class for maintaining Tabs with a main WebView and a subwindow.
*/
- public class Tab {
+ public class Tab implements WebView.PictureListener {
// Main WebView
private WebView mMainView;
// Subwindow WebView
@@ -160,10 +176,9 @@
// information needed to restore the WebView if the user goes back to
// the tab.
private Bundle mSavedState;
- // Extra saved information for displaying the tab in the picker.
- private String mUrl;
- private String mTitle;
-
+ // Data used when displaying the tab in the picker.
+ private PickerData mPickerData;
+
// Parent Tab. This is the Tab that created this Tab, or null
// if the Tab was created by the UI
private Tab mParentTab;
@@ -234,7 +249,10 @@
* @return The WebView's url or null.
*/
public String getUrl() {
- return mUrl;
+ if (mPickerData != null) {
+ return mPickerData.mUrl;
+ }
+ return null;
}
/**
@@ -245,7 +263,17 @@
* @return The WebView's title (or url) or null.
*/
public String getTitle() {
- return mTitle;
+ if (mPickerData != null) {
+ return mPickerData.mTitle;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the picker data.
+ */
+ public PickerData getPickerData() {
+ return mPickerData;
}
private void setParentTab(Tab parent) {
@@ -307,6 +335,18 @@
public boolean closeOnExit() {
return mCloseOnExit;
}
+
+ public void onNewPicture(WebView view, Picture p) {
+ if (mPickerData == null) {
+ return;
+ }
+
+ mPickerData.mPicture = p;
+ // Tell the FakeWebView to redraw.
+ if (mPickerData.mFakeWebView != null) {
+ mPickerData.mFakeWebView.invalidate();
+ }
+ }
};
// Directory to store thumbnails for each WebView.
@@ -486,8 +526,8 @@
// This tab may have been pushed in to the background and then closed.
// If the saved state contains a picture file, delete the file.
if (t.mSavedState != null) {
- if (t.mSavedState.containsKey("picture")) {
- new File(t.mSavedState.getString("picture")).delete();
+ if (t.mSavedState.containsKey(CURRPICTURE)) {
+ new File(t.mSavedState.getString(CURRPICTURE)).delete();
}
}
@@ -546,6 +586,8 @@
private static final String CURRTAB = "currentTab";
private static final String CURRURL = "currentUrl";
private static final String CURRTITLE = "currentTitle";
+ private static final String CURRWIDTH = "currentWidth";
+ private static final String CURRPICTURE = "currentPicture";
private static final String CLOSEONEXIT = "closeonexit";
private static final String PARENTTAB = "parentTab";
private static final String APPID = "appid";
@@ -598,8 +640,7 @@
Tab t = new Tab(null, false, null, null);
t.mSavedState = inState.getBundle(WEBVIEW + i);
if (t.mSavedState != null) {
- t.mUrl = t.mSavedState.getString(CURRURL);
- t.mTitle = t.mSavedState.getString(CURRTITLE);
+ populatePickerDataFromSavedState(t);
// Need to maintain the app id and original url so we
// can possibly reuse this tab.
t.mAppId = t.mSavedState.getString(APPID);
@@ -795,8 +836,7 @@
// Clear the saved state except for the app id and close-on-exit
// values.
t.mSavedState = null;
- t.mUrl = null;
- t.mTitle = null;
+ t.mPickerData = null;
// Save the new url in order to avoid deleting the WebView.
t.mOriginalUrl = url;
return true;
@@ -921,30 +961,89 @@
}
/**
- * Ensure that Tab t has a title, url, and favicon.
+ * Ensure that Tab t has data to display in the tab picker.
* @param t Tab to populate.
*/
/* package */ void populatePickerData(Tab t) {
- if (t == null || t.mMainView == null) {
+ if (t == null) {
return;
}
+
+ // mMainView == null indicates that the tab has been freed.
+ if (t.mMainView == null) {
+ populatePickerDataFromSavedState(t);
+ return;
+ }
+
// FIXME: The only place we cared about subwindow was for
// bookmarking (i.e. not when saving state). Was this deliberate?
final WebBackForwardList list = t.mMainView.copyBackForwardList();
final WebHistoryItem item =
list != null ? list.getCurrentItem() : null;
populatePickerData(t, item);
+
+ // This method is only called during the tab picker creation. At this
+ // point we need to listen for new pictures since the WebView is still
+ // active.
+ final WebView w = t.getTopWindow();
+ w.setPictureListener(t);
+ // Capture the picture here instead of populatePickerData since it can
+ // be called when saving the state of a tab.
+ t.mPickerData.mPicture = w.capturePicture();
}
- // Populate the picker data
- private void populatePickerData(Tab t, WebHistoryItem item) {
- if (item != null) {
- t.mUrl = item.getUrl();
- t.mTitle = item.getTitle();
- if (t.mTitle == null) {
- t.mTitle = t.mUrl;
+ // Create the PickerData and populate it using the saved state of the tab.
+ private void populatePickerDataFromSavedState(Tab t) {
+ if (t.mSavedState == null) {
+ return;
+ }
+
+ final PickerData data = new PickerData();
+ final Bundle state = t.mSavedState;
+ data.mUrl = state.getString(CURRURL);
+ data.mTitle = state.getString(CURRTITLE);
+ data.mWidth = state.getInt(CURRWIDTH, 0);
+ // XXX: These keys are from WebView.savePicture so if they change, this
+ // will break.
+ data.mScale = state.getFloat("scale", 1.0f);
+ data.mScrollX = state.getInt("scrollX", 0);
+ data.mScrollY = state.getInt("scrollY", 0);
+
+ if (state.containsKey(CURRPICTURE)) {
+ final File f = new File(t.mSavedState.getString(CURRPICTURE));
+ try {
+ final FileInputStream in = new FileInputStream(f);
+ data.mPicture = Picture.createFromStream(in);
+ in.close();
+ } catch (Exception ex) {
+ // Ignore any problems with inflating the picture. We just
+ // won't draw anything.
}
}
+
+ // Set the tab's picker data.
+ t.mPickerData = data;
+ }
+
+ // Populate the picker data using the given history item and the current
+ // top WebView.
+ private void populatePickerData(Tab t, WebHistoryItem item) {
+ final PickerData data = new PickerData();
+ if (item != null) {
+ data.mUrl = item.getUrl();
+ data.mTitle = item.getTitle();
+ if (data.mTitle == null) {
+ data.mTitle = data.mUrl;
+ }
+ }
+ // We want to display the top window in the tab picker but use the url
+ // and title of the main window.
+ final WebView w = t.getTopWindow();
+ data.mWidth = w.getWidth();
+ data.mScale = w.getScale();
+ data.mScrollX = w.getScrollX();
+ data.mScrollY = w.getScrollY();
+ t.mPickerData = data;
}
/**
@@ -955,8 +1054,14 @@
for (int i = 0; i < size; i++) {
final Tab t = getTab(i);
if (t != null && t.mSavedState == null) {
- t.mUrl = null;
- t.mTitle = null;
+ t.mPickerData = null;
+ }
+ if (t.mMainView != null) {
+ // Clear the picture listeners.
+ t.mMainView.setPictureListener(null);
+ if (t.mSubView != null) {
+ t.mSubView.setPictureListener(null);
+ }
}
}
}
@@ -978,7 +1083,7 @@
final File f = new File(mThumbnailDir, w.hashCode()
+ "_pic.save");
if (w.savePicture(b, f)) {
- b.putString("picture", f.getPath());
+ b.putString(CURRPICTURE, f.getPath());
}
}
@@ -986,12 +1091,17 @@
final WebHistoryItem item =
list != null ? list.getCurrentItem() : null;
populatePickerData(t, item);
- if (t.mUrl != null) {
- b.putString(CURRURL, t.mUrl);
+
+ // XXX: WebView.savePicture stores the scale and scroll positions
+ // in the bundle so we don't have to do it here.
+ final PickerData data = t.mPickerData;
+ if (data.mUrl != null) {
+ b.putString(CURRURL, data.mUrl);
}
- if (t.mTitle != null) {
- b.putString(CURRTITLE, t.mTitle);
+ if (data.mTitle != null) {
+ b.putString(CURRTITLE, data.mTitle);
}
+ b.putInt(CURRWIDTH, data.mWidth);
b.putBoolean(CLOSEONEXIT, t.mCloseOnExit);
if (t.mAppId != null) {
b.putString(APPID, t.mAppId);
@@ -1022,8 +1132,7 @@
// Restore the internal state even if the WebView fails to restore.
// This will maintain the app id, original url and close-on-exit values.
t.mSavedState = null;
- t.mUrl = null;
- t.mTitle = null;
+ t.mPickerData = null;
t.mCloseOnExit = b.getBoolean(CLOSEONEXIT);
t.mAppId = b.getString(APPID);
t.mOriginalUrl = b.getString(ORIGINALURL);
@@ -1033,8 +1142,8 @@
if (list == null) {
return false;
}
- if (b.containsKey("picture")) {
- final File f = new File(b.getString("picture"));
+ if (b.containsKey(CURRPICTURE)) {
+ final File f = new File(b.getString(CURRPICTURE));
w.restorePicture(b, f);
f.delete();
}