LOCAL_PACKAGE_NAME := Browser
+LOCAL_EMMA_COVERAGE_FILTER := *,-com.android.common.*
+
include $(BUILD_PACKAGE)
# additionally, build tests in sub-folders in a separate .apk
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
- <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
</set>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
</set>
--- /dev/null
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/selectControls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip"
+ android:paddingLeft="4dip"
+ android:paddingRight="4dip"
+ android:paddingBottom="1dip"
+ android:background="@android:drawable/bottom_bar">
+ <ImageButton
+ android:src="@drawable/ic_btn_copy"
+ android:id="@+id/copy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <ImageButton
+ android:src="@drawable/ic_btn_share"
+ android:id="@+id/share"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <ImageButton
+ android:src="@drawable/ic_btn_select_all"
+ android:id="@+id/select_all"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <ImageButton
+ android:src="@drawable/ic_btn_find"
+ android:id="@+id/find"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <LinearLayout
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"
+ />
+
+ <ImageButton
+ android:src="@drawable/ic_btn_close_panel"
+ android:id="@+id/done"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+</LinearLayout>
+
android:layout_height="match_parent"
android:padding="10dip" >
<LinearLayout
+ android:id="@+id/inner_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
<item quantity="few" msgid="5544267486978946555">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
<item quantity="other" msgid="6616125067364315405">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
</plurals>
- <string name="title_bar_loading" msgid="7438217780834640678">"Ladevorgang läuft..."</string>
+ <string name="title_bar_loading" msgid="7438217780834640678">"Wird geladen..."</string>
<string name="page_info" msgid="4048529256302257195">"Seiteninfo"</string>
<string name="page_info_view" msgid="5303490449842635158">"Seiteninfo anzeigen"</string>
<string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
<string name="contextmenu_copylink" msgid="5153657160294534270">"Link-URL kopieren"</string>
<string name="contextmenu_download_image" msgid="4243829645180686912">"Bild speichern"</string>
<string name="contextmenu_view_image" msgid="3870625602053600905">"Bild anzeigen"</string>
- <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrundbild festlegen"</string>
+ <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrund festlegen"</string>
<string name="contextmenu_dial_dot" msgid="5856550683415933806">"Wählen..."</string>
<string name="contextmenu_add_contact" msgid="3183511922223645716">"Kontakt hinzufügen"</string>
<string name="contextmenu_send_mail" msgid="1014513374828775660">"E-Mail senden"</string>
<string name="website_settings_clear_all_dialog_message" msgid="6150502090601476333">"Alle Websitedaten und Standortberechtigungen werden gelöscht."</string>
<string name="website_settings_clear_all_dialog_ok_button" msgid="6401582240627669431">"Alle Daten löschen"</string>
<string name="website_settings_clear_all_dialog_cancel_button" msgid="1896757051856611674">"Abbrechen"</string>
- <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrundbild wird eingestellt..."</string>
+ <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrund wird eingestellt..."</string>
</resources>
<string name="active_tabs" msgid="3050623868203544623">"Windows"</string>
<string name="tab_bookmarks" msgid="2305793036003473653">"Marcadores"</string>
<string name="tab_most_visited" msgid="1077402532455000703">"Más visitados"</string>
- <string name="tab_history" msgid="1979267558744613746">"Historial"</string>
+ <string name="tab_history" msgid="1979267558744613746">"Historial "</string>
<string name="added_to_bookmarks" msgid="1020224130695956728">"Agregado a marcadores"</string>
<string name="removed_from_bookmarks" msgid="6063705902028438800">"Suprimido de los marcadores"</string>
<string name="sign_in_to" msgid="5939425800148759165">"Iniciar sesión en <xliff:g id="HOSTNAME">%s1</xliff:g> \"<xliff:g id="REALM">%s2</xliff:g>\""</string>
<string name="popup_window_attempt" msgid="2673111696288657989">"Este sitio está intentando abrir una ventana emergente."</string>
<string name="allow" msgid="1157313689171991335">"Permitir"</string>
<string name="block" msgid="9172175889884707800">"Bloquear"</string>
- <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana"</string>
+ <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana "</string>
<string name="too_many_windows_dialog_message" msgid="1398571800233959583">"No se ha podido abrir una ventana nueva porque ya has abierto el máximo permitido."</string>
<string name="too_many_subwindows_dialog_title" msgid="3805453941587725944">"Ventana emergente ya abierta"</string>
<string name="too_many_subwindows_dialog_message" msgid="5827289829907966657">"No es posible abrir una ventana emergente nueva porque sólo puede abrirse una por vez."</string>
<string name="download_title" msgid="2122874021047565594">"Historial de descarga"</string>
<string name="download_unknown_filename" msgid="4013465542563652175">"<Desconocido>"</string>
<string name="download_menu_open" msgid="4888327480367757513">"Abrir"</string>
- <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista"</string>
+ <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista\n "</string>
<string name="download_menu_delete" msgid="8815502136393894148">"Eliminar"</string>
<string name="download_menu_cancel" msgid="2545333007601851574">"Cancelar descarga"</string>
- <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas"</string>
+ <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas\n "</string>
<string name="download_cancel_dlg_title" msgid="8909108500262799748">"Cancelar descargas"</string>
<string name="download_cancel_dlg_msg" msgid="6285389170052357797">"Las <xliff:g id="DOWNLOAD_COUNT">%d</xliff:g> descargas se cancelarán y se borrarán del historial de descarga."</string>
<string name="download_delete_file" msgid="5330036497843073249">"El archivo se eliminará"</string>
<string name="expires_on" msgid="8061200430557020704">"Дата окончания действия:"</string>
<string name="stopping" msgid="4839698519340302982">"Остановка..."</string>
<string name="stop" msgid="5687251076030630074">"Стоп"</string>
- <string name="reload" msgid="8585220783228408062">"Ð\9eбновление"</string>
+ <string name="reload" msgid="8585220783228408062">"Ð\9eбновиÑ\82Ñ\8c"</string>
<string name="back" msgid="8414603107175713668">"Назад"</string>
<string name="forward" msgid="4288210890526641577">"Вперед"</string>
<string name="save" msgid="5922311934992468496">"ОК"</string>
<string name="switch_to_thumbnails" msgid="5493351529609043151">"Miniatyrvy"</string>
<string name="switch_to_list" msgid="8900531247982121055">"Listvy"</string>
<string name="current_page" msgid="7510129573681663135">"från "</string>
- <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort."</string>
+ <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort. "</string>
<string name="open_in_new_window" msgid="6596775546468054510">"Öppna i nytt fönster"</string>
<string name="goto_dot" msgid="3895839050522602723">"Kör"</string>
<string name="find_dot" msgid="6259312434696611957">"Sök på sidan"</string>
<item>Android</item>
<item>Desktop</item>
<item>iPhone</item>
+ <item>iPad</item>
+ <item>Froyo-N1</item>
</string-array>
<!-- Do not tranlsate. Development option -->
<string-array name="pref_development_ua_values" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
+ <item>3</item>
+ <item>4</item>
</string-array>
<string name="pref_development_error_console" translatable="false">Show JavaScript Console</string>
<!-- Settings screen, setting option name -->
<item name="android:windowContentOverlay">@null</item>
</style>
- <style name="FindDialog">
- <item name="android:windowEnterAnimation">@anim/find_dialog_enter</item>
- <item name="android:windowExitAnimation">@anim/find_dialog_exit</item>
- </style>
-
<style name="TitleBar">
<item name="android:windowEnterAnimation">@anim/title_bar_enter</item>
<item name="android:windowExitAnimation">@anim/title_bar_exit</item>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 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.
--->
-
-<resources>
- <style name="FindDialogTheme">
- <item name="android:windowFrame">@null</item>
- <item name="android:windowIsFloating">true</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:background">@null</item>
- <item name="android:windowBackground">@null</item>
- <item name="android:windowAnimationStyle">@style/FindDialog</item>
- <item name="android:backgroundDimEnabled">false</item>
- </style>
-</resources>
attachTabToContentView(mTabControl.getCurrentTab());
}
+ // Delete old thumbnails to save space
+ File dir = mTabControl.getThumbnailDir();
+ if (dir.exists()) {
+ for (String child : dir.list()) {
+ File f = new File(dir, child);
+ f.delete();
+ }
+ }
+
// Read JavaScript flags if it exists.
String jsFlags = mSettings.getJsFlags();
if (jsFlags.trim().length() != 0) {
if (mainView == null) {
return;
}
+ // Do not need to check for null, since the current tab will have
+ // at least a main WebView, or we would have returned above.
+ if (dialogIsUp()) {
+ // Do not show the fake title bar, which would cover up the
+ // find or select dialog.
+ return;
+ }
WindowManager manager
= (WindowManager) getSystemService(Context.WINDOW_SERVICE);
getTopWindow().requestFocus();
}
+ private WebView showDialog(WebDialog dialog) {
+ // Need to do something special for Tablet
+ Tab tab = mTabControl.getCurrentTab();
+ if (tab.getSubWebView() == null) {
+ // If the find or select is being performed on the main webview,
+ // remove the embedded title bar.
+ WebView mainView = tab.getWebView();
+ if (mainView != null) {
+ mainView.setEmbeddedTitleBar(null);
+ }
+ }
+ hideFakeTitleBar();
+ mMenuState = EMPTY_MENU;
+ return tab.showDialog(dialog);
+ }
+
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!mCanChord) {
break;
case R.id.find_menu_id:
- if (null == mFindDialog) {
- mFindDialog = new FindDialog(this);
- }
- mFindDialog.setWebView(getTopWindow());
- mFindDialog.show();
- getTopWindow().setFindIsUp(true);
- mMenuState = EMPTY_MENU;
+ showFindDialog();
break;
case R.id.select_text_id:
- getTopWindow().emulateShiftHeld();
+ showSelectDialog();
break;
+
case R.id.page_info_menu_id:
showPageInfo(mTabControl.getCurrentTab(), false);
break;
return true;
}
- public void closeFind() {
+ private boolean dialogIsUp() {
+ return null != mFindDialog && mFindDialog.isVisible() ||
+ null != mSelectDialog && mSelectDialog.isVisible();
+ }
+
+ private boolean closeDialog(WebDialog dialog) {
+ if (null == dialog || !dialog.isVisible()) return false;
+ Tab currentTab = mTabControl.getCurrentTab();
+ currentTab.closeDialog(dialog);
+ dialog.dismiss();
+ return true;
+ }
+
+ /*
+ * Remove the find dialog or select dialog.
+ */
+ public void closeDialogs() {
+ if (!(closeDialog(mFindDialog) || closeDialog(mSelectDialog))) return;
+ // If the Find was being performed in the main WebView, replace the
+ // embedded title bar.
+ Tab currentTab = mTabControl.getCurrentTab();
+ if (currentTab.getSubWebView() == null) {
+ WebView mainView = currentTab.getWebView();
+ if (mainView != null) {
+ mainView.setEmbeddedTitleBar(mTitleBar);
+ }
+ }
mMenuState = R.id.MAIN_MENU;
+ if (mInLoad) {
+ // The title bar was hidden, because otherwise it would cover up the
+ // find or select dialog. Now that the dialog has been removed,
+ // show the fake title bar once again.
+ showFakeTitleBar();
+ }
+ }
+
+ public void showFindDialog() {
+ if (null == mFindDialog) {
+ mFindDialog = new FindDialog(this);
+ }
+ showDialog(mFindDialog).setFindIsUp(true);
+ }
+
+ public void setFindDialogText(String text) {
+ mFindDialog.setText(text);
+ }
+
+ public void showSelectDialog() {
+ if (null == mSelectDialog) {
+ mSelectDialog = new SelectDialog(this);
+ }
+ showDialog(mSelectDialog).setUpSelect();
+ mSelectDialog.hideSoftInput();
}
@Override
onProgressChanged(view, INITIAL_PROGRESS);
mDidStopLoad = false;
if (!mIsNetworkUp) createAndShowNetworkDialog();
-
+ closeDialogs();
if (mSettings.isTracing()) {
String host;
try {
// Nothing to do.
return;
}
+ Tab t = mTabControl.getCurrentTab();
+ if (t == null) {
+ // There is no current tab so we cannot toggle the error console
+ return;
+ }
mShouldShowErrorConsole = flag;
- ErrorConsoleView errorConsole = mTabControl.getCurrentTab()
- .getErrorConsole(true);
+ ErrorConsoleView errorConsole = t.getErrorConsole(true);
if (flag) {
// Setting the show state of the console will cause it's the layout to be inflated.
private Menu mMenu;
private FindDialog mFindDialog;
+ private SelectDialog mSelectDialog;
// Used to prevent chording to result in firing two shortcuts immediately
// one after another. Fixes bug 1211714.
boolean mCanChord;
savedVersion = in.readInt();
} catch (EOFException e) {
// It means we had no previous state; that's fine
+ } finally {
+ if (in != null) {
+ in.close();
+ }
}
// Build a flattened representation of the bookmarks table
} catch (IOException ioe) {
Log.w(TAG, "Bad backup data; not restoring");
crc = -1;
+ } finally {
+ if (in != null) {
+ in.close();
+ }
}
}
}
}
- class Bookmark {
+ static class Bookmark {
public String url;
public int visits;
public long date;
data.writeEntityHeader(key, toCopy);
FileInputStream in = new FileInputStream(file);
- int nRead;
- while (toCopy > 0) {
- nRead = in.read(buf, 0, CHUNK);
- data.writeEntityData(buf, nRead);
- toCopy -= nRead;
+ try {
+ int nRead;
+ while (toCopy > 0) {
+ nRead = in.read(buf, 0, CHUNK);
+ data.writeEntityData(buf, nRead);
+ toCopy -= nRead;
+ }
+ } finally {
+ if (in != null) {
+ in.close();
+ }
}
- in.close();
}
// Read the given file from backup to a file, calculating a CRC32 along the way
CRC32 crc = new CRC32();
FileOutputStream out = new FileOutputStream(file);
- while (toRead > 0) {
- int numRead = data.readEntityData(buf, 0, CHUNK);
- crc.update(buf, 0, numRead);
- out.write(buf, 0, numRead);
- toRead -= numRead;
+ try {
+ while (toRead > 0) {
+ int numRead = data.readEntityData(buf, 0, CHUNK);
+ crc.update(buf, 0, numRead);
+ out.write(buf, 0, numRead);
+ toRead -= numRead;
+ }
+ } finally {
+ if (out != null) {
+ out.close();
+ }
}
-
- out.close();
return crc.getValue();
}
throws IOException {
DataOutputStream out = new DataOutputStream(
new FileOutputStream(stateFile.getFileDescriptor()));
- out.writeLong(fileSize);
- out.writeLong(crc);
- out.writeInt(BACKUP_AGENT_VERSION);
+ try {
+ out.writeLong(fileSize);
+ out.writeLong(crc);
+ out.writeInt(BACKUP_AGENT_VERSION);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
}
}
} else {
ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
}
- ed.commit();
+ ed.apply();
if (mBookmarksAdapter != null) {
mBookmarksAdapter.switchViewMode(viewMode);
fixPicasaBookmark();
Editor ed = p.edit();
ed.putBoolean("fix_picasa", false);
- ed.commit();
+ ed.apply();
}
}
mSettings = BrowserSettings.getInstance();
"privacy_clear_geolocation_access";
private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
- "U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, " +
- "like Gecko) Version/4.0 Safari/530.17";
+ "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
+ "like Gecko) Version/5.0 Safari/533.16";
private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
- "CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 " +
- "(KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";
+ "CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 " +
+ "(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";
+
+ private static final String IPAD_USERAGENT = "Mozilla/5.0 (iPad; U; " +
+ "CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 " +
+ "(KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10";
+
+ private static final String FROYO_USERAGENT = "Mozilla/5.0 (Linux; U; " +
+ "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " +
+ "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
// Value to truncate strings when adding them to a TextView within
// a ListView
s.setUserAgentString(DESKTOP_USERAGENT);
} else if (b.userAgent == 2) {
s.setUserAgentString(IPHONE_USERAGENT);
+ } else if (b.userAgent == 3) {
+ s.setUserAgentString(IPAD_USERAGENT);
+ } else if (b.userAgent == 4) {
+ s.setUserAgentString(FROYO_USERAGENT);
}
s.setUseWideViewPort(b.useWideViewPort);
s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
Editor ed = PreferenceManager.
getDefaultSharedPreferences(context).edit();
ed.putString(PREF_HOMEPAGE, url);
- ed.commit();
+ ed.apply();
homeUrl = url;
}
/* package */ void clearFormData(Context context) {
WebViewDatabase.getInstance(context).clearFormData();
if (mTabControl != null) {
- mTabControl.getCurrentTopWebView().clearFormData();
+ WebView currentTopView = mTabControl.getCurrentTopWebView();
+ if (currentTopView != null) {
+ currentTopView.clearFormData();
+ }
}
}
reset();
SharedPreferences p =
PreferenceManager.getDefaultSharedPreferences(ctx);
- p.edit().clear().commit();
+ p.edit().clear().apply();
PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
true);
// reset homeUrl
* This class is an adapter for ErrorConsoleListView that contains the error console
* message data.
*/
- private class ErrorConsoleMessageList extends android.widget.BaseAdapter
+ private static class ErrorConsoleMessageList extends android.widget.BaseAdapter
implements android.widget.ListAdapter {
private Vector<ConsoleMessage> mMessages;
package com.android.browser;
-import android.app.Dialog;
import android.content.Context;
-import android.os.Bundle;
import android.text.Editable;
+import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.EditText;
+import android.widget.LinearLayout;
import android.widget.TextView;
-/* package */ class FindDialog extends Dialog implements TextWatcher {
- private WebView mWebView;
+/* package */ class FindDialog extends WebDialog implements TextWatcher {
private TextView mMatches;
- private BrowserActivity mBrowserActivity;
// Views with which the user can interact.
private EditText mEditText;
private View mPrevButton;
private View mMatchesView;
+ // When the dialog is opened up with old text, enter needs to be pressed
+ // (or the text needs to be changed) before WebView.findAll can be called.
+ // Once it has been called, enter should move to the next match.
+ private boolean mMatchesFound;
+ private int mNumberOfMatches;
+
private View.OnClickListener mFindListener = new View.OnClickListener() {
public void onClick(View v) {
findNext();
}
};
- private View.OnClickListener mFindCancelListener =
- new View.OnClickListener() {
- public void onClick(View v) {
- dismiss();
- }
- };
-
- private View.OnClickListener mFindPreviousListener =
+ private View.OnClickListener mFindPreviousListener =
new View.OnClickListener() {
public void onClick(View v) {
if (mWebView == null) {
throw new AssertionError("No WebView for FindDialog::onClick");
}
mWebView.findNext(false);
+ updateMatchesString();
hideSoftInput();
}
};
- /*
- * Remove the soft keyboard from the screen.
- */
- private void hideSoftInput() {
- InputMethodManager imm = (InputMethodManager)
- mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
- }
-
private void disableButtons() {
mPrevButton.setEnabled(false);
mNextButton.setEnabled(false);
mNextButton.setFocusable(false);
}
- /* package */ void setWebView(WebView webview) {
- mWebView = webview;
- }
-
/* package */ FindDialog(BrowserActivity context) {
- super(context, R.style.FindDialogTheme);
- mBrowserActivity = context;
- setCanceledOnTouchOutside(true);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super(context);
- Window theWindow = getWindow();
- theWindow.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL);
-
- setContentView(R.layout.browser_find);
-
- theWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
+ LayoutInflater factory = LayoutInflater.from(context);
+ factory.inflate(R.layout.browser_find, this);
+ addCancel();
mEditText = (EditText) findViewById(R.id.edit);
View button = findViewById(R.id.next);
button.setOnClickListener(mFindPreviousListener);
mPrevButton = button;
- button = findViewById(R.id.done);
- button.setOnClickListener(mFindCancelListener);
-
mMatches = (TextView) findViewById(R.id.matches);
mMatchesView = findViewById(R.id.matches_view);
disableButtons();
- theWindow.setSoftInputMode(
- WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
}
-
+
+ /**
+ * Called by BrowserActivity.closeDialog. Start the animation to hide
+ * the dialog, inform the WebView that the dialog is being dismissed,
+ * and hide the soft keyboard.
+ */
public void dismiss() {
super.dismiss();
- mBrowserActivity.closeFind();
mWebView.notifyFindDialogDismissed();
+ hideSoftInput();
+ }
+
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ KeyEvent.DispatcherState state = getKeyDispatcherState();
+ if (state != null) {
+ int action = event.getAction();
+ if (KeyEvent.ACTION_DOWN == action
+ && event.getRepeatCount() == 0) {
+ state.startTracking(event, this);
+ return true;
+ } else if (KeyEvent.ACTION_UP == action
+ && !event.isCanceled() && state.isTracking(event)) {
+ mBrowserActivity.closeDialogs();
+ return true;
+ }
+ }
+ }
+ return super.dispatchKeyEventPreIme(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
- && event.getAction() == KeyEvent.ACTION_UP
- && mEditText.hasFocus()) {
- findNext();
- return true;
+ int keyCode = event.getKeyCode();
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER
+ && mEditText.hasFocus()) {
+ if (mMatchesFound) {
+ findNext();
+ } else {
+ findAll();
+ // Set the selection to the end.
+ Spannable span = (Spannable) mEditText.getText();
+ Selection.setSelection(span, span.length());
+ }
+ return true;
+ }
}
return super.dispatchKeyEvent(event);
}
throw new AssertionError("No WebView for FindDialog::findNext");
}
mWebView.findNext(true);
+ updateMatchesString();
hideSoftInput();
}
public void show() {
super.show();
+ // In case the matches view is showing from a previous search
+ mMatchesView.setVisibility(View.INVISIBLE);
+ mMatchesFound = false;
+ // This text is only here to ensure that mMatches has a height.
+ mMatches.setText("0");
mEditText.requestFocus();
- mEditText.setText("");
Spannable span = (Spannable) mEditText.getText();
- span.setSpan(this, 0, span.length(),
- Spannable.SPAN_INCLUSIVE_INCLUSIVE);
- setMatchesFound(0);
+ int length = span.length();
+ Selection.setSelection(span, 0, length);
+ span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
disableButtons();
+ InputMethodManager imm = (InputMethodManager)
+ mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mEditText, 0);
}
// TextWatcher methods
int start,
int before,
int count) {
+ findAll();
+ }
+
+ private void findAll() {
if (mWebView == null) {
throw new AssertionError(
- "No WebView for FindDialog::onTextChanged");
+ "No WebView for FindDialog::findAll");
}
CharSequence find = mEditText.getText();
if (0 == find.length()) {
mMatchesView.setVisibility(View.INVISIBLE);
} else {
mMatchesView.setVisibility(View.VISIBLE);
- mWebView.setFindDialogHeight(
- getWindow().getDecorView().getHeight());
int found = mWebView.findAll(find.toString());
+ mMatchesFound = true;
setMatchesFound(found);
if (found < 2) {
disableButtons();
if (found == 0) {
- setMatchesFound(0);
+ // Cannot use getQuantityString, which ignores the "zero"
+ // quantity.
+ // FIXME: is this fix is beyond the scope
+ // of adding touch selection to gingerbread?
+ // mMatches.setText(mBrowserActivity.getResources().getString(
+ // R.string.no_matches));
}
} else {
mPrevButton.setFocusable(true);
}
private void setMatchesFound(int found) {
+ mNumberOfMatches = found;
+ updateMatchesString();
+ }
+
+ public void setText(String text) {
+ mEditText.setText(text);
+ findAll();
+ }
+
+ private void updateMatchesString() {
+ // Note: updateMatchesString is only called by methods that have already
+ // checked mWebView for null.
String template = mBrowserActivity.getResources().
- getQuantityString(R.plurals.matches_found, found, found);
+ getQuantityString(R.plurals.matches_found, mNumberOfMatches,
+ mWebView.findIndex() + 1, mNumberOfMatches);
mMatches.setText(template);
}
--- /dev/null
+/*
+ * 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.provider.Browser;
+import android.view.LayoutInflater;
+import android.view.View;
+
+/* package */ class SelectDialog extends WebDialog {
+ private View mCopyButton;
+ private View mSelectAllButton;
+ private View mShareButton;
+ private View mFindButton;
+
+ SelectDialog(BrowserActivity context) {
+ super(context);
+ LayoutInflater factory = LayoutInflater.from(context);
+ factory.inflate(R.layout.browser_select, this);
+ addCancel();
+
+ mCopyButton = findViewById(R.id.copy);
+ mCopyButton.setOnClickListener(mCopyListener);
+ mSelectAllButton = findViewById(R.id.select_all);
+ mSelectAllButton.setOnClickListener(mSelectAllListener);
+ mShareButton = findViewById(R.id.share);
+ mShareButton.setOnClickListener(mShareListener);
+ mFindButton = findViewById(R.id.find);
+ mFindButton.setOnClickListener(mFindListener);
+ }
+
+ private View.OnClickListener mCopyListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mWebView.copySelection();
+ mBrowserActivity.closeDialogs();
+ }
+ };
+
+ private View.OnClickListener mSelectAllListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mWebView.selectAll();
+ }
+ };
+
+ private View.OnClickListener mShareListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ String selection = mWebView.getSelection();
+ Browser.sendString(mBrowserActivity, selection);
+ mBrowserActivity.closeDialogs();
+ }
+ };
+
+ private View.OnClickListener mFindListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ String selection = mWebView.getSelection();
+ mBrowserActivity.closeDialogs();
+ mBrowserActivity.showFindDialog();
+ mBrowserActivity.setFindDialogText(selection);
+ }
+ };
+
+ /**
+ * Called by BrowserActivity.closeDialog. Start the animation to hide
+ * the dialog, and inform the WebView that the dialog is being dismissed.
+ */
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ mWebView.notifySelectDialogDismissed();
+ }
+
+}
// Save the new value as the last read value
preferences.edit()
.putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
- .commit();
+ .apply();
Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
// The Geolocation permissions prompt
private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
// Main WebView wrapper
- private View mContainer;
+ private LinearLayout mContainer;
// Main WebView
private WebView mMainView;
// Subwindow container
static final String CURRTAB = "currentTab";
static final String CURRURL = "currentUrl";
static final String CURRTITLE = "currentTitle";
- static final String CURRPICTURE = "currentPicture";
static final String CLOSEONEXIT = "closeonexit";
static final String PARENTTAB = "parentTab";
static final String APPID = "appid";
return mVoiceSearchData != null;
}
/**
- * Return true if the voice search Intent came with a String identifying
- * that Google provided the Intent.
+ * Return true if the Tab is in voice search mode and the voice search
+ * Intent came with a String identifying that Google provided the Intent.
*/
public boolean voiceSearchSourceIsGoogle() {
return mVoiceSearchData != null && mVoiceSearchData.mSourceIsGoogle;
// return true if want to hijack the url to let another app to handle it
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ if (voiceSearchSourceIsGoogle()) {
+ // This method is called when the user clicks on a link.
+ // VoiceSearchMode is turned off when the user leaves the
+ // Google results page, so at this point the user must be on
+ // that page. If the user clicked a link on that page, assume
+ // that the voice search was effective, and broadcast an Intent
+ // so a receiver can take note of that fact.
+ Intent logIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT);
+ logIntent.putExtra(LoggingEvents.EXTRA_EVENT,
+ LoggingEvents.VoiceSearch.RESULT_CLICKED);
+ mActivity.sendBroadcast(logIntent);
+ }
if (mInForeground) {
return mActivity.shouldOverrideUrlLoading(view, url);
} else {
} else if (url.startsWith("http://")) {
url = url.substring(4);
}
+ // Escape wildcards for LIKE operator.
+ url = url.replace("\\", "\\\\").replace("%", "\\%")
+ .replace("_", "\\_");
Cursor c = null;
try {
final ContentResolver cr
url = "%" + url;
String [] selArgs = new String[] { url };
String where = Browser.BookmarkColumns.URL
- + " LIKE ? AND "
+ + " LIKE ? ESCAPE '\\' AND "
+ Browser.BookmarkColumns.BOOKMARK + " = 0";
c = cr.query(Browser.BOOKMARKS_URI, new String[]
{ Browser.BookmarkColumns._ID }, where, selArgs,
}
@Override
+ public void onSelectionDone(WebView view) {
+ if (mInForeground) mActivity.closeDialogs();
+ }
+
+ @Override
+ public void onSelectionStart(WebView view) {
+ if (false && mInForeground) mActivity.showSelectDialog();
+ }
+
+ @Override
public void onShowCustomView(View view,
WebChromeClient.CustomViewCallback callback) {
if (mInForeground) mActivity.onShowCustomView(view, callback);
private static class SubWindowClient extends WebViewClient {
// The main WebViewClient.
private final WebViewClient mClient;
+ private final BrowserActivity mBrowserActivity;
- SubWindowClient(WebViewClient client) {
+ SubWindowClient(WebViewClient client, BrowserActivity activity) {
mClient = client;
+ mBrowserActivity = activity;
+ }
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ // Unlike the others, do not call mClient's version, which would
+ // change the progress bar. However, we do want to remove the
+ // find or select dialog.
+ mBrowserActivity.closeDialogs();
}
@Override
public void doUpdateVisitedHistory(WebView view, String url,
// The tab consists of a container view, which contains the main
// WebView, as well as any other UI elements associated with the tab.
- mContainer = mInflateService.inflate(R.layout.tab, null);
+ mContainer = (LinearLayout) mInflateService.inflate(R.layout.tab, null);
mDownloadListener = new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
*/
boolean createSubWindow() {
if (mSubView == null) {
+ mActivity.closeDialogs();
mSubViewContainer = mInflateService.inflate(
R.layout.browser_subwindow, null);
mSubView = (WebView) mSubViewContainer.findViewById(R.id.webview);
mSubView.setMapTrackballToArrowKeys(false);
// Enable the built-in zoom
mSubView.getSettings().setBuiltInZoomControls(true);
- mSubView.setWebViewClient(new SubWindowClient(mWebViewClient));
+ mSubView.setWebViewClient(new SubWindowClient(mWebViewClient,
+ mActivity));
mSubView.setWebChromeClient(new SubWindowChromeClient(
mWebChromeClient));
// Set a different DownloadListener for the mSubView, since it will
if (mSubView.copyBackForwardList().getSize() == 0) {
// This subwindow was opened for the sole purpose of
// downloading a file. Remove it.
- dismissSubWindow();
+ mActivity.dismissSubWindow(Tab.this);
}
}
});
*/
void dismissSubWindow() {
if (mSubView != null) {
+ mActivity.closeDialogs();
BrowserSettings.getInstance().deleteObserver(
mSubView.getSettings());
mSubView.destroy();
void removeSubWindow(ViewGroup content) {
if (mSubView != null) {
content.removeView(mSubViewContainer);
+ mActivity.closeDialogs();
}
}
(FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
wrapper.removeView(mMainView);
content.removeView(mContainer);
+ mActivity.closeDialogs();
removeSubWindow(content);
}
mSavedState = new Bundle();
final WebBackForwardList list = mMainView.saveState(mSavedState);
- if (list != null) {
- final File f = new File(mActivity.getTabControl().getThumbnailDir(),
- mMainView.hashCode() + "_pic.save");
- if (mMainView.savePicture(mSavedState, f)) {
- mSavedState.putString(CURRPICTURE, f.getPath());
- } else {
- // if savePicture returned false, we can't trust the contents,
- // and it may be large, so we delete it right away
- f.delete();
- }
- }
// Store some extra info for displaying the tab in the picker.
final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
if (list == null) {
return false;
}
- if (b.containsKey(CURRPICTURE)) {
- final File f = new File(b.getString(CURRPICTURE));
- mMainView.restorePicture(b, f);
- f.delete();
- }
return true;
}
+
+ /*
+ * Opens the find and select text dialogs. Called by BrowserActivity.
+ */
+ WebView showDialog(WebDialog dialog) {
+ LinearLayout container;
+ WebView view;
+ if (mSubView != null) {
+ view = mSubView;
+ container = (LinearLayout) mSubViewContainer.findViewById(
+ R.id.inner_container);
+ } else {
+ view = mMainView;
+ container = mContainer;
+ }
+ dialog.show();
+ container.addView(dialog, 0, new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ dialog.setWebView(view);
+ return view;
+ }
+
+ /*
+ * Close the find or select dialog. Called by BrowserActivity.closeDialog.
+ */
+ void closeDialog(WebDialog dialog) {
+ // The dialog may be attached to the subwindow. Ensure that the
+ // correct parent has it removed.
+ LinearLayout parent = (LinearLayout) dialog.getParent();
+ if (parent != null) parent.removeView(dialog);
+ }
}
}
}
- // This tab may have been pushed in to the background and then closed.
- // If the saved state contains a picture file, delete the file.
- Bundle savedState = t.getSavedState();
- if (savedState != null) {
- if (savedState.containsKey(Tab.CURRPICTURE)) {
- new File(savedState.getString(Tab.CURRPICTURE)).delete();
- }
- }
-
// Remove it from the queue of viewed tabs.
mTabQueue.remove(t);
return true;
--- /dev/null
+/*
+ * 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.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+
+/* package */ class WebDialog extends LinearLayout {
+ protected WebView mWebView;
+ protected BrowserActivity mBrowserActivity;
+ private boolean mIsVisible;
+
+ /* package */ WebDialog(BrowserActivity context) {
+ super(context);
+ mBrowserActivity = context;
+ }
+
+ /* dialogs that have cancel buttons can optionally share code by including a
+ * view with an id of 'done'.
+ */
+ protected void addCancel() {
+ View button = findViewById(R.id.done);
+ if (button != null) button.setOnClickListener(mCancelListener);
+ }
+
+ private View.OnClickListener mCancelListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mBrowserActivity.closeDialogs();
+ }
+ };
+
+ protected void dismiss() {
+ startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+ R.anim.dialog_exit));
+ mIsVisible = false;
+ }
+
+ /*
+ * Remove the soft keyboard from the screen.
+ */
+ protected void hideSoftInput() {
+ InputMethodManager imm = (InputMethodManager)
+ mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
+ }
+
+ protected boolean isVisible() {
+ return mIsVisible;
+ }
+
+ /* package */ void setWebView(WebView webview) {
+ mWebView = webview;
+ }
+
+ protected void show() {
+ startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+ R.anim.dialog_enter));
+ mIsVisible = true;
+ }
+
+}
private static String sMBStored = null;
private SiteAdapter mAdapter = null;
- class Site {
+ static class Site {
private String mOrigin;
private String mTitle;
private Bitmap mIcon;
* Adds the specified feature to the site corresponding to supplied
* origin in the map. Creates the site if it does not already exist.
*/
- private void addFeatureToSite(Map sites, String origin, int feature) {
+ private void addFeatureToSite(Map<String, Site> sites, String origin, int feature) {
Site site = null;
if (sites.containsKey(origin)) {
site = (Site) sites.get(origin);
WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
public void onReceiveValue(Map origins) {
- Map sites = new HashMap<String, Site>();
+ Map<String, Site> sites = new HashMap<String, Site>();
if (origins != null) {
Iterator<String> iter = origins.keySet().iterator();
while (iter.hasNext()) {
});
}
- public void askForGeolocation(final Map sites) {
+ public void askForGeolocation(final Map<String, Site> sites) {
GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set<String> >() {
public void onReceiveValue(Set<String> origins) {
if (origins != null) {
});
}
- public void populateIcons(Map sites) {
+ public void populateIcons(Map<String, Site> sites) {
// Create a map from host to origin. This is used to add metadata
// (title, icon) for this origin from the bookmarks DB.
- HashMap hosts = new HashMap<String, Set<Site> >();
- Set keys = sites.keySet();
- Iterator<String> originIter = keys.iterator();
+ HashMap<String, Set<Site>> hosts = new HashMap<String, Set<Site>>();
+ Set<Map.Entry<String, Site>> elements = sites.entrySet();
+ Iterator<Map.Entry<String, Site>> originIter = elements.iterator();
while (originIter.hasNext()) {
- String origin = originIter.next();
- Site site = (Site) sites.get(origin);
- String host = Uri.parse(origin).getHost();
- Set hostSites = null;
+ Map.Entry<String, Site> entry = originIter.next();
+ Site site = entry.getValue();
+ String host = Uri.parse(entry.getKey()).getHost();
+ Set<Site> hostSites = null;
if (hosts.containsKey(host)) {
- hostSites = (Set) hosts.get(host);
+ hostSites = (Set<Site>)hosts.get(host);
} else {
hostSites = new HashSet<Site>();
hosts.put(host, hostSites);
new String[] { Browser.BookmarkColumns.URL, Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.FAVICON }, "bookmark = 1", null, null);
- if ((c != null) && c.moveToFirst()) {
- int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
- int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
- int faviconIndex = c.getColumnIndex(Browser.BookmarkColumns.FAVICON);
- do {
- String url = c.getString(urlIndex);
- String host = Uri.parse(url).getHost();
- if (hosts.containsKey(host)) {
- String title = c.getString(titleIndex);
- Bitmap bmp = null;
- byte[] data = c.getBlob(faviconIndex);
- if (data != null) {
- bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
- }
- Set matchingSites = (Set) hosts.get(host);
- Iterator<Site> sitesIter = matchingSites.iterator();
- while (sitesIter.hasNext()) {
- Site site = sitesIter.next();
- // We should only set the title if the bookmark is for the root
- // (i.e. www.google.com), as website settings act on the origin
- // as a whole rather than a single page under that origin. If the
- // user has bookmarked a page under the root but *not* the root,
- // then we risk displaying the title of that page which may or
- // may not have any relevance to the origin.
- if (url.equals(site.getOrigin()) ||
- (new String(site.getOrigin()+"/")).equals(url)) {
- site.setTitle(title);
+ if (c != null) {
+ if (c.moveToFirst()) {
+ int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
+ int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
+ int faviconIndex = c.getColumnIndex(Browser.BookmarkColumns.FAVICON);
+ do {
+ String url = c.getString(urlIndex);
+ String host = Uri.parse(url).getHost();
+ if (hosts.containsKey(host)) {
+ String title = c.getString(titleIndex);
+ Bitmap bmp = null;
+ byte[] data = c.getBlob(faviconIndex);
+ if (data != null) {
+ bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
}
- if (bmp != null) {
- site.setIcon(bmp);
+ Set matchingSites = (Set) hosts.get(host);
+ Iterator<Site> sitesIter = matchingSites.iterator();
+ while (sitesIter.hasNext()) {
+ Site site = sitesIter.next();
+ // We should only set the title if the bookmark is for the root
+ // (i.e. www.google.com), as website settings act on the origin
+ // as a whole rather than a single page under that origin. If the
+ // user has bookmarked a page under the root but *not* the root,
+ // then we risk displaying the title of that page which may or
+ // may not have any relevance to the origin.
+ if (url.equals(site.getOrigin()) ||
+ (new String(site.getOrigin()+"/")).equals(url)) {
+ site.setTitle(title);
+ }
+ if (bmp != null) {
+ site.setIcon(bmp);
+ }
}
}
- }
- } while (c.moveToNext());
+ } while (c.moveToNext());
+ }
+ c.close();
}
-
- c.close();
}
- public void populateOrigins(Map sites) {
+ public void populateOrigins(Map<String, Site> sites) {
clear();
// We can now simply populate our array with Site instances
- Set keys = sites.keySet();
- Iterator<String> originIter = keys.iterator();
- while (originIter.hasNext()) {
- String origin = originIter.next();
- Site site = (Site) sites.get(origin);
+ Set<Map.Entry<String, Site>> elements = sites.entrySet();
+ Iterator<Map.Entry<String, Site>> entryIterator = elements.iterator();
+ while (entryIterator.hasNext()) {
+ Map.Entry<String, Site> entry = entryIterator.next();
+ Site site = entry.getValue();
add(site);
}
function runTests() {
// Assume that if the test isn't done after 10s that we failed.
- window.setTimeout(function() { JNIBindingsTest.testComplete(); }, 10000);
+ window.setTimeout(function() { JNIBindingsTest.notifyComplete(); }, 10000);
if (testPrimitiveTypes()) {
appendLog("testPrimitiveTypes passed!");
appendLog("testParameterTypeMismatch failed!");
}
- JNIBindingsTest.testComplete();
+ JNIBindingsTest.notifyComplete();
}
</script>
import android.util.Log;
import java.util.Arrays;
+
import junit.framework.AssertionFailedError;
public class JNIBindingsTest extends AndroidTestCase {
mTestApp = testApp;
}
- public void testComplete() {
+ public void notifyComplete() {
Log.v(LOGTAG, "Completing the test.");
- mTestApp.testComplete();
+ mTestApp.notifyComplete();
}
public void printAssertionFailed(AssertionFailedError e) {
assertEquals(expectedIntParam, intParam);
assertEquals(expectedDoubleParam, doubleParam);
assertEquals(expectedBooleanParam, booleanParam);
- assertEquals(expectedCharParam, charParam);;
+ assertEquals(expectedCharParam, charParam);
// EMULATE_JSC_BINDINGS JSC passes "undefined" for undefined types.
assertEquals(expectedUndefinedParam, undefinedParam);
import android.app.Instrumentation;
import android.net.http.SslError;
-import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
/**
* Adds a JavaScript interface to the webview and calls functions on it to verify variables
* are passed from JS to Java correctly.
private final static String TAG = "JNIBindingsTest";
+ private static final String SDCARD_BINDINGS_TEST_HTML = "/sdcard/bindings_test.html";
+
private static final int MSG_WEBKIT_DATA_READY = 101;
private BrowserActivity mActivity = null;
mWebView = webView;
}
+ @Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_WEBKIT_DATA_READY: {
mInst = getInstrumentation();
mInst.waitForIdleSync();
+ extractAsset();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ removeAsset();
+ super.tearDown();
+ }
+
+ protected void extractAsset() throws IOException {
+ InputStream in = getInstrumentation().getContext().getAssets().open("bindings_test.html");
+ OutputStream out = new FileOutputStream(SDCARD_BINDINGS_TEST_HTML);
+
+ byte[] buf = new byte[2048];
+ int len;
+
+ while ((len = in.read(buf)) >= 0 ) {
+ out.write(buf, 0, len);
+ }
+ out.close();
+ in.close();
+ }
+
+ protected void removeAsset(){
+ File fileToDelete = new File(SDCARD_BINDINGS_TEST_HTML);
+ fileToDelete.delete();
}
/**
});
}
- public synchronized void testComplete() {
+ public synchronized void notifyComplete() {
mTestDone = true;
notify();
}
Tab tab = mActivity.getTabControl().getCurrentTab();
WebView webView = tab.getWebView();
- webView.loadUrl("file:///sdcard/bindings_test.html");
+ webView.loadUrl("file://" + SDCARD_BINDINGS_TEST_HTML);
synchronized(this) {
while(!mTestDone) {
try {
package com.android.browser;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
import android.app.Instrumentation;
import android.content.Intent;
import android.net.Uri;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
*
* Iterates over a list of URLs from a file and outputs the time to load each.
private Instrumentation mInst = null;
private CountDownLatch mLatch = new CountDownLatch(1);
private RunStatus mStatus;
+ private boolean pageLoadFinishCalled, pageProgressFull;
public PopularUrlsTest() {
super(BrowserActivity.class);
protected void setUp() throws Exception {
super.setUp();
+ Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("about:blank"));
+ setActivityIntent(i);
mActivity = getActivity();
mInst = getInstrumentation();
mInst.waitForIdleSync();
webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) {
- /**
- * Reset the latch whenever page progress reaches 100%.
- */
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress >= 100) {
- resetLatch();
+ if (!pageProgressFull) {
+ // void duplicate calls
+ pageProgressFull = true;
+ if (pageLoadFinishCalled) {
+ //reset latch and move forward only if both indicators are true
+ resetLatch();
+ }
+ }
}
}
String host, String realm) {
handler.proceed("user", "passwd");
}
+
+ /* (non-Javadoc)
+ * @see com.android.browser.TestWebViewClient#onPageFinished(android.webkit.WebView, java.lang.String)
+ */
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ if (!pageLoadFinishCalled) {
+ pageLoadFinishCalled = true;
+ if (pageProgressFull) {
+ //reset latch and move forward only if both indicators are true
+ resetLatch();
+ }
+ }
+ }
+
});
}
void resetLatch() {
- CountDownLatch temp = mLatch;
- mLatch = new CountDownLatch(1);
- if (temp != null) {
- // Notify existing latch that it's done.
- while (temp.getCount() > 0) {
- temp.countDown();
- }
+ if (mLatch.getCount() != 1) {
+ Log.w(TAG, "Expecting latch to be 1, but it's not!");
+ } else {
+ mLatch.countDown();
}
}
+ void resetForNewPage() {
+ mLatch = new CountDownLatch(1);
+ pageLoadFinishCalled = false;
+ pageProgressFull = false;
+ }
+
void waitForLoad() throws InterruptedException {
boolean timedout = !mLatch.await(PAGE_LOAD_TIMEOUT, TimeUnit.MILLISECONDS);
if (timedout) {
mFile = new File(file);
FileReader input = null;
BufferedReader reader = null;
+ isRecovery = false;
+ iteration = 0;
+ page = 0;
try {
input = new FileReader(mFile);
isRecovery = true;
reader = new BufferedReader(input);
- iteration = Integer.parseInt(reader.readLine());
- page = Integer.parseInt(reader.readLine());
+ String line = reader.readLine();
+ if (line == null)
+ return;
+ iteration = Integer.parseInt(line);
+ line = reader.readLine();
+ if (line == null)
+ return;
+ page = Integer.parseInt(line);
} catch (FileNotFoundException ex) {
- isRecovery = false;
- iteration = 0;
- page = 0;
+ return;
+ } catch (NumberFormatException nfe) {
+ Log.wtf(TAG, "unexpected data in status file, will start from begining");
+ return;
} finally {
try {
if (reader != null) {
public void write() throws IOException {
FileWriter output = null;
- OutputStreamWriter writer = null;
if (mFile.exists()) {
mFile.delete();
}
output.write(page + newLine);
output.write(url + newLine);
} finally {
- try {
- if (writer != null) {
- writer.close();
- }
- } finally {
- if (output != null) {
- output.close();
- }
+ if (output != null) {
+ output.close();
}
}
}
if (mStatus.getIsRecovery()) {
Log.e(TAG, "Recovering after crash: " + iterator.next());
+ mStatus.incrementPage();
}
while (mStatus.getIteration() < loopCount) {
+ if (clearCache) {
+ webView.clearCache(true);
+ }
while(iterator.hasNext()) {
page = iterator.next();
mStatus.setUrl(page);
mStatus.write();
Log.i(TAG, "start: " + page);
Uri uri = Uri.parse(page);
- if (clearCache) {
- webView.clearCache(true);
- }
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
long startTime = System.currentTimeMillis();
+ resetForNewPage();
mInst.runOnMainSync(new Runnable() {
public void run() {
bufferedReader.close();
}
}
+ } catch (FileNotFoundException fnfe) {
+ Log.e(TAG, fnfe.getMessage(), fnfe);
+ fail("Test environment not setup correctly");
} finally {
if (writer != null) {
writer.close();
BufferedReader bufferedReader = getInputStream();
try {
loopUrls(bufferedReader, null, true, STABILITY_LOOPCOUNT);
+ } catch (FileNotFoundException fnfe) {
+ Log.e(TAG, fnfe.getMessage(), fnfe);
+ fail("Test environment not setup correctly");
} finally {
if (bufferedReader != null) {
bufferedReader.close();