summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/browser/ActiveTabsPage.java273
-rw-r--r--src/com/android/browser/AddBookmarkPage.java540
-rw-r--r--src/com/android/browser/AutoFillSettingsFragment.java8
-rw-r--r--src/com/android/browser/AutofillHandler.java202
-rw-r--r--src/com/android/browser/BaseUi.java146
-rw-r--r--src/com/android/browser/BookmarkDragHandler.java116
-rw-r--r--src/com/android/browser/BookmarkItem.java20
-rw-r--r--src/com/android/browser/BookmarkUtils.java6
-rw-r--r--src/com/android/browser/BookmarksLoader.java4
-rw-r--r--src/com/android/browser/BreadCrumbView.java15
-rw-r--r--src/com/android/browser/Browser.java10
-rw-r--r--src/com/android/browser/BrowserActivity.java11
-rw-r--r--src/com/android/browser/BrowserBookmarksAdapter.java10
-rw-r--r--src/com/android/browser/BrowserBookmarksPage.java390
-rw-r--r--src/com/android/browser/BrowserHistoryPage.java83
-rw-r--r--src/com/android/browser/BrowserPreferencesPage.java13
-rw-r--r--src/com/android/browser/BrowserSettings.java1234
-rw-r--r--src/com/android/browser/BrowserWebView.java (renamed from src/com/android/browser/ScrollWebView.java)35
-rw-r--r--src/com/android/browser/BrowserYesNoPreference.java32
-rw-r--r--src/com/android/browser/CombinedBookmarkHistoryView.java16
-rw-r--r--src/com/android/browser/Controller.java285
-rw-r--r--src/com/android/browser/CrashRecoveryHandler.java120
-rw-r--r--src/com/android/browser/InstantSearchEngine.java33
-rw-r--r--src/com/android/browser/IntentHandler.java44
-rw-r--r--src/com/android/browser/NavScreen.java457
-rw-r--r--src/com/android/browser/PhoneUi.java335
-rw-r--r--src/com/android/browser/PieControl.java21
-rw-r--r--src/com/android/browser/PreferenceKeys.java98
-rw-r--r--src/com/android/browser/ShortcutActivity.java6
-rw-r--r--src/com/android/browser/SuggestionsAdapter.java9
-rw-r--r--src/com/android/browser/Tab.java137
-rw-r--r--src/com/android/browser/TabBar.java13
-rw-r--r--src/com/android/browser/TabControl.java206
-rw-r--r--src/com/android/browser/TitleBar.java211
-rw-r--r--src/com/android/browser/TitleBarBase.java496
-rw-r--r--src/com/android/browser/TitleBarPhone.java151
-rw-r--r--src/com/android/browser/TitleBarXLarge.java456
-rw-r--r--src/com/android/browser/UI.java4
-rw-r--r--src/com/android/browser/UiController.java11
-rw-r--r--src/com/android/browser/UrlHandler.java133
-rw-r--r--src/com/android/browser/UrlInputView.java6
-rw-r--r--src/com/android/browser/UrlUtils.java34
-rw-r--r--src/com/android/browser/WebViewController.java12
-rw-r--r--src/com/android/browser/XLargeUi.java216
-rw-r--r--src/com/android/browser/addbookmark/FolderSpinnerAdapter.java75
-rw-r--r--src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java2
-rw-r--r--src/com/android/browser/preferences/AccessibilityPreferencesFragment.java84
-rw-r--r--src/com/android/browser/preferences/AdvancedPreferencesFragment.java53
-rw-r--r--src/com/android/browser/preferences/DebugPreferencesFragment.java15
-rw-r--r--src/com/android/browser/preferences/GeneralPreferencesFragment.java12
-rw-r--r--src/com/android/browser/preferences/LabPreferencesFragment.java25
-rw-r--r--src/com/android/browser/preferences/MinFontSizePreference.java170
-rw-r--r--src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java10
-rw-r--r--src/com/android/browser/preferences/WebViewPreview.java106
-rw-r--r--src/com/android/browser/provider/BrowserProvider.java (renamed from src/com/android/browser/BrowserProvider.java)17
-rw-r--r--src/com/android/browser/provider/BrowserProvider2.java209
-rw-r--r--src/com/android/browser/search/SearchEngines.java2
-rw-r--r--src/com/android/browser/view/BookmarkContainer.java92
-rw-r--r--src/com/android/browser/view/BookmarkExpandableGridView.java460
-rw-r--r--src/com/android/browser/view/StopProgressView.java98
-rw-r--r--src/com/android/browser/view/TabHolderView.java (renamed from src/com/android/browser/RlzReceiver.java)46
61 files changed, 5075 insertions, 3059 deletions
diff --git a/src/com/android/browser/ActiveTabsPage.java b/src/com/android/browser/ActiveTabsPage.java
index 664fd68..0feba9a 100644
--- a/src/com/android/browser/ActiveTabsPage.java
+++ b/src/com/android/browser/ActiveTabsPage.java
@@ -18,62 +18,88 @@ package com.android.browser;
import android.content.Context;
import android.graphics.Bitmap;
-import android.os.Handler;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.widget.AbsListView;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
-import android.widget.ListView;
import android.widget.TextView;
-public class ActiveTabsPage extends LinearLayout {
+interface OnCloseTab {
+ void onCloseTab(int position);
+}
- private static final String LOGTAG = "TabPicker";
+public class ActiveTabsPage extends LinearLayout implements OnClickListener,
+ OnItemClickListener, OnCloseTab {
- private final LayoutInflater mFactory;
- private final UiController mUiController;
- private final TabControl mControl;
- private final TabsListAdapter mAdapter;
- private final ListView mListView;
+ private Context mContext;
+ private UiController mController;
+ private TabControl mTabControl;
+ private View mNewTab, mNewIncognitoTab;
+ private TabAdapter mAdapter;
+ private AbsListView mTabsList;
- public ActiveTabsPage(Context context, UiController control) {
+ public ActiveTabsPage(Context context, UiController controller) {
super(context);
- mUiController = control;
- mControl = control.getTabControl();
- mFactory = LayoutInflater.from(context);
- mFactory.inflate(R.layout.active_tabs, this);
- mListView = (ListView) findViewById(R.id.list);
- mAdapter = new TabsListAdapter();
- mListView.setAdapter(mAdapter);
- mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View view,
- int position, long id) {
- if (mControl.canCreateNewTab()) {
- position -= 2;
- }
- boolean needToAttach = false;
- if (position == -2) {
- // Create a new tab
- mUiController.openTabToHomePage();
- } else if (position == -1) {
- // Create a new incognito tab
- mUiController.openIncognitoTab();
- } else {
- // Open the corresponding tab
- // If the tab is the current one, switchToTab will
- // do nothing and return, so we need to make sure
- // it gets attached back to its mContentView in
- // removeActiveTabPage
- needToAttach = !mUiController.switchToTab(position);
- }
- mUiController.removeActiveTabsPage(needToAttach);
- }
- });
+ mContext = context;
+ mController = controller;
+ mTabControl = mController.getTabControl();
+ setOrientation(VERTICAL);
+ setBackgroundResource(R.drawable.bg_browser);
+ LayoutInflater inflate = LayoutInflater.from(mContext);
+ inflate.inflate(R.layout.active_tabs, this, true);
+ mNewTab = findViewById(R.id.new_tab);
+ mNewIncognitoTab = findViewById(R.id.new_incognito_tab);
+ mNewTab.setOnClickListener(this);
+ mNewIncognitoTab.setOnClickListener(this);
+ int visibility = mTabControl.canCreateNewTab() ? View.VISIBLE : View.GONE;
+ mNewTab.setVisibility(visibility);
+ mNewIncognitoTab.setVisibility(visibility);
+ mTabsList = (AbsListView) findViewById(android.R.id.list);
+ mAdapter = new TabAdapter(mContext, mTabControl);
+ mAdapter.setOnCloseListener(this);
+ mTabsList.setAdapter(mAdapter);
+ mTabsList.setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mNewTab) {
+ mController.openTabToHomePage();
+ } else if (v == mNewIncognitoTab) {
+ mController.openIncognitoTab();
+ }
+ mController.removeActiveTabsPage(false);
+ }
+
+ @Override
+ public void onItemClick(
+ AdapterView<?> parent, View view, int position, long id) {
+ final Tab tab = mTabControl.getTab(position);
+ boolean needToAttach = !mController.switchToTab(tab);
+ mController.removeActiveTabsPage(needToAttach);
+ }
+
+ @Override
+ public void onCloseTab(int position) {
+ Tab tab = mTabControl.getTab(position);
+ if (tab != null) {
+ mController.closeTab(tab);
+ if (mTabControl.getTabCount() == 0) {
+ mController.openTabToHomePage();
+ mController.removeActiveTabsPage(false);
+ } else {
+ mAdapter.notifyDataSetChanged();
+ }
+ }
}
/**
@@ -81,7 +107,7 @@ public class ActiveTabsPage extends LinearLayout {
* the parent to be pressed without being pressed itself. This way the line
* of a tab can be pressed, but the close button itself is not.
*/
- private static class CloseHolder extends ImageView {
+ public static class CloseHolder extends ImageView {
public CloseHolder(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -96,118 +122,79 @@ public class ActiveTabsPage extends LinearLayout {
}
}
- private class TabsListAdapter extends BaseAdapter {
- private boolean mNotified = true;
- private int mReturnedCount;
- private Handler mHandler = new Handler();
+ static class TabAdapter extends BaseAdapter implements OnClickListener {
- public int getCount() {
- int count = mControl.getTabCount();
- if (mControl.canCreateNewTab()) {
- count += 2;
- }
- // XXX: This is a workaround to be more like a real adapter. Most
- // adapters call notifyDataSetChanged() whenever the internal data
- // has changed. Since TabControl is our internal data, we don't
- // know when that changes.
- //
- // Keep track of the last count we returned and whether we called
- // notifyDataSetChanged(). If we did not initiate a data set
- // change, and the count is different, send the notify and return
- // the old count.
- if (!mNotified && count != mReturnedCount) {
- notifyChange();
- return mReturnedCount;
- }
- mReturnedCount = count;
- mNotified = false;
- return count;
- }
- public Object getItem(int position) {
- return null;
- }
- public long getItemId(int position) {
- return position;
- }
- public int getViewTypeCount() {
- return 2;
+ LayoutInflater mInflater;
+ OnCloseTab mCloseListener;
+ TabControl mTabControl;
+
+ TabAdapter(Context context, TabControl tabs) {
+ mInflater = LayoutInflater.from(context);
+ mTabControl = tabs;
}
- public int getItemViewType(int position) {
- if (mControl.canCreateNewTab()) {
- position -= 2;
- }
- // Do not recycle the "add new tab" item.
- return position < 0 ? IGNORE_ITEM_VIEW_TYPE : 1;
+
+ void setOnCloseListener(OnCloseTab listener) {
+ mCloseListener = listener;
}
- public View getView(int position, View convertView, ViewGroup parent) {
- final int tabCount = mControl.getTabCount();
- if (mControl.canCreateNewTab()) {
- position -= 2;
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ if (view == null) {
+ view = mInflater.inflate(R.layout.tab_view, parent, false);
}
+ ImageView favicon = (ImageView) view.findViewById(R.id.favicon);
+ ImageView thumbnail = (ImageView) view.findViewById(R.id.thumb);
+ TextView title = (TextView) view.findViewById(R.id.label);
+ Tab tab = getItem(position);
- if (convertView == null) {
- if (position == -2) {
- convertView = mFactory.inflate(R.layout.tab_view_add_tab, null);
- } else if (position == -1) {
- convertView = mFactory.inflate(R.layout.tab_view_add_incognito_tab, null);
+ String label = tab.getTitle();
+ if (TextUtils.isEmpty(label)) {
+ label = tab.getUrl();
+ }
+ title.setText(label);
+ Bitmap thumbnailBitmap = tab.getScreenshot();
+ if (thumbnailBitmap == null) {
+ thumbnail.setImageResource(R.drawable.browser_thumbnail);
+ } else {
+ thumbnail.setImageBitmap(thumbnailBitmap);
+ }
+ Bitmap faviconBitmap = tab.getFavicon();
+ if (tab.isPrivateBrowsingEnabled()) {
+ favicon.setImageResource(R.drawable.ic_incognito_holo_dark);
+ } else {
+ if (faviconBitmap == null) {
+ favicon.setImageResource(R.drawable.app_web_browser_sm);
} else {
- convertView = mFactory.inflate(R.layout.tab_view, null);
+ favicon.setImageBitmap(faviconBitmap);
}
}
+ View close = view.findViewById(R.id.close);
+ close.setTag(position);
+ close.setOnClickListener(this);
+ return view;
+ }
- if (position >= 0) {
- TextView title =
- (TextView) convertView.findViewById(R.id.title);
- TextView url = (TextView) convertView.findViewById(R.id.url);
- ImageView favicon =
- (ImageView) convertView.findViewById(R.id.favicon);
- View close = convertView.findViewById(R.id.close);
- Tab tab = mControl.getTab(position);
- if (tab.getWebView() == null) {
- // This means that populatePickerData will have to use the
- // saved state.
- Log.w(LOGTAG, "Tab " + position + " has a null WebView and "
- + (tab.getSavedState() == null ? "null" : "non-null")
- + " saved state ");
- }
- if (tab.getTitle() == null || tab.getTitle().length() == 0) {
- Log.w(LOGTAG, "Tab " + position + " has no title. "
- + "Check above in the Logs to see whether it has a "
- + "null WebView or null WebHistoryItem");
- }
- title.setText(tab.getTitle());
- url.setText(tab.getUrl());
- Bitmap icon = tab.getFavicon();
- if (icon != null) {
- favicon.setImageBitmap(icon);
- } else {
- favicon.setImageResource(R.drawable.app_web_browser_sm);
- }
- final int closePosition = position;
- close.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- mUiController.closeTab(
- mControl.getTab(closePosition));
- if (tabCount == 1) {
- mUiController.openTabToHomePage();
- mUiController.removeActiveTabsPage(false);
- } else {
- mNotified = true;
- notifyDataSetChanged();
- }
- }
- });
+ @Override
+ public void onClick(View v) {
+ int position = (Integer) v.getTag();
+ if (mCloseListener != null) {
+ mCloseListener.onCloseTab(position);
}
- return convertView;
}
- void notifyChange() {
- mHandler.post(new Runnable() {
- public void run() {
- mNotified = true;
- notifyDataSetChanged();
- }
- });
+ @Override
+ public int getCount() {
+ return mTabControl.getTabCount();
+ }
+
+ @Override
+ public Tab getItem(int position) {
+ return mTabControl.getTab(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
}
}
}
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index 08f9d39..a9e5f52 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -16,19 +16,19 @@
package com.android.browser;
-import com.android.browser.provider.BrowserProvider2;
import com.android.browser.addbookmark.FolderSpinner;
import com.android.browser.addbookmark.FolderSpinnerAdapter;
import android.app.Activity;
import android.app.LoaderManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.AsyncTaskLoader;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
-import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -40,8 +40,8 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.preference.PreferenceManager;
import android.provider.BrowserContract;
+import android.provider.BrowserContract.Accounts;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
@@ -53,20 +53,23 @@ import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ListView;
+import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.Stack;
public class AddBookmarkPage extends Activity
implements View.OnClickListener, TextView.OnEditorActionListener,
AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor>,
- BreadCrumbView.Controller, FolderSpinner.OnSetSelectionListener {
+ BreadCrumbView.Controller, FolderSpinner.OnSetSelectionListener,
+ OnItemSelectedListener {
public static final long DEFAULT_FOLDER_ID = -1;
public static final String TOUCH_ICON_URL = "touch_icon_url";
@@ -83,12 +86,9 @@ public class AddBookmarkPage extends Activity
private final String LOGTAG = "Bookmarks";
// IDs for the CursorLoaders that are used.
- private final int LOADER_ID_FOLDER_CONTENTS = 0;
- private final int LOADER_ID_ALL_FOLDERS = 1;
- private final int LOADER_ID_FIND_ROOT = 2;
- private final int LOADER_ID_CHECK_FOR_DUPE = 3;
- private final int LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK = 4;
- private final int LOADER_ID_FIND_FOLDER_BY_ID = 5;
+ private final int LOADER_ID_ACCOUNTS = 0;
+ private final int LOADER_ID_FOLDER_CONTENTS = 1;
+ private final int LOADER_ID_EDIT_INFO = 2;
private EditText mTitle;
private EditText mAddress;
@@ -121,6 +121,9 @@ public class AddBookmarkPage extends Activity
private View mRemoveLink;
private View mFakeTitleHolder;
private FolderSpinnerAdapter mFolderAdapter;
+ private Spinner mAccountSpinner;
+ private ArrayAdapter<BookmarkAccount> mAccountAdapter;
+
private static class Folder {
String Name;
long Id;
@@ -142,26 +145,16 @@ public class AddBookmarkPage extends Activity
}
private Uri getUriForFolder(long folder) {
- Uri uri;
- if (folder == mRootFolder) {
- uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
- } else {
- uri = BrowserContract.Bookmarks.buildFolderUri(folder);
- }
- String[] accountInfo = getAccountNameAndType(this);
- if (accountInfo != null) {
- uri = BookmarksLoader.addAccount(uri, accountInfo[1], accountInfo[0]);
- }
- return uri;
+ return BrowserContract.Bookmarks.buildFolderUri(folder);
}
@Override
- public void onTop(int level, Object data) {
+ public void onTop(BreadCrumbView view, int level, Object data) {
if (null == data) return;
Folder folderData = (Folder) data;
long folder = folderData.Id;
LoaderManager manager = getLoaderManager();
- CursorLoader loader = (CursorLoader) ((Loader) manager.getLoader(
+ CursorLoader loader = (CursorLoader) ((Loader<?>) manager.getLoader(
LOADER_ID_FOLDER_CONTENTS));
loader.setUri(getUriForFolder(folder));
loader.forceLoad();
@@ -213,7 +206,7 @@ public class AddBookmarkPage extends Activity
// editing a folder, 1 otherwise.
mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 0 : 1);
} else {
- ((TextView) mFolder.getSelectedView()).setText(folder.Name);
+ mFolderAdapter.setOtherFolderDisplayText(folder.Name);
}
}
} else {
@@ -227,17 +220,15 @@ public class AddBookmarkPage extends Activity
} else {
Object data = mCrumbs.getTopData();
if (data != null && ((Folder) data).Id == mCurrentFolder) {
- // We are showing the correct folder heirarchy. The
+ // We are showing the correct folder hierarchy. The
// folder selector will say "Other folder..." Change it
// to say the name of the folder once again.
- ((TextView) mFolder.getSelectedView()).setText(((Folder) data).Name);
+ mFolderAdapter.setOtherFolderDisplayText(((Folder) data).Name);
} else {
- // We are not be showing the correct folder heirarchy.
+ // We are not showing the correct folder hierarchy.
// Clear the Crumbs and find the proper folder
- mCrumbs.clear();
setupTopCrumb();
LoaderManager manager = getLoaderManager();
- manager.restartLoader(LOADER_ID_ALL_FOLDERS, null, this);
manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
}
@@ -319,7 +310,6 @@ public class AddBookmarkPage extends Activity
// and choose a different one, so that we will start from
// the correct place.
LoaderManager manager = getLoaderManager();
- manager.initLoader(LOADER_ID_ALL_FOLDERS, null, this);
manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
break;
default:
@@ -351,11 +341,6 @@ public class AddBookmarkPage extends Activity
values.put(BrowserContract.Bookmarks.TITLE,
name);
values.put(BrowserContract.Bookmarks.IS_FOLDER, 1);
- String[] accountInfo = getAccountNameAndType(this);
- if (accountInfo != null) {
- values.put(BrowserContract.Bookmarks.ACCOUNT_TYPE, accountInfo[1]);
- values.put(BrowserContract.Bookmarks.ACCOUNT_NAME, accountInfo[0]);
- }
long currentFolder;
Object data = mCrumbs.getTopData();
if (data != null) {
@@ -391,66 +376,78 @@ public class AddBookmarkPage extends Activity
}
}
+ private LoaderCallbacks<EditBookmarkInfo> mEditInfoLoaderCallbacks =
+ new LoaderCallbacks<EditBookmarkInfo>() {
+
+ @Override
+ public void onLoaderReset(Loader<EditBookmarkInfo> loader) {
+ // Don't care
+ }
+
+ @Override
+ public void onLoadFinished(Loader<EditBookmarkInfo> loader,
+ EditBookmarkInfo info) {
+ boolean setAccount = false;
+ if (info.id != -1) {
+ mEditingExisting = true;
+ showRemoveButton();
+ mFakeTitle.setText(R.string.edit_bookmark);
+ mTitle.setText(info.title);
+ mFolderAdapter.setOtherFolderDisplayText(info.parentTitle);
+ mMap.putLong(BrowserContract.Bookmarks._ID, info.id);
+ setAccount = true;
+ setAccount(info.accountName, info.accountType);
+ mCurrentFolder = info.parentId;
+ onCurrentFolderFound();
+ }
+ // TODO: Detect if lastUsedId is a subfolder of info.id in the
+ // editing folder case. For now, just don't show the last used
+ // folder at all to prevent any chance of the user adding a parent
+ // folder to a child folder
+ if (info.lastUsedId != -1 && info.lastUsedId != info.id
+ && !mEditingFolder) {
+ if (setAccount && info.lastUsedId != mRootFolder
+ && TextUtils.equals(info.lastUsedAccountName, info.accountName)
+ && TextUtils.equals(info.lastUsedAccountType, info.accountType)) {
+ mFolderAdapter.addRecentFolder(info.lastUsedId, info.lastUsedTitle);
+ } else if (!setAccount) {
+ setAccount = true;
+ setAccount(info.lastUsedAccountName, info.lastUsedAccountType);
+ if (info.lastUsedId != mRootFolder) {
+ mFolderAdapter.addRecentFolder(info.lastUsedId,
+ info.lastUsedTitle);
+ }
+ }
+ }
+ if (!setAccount) {
+ mAccountSpinner.setSelection(0);
+ }
+ }
+
+ @Override
+ public Loader<EditBookmarkInfo> onCreateLoader(int id, Bundle args) {
+ return new EditBookmarkInfoLoader(AddBookmarkPage.this, mMap);
+ }
+ };
+
+ void setAccount(String accountName, String accountType) {
+ for (int i = 0; i < mAccountAdapter.getCount(); i++) {
+ BookmarkAccount account = mAccountAdapter.getItem(i);
+ if (TextUtils.equals(account.accountName, accountName)
+ && TextUtils.equals(account.accountType, accountType)) {
+ onRootFolderFound(account.rootFolderId);
+ mAccountSpinner.setSelection(i);
+ return;
+ }
+ }
+ }
+
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection;
switch (id) {
- case LOADER_ID_CHECK_FOR_DUPE:
- projection = new String[] {
- BrowserContract.Bookmarks._ID,
- BrowserContract.Bookmarks.PARENT,
- BrowserContract.Bookmarks.TITLE
- };
- return new CursorLoader(this,
- BookmarkUtils.getBookmarksUri(this),
- projection,
- BrowserContract.Bookmarks.URL + " = ?",
- new String[] { mOriginalUrl },
- null);
- case LOADER_ID_FIND_ROOT:
- String name = args.getString(BrowserBookmarksPage.PREF_ACCOUNT_NAME);
- String type = args.getString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE);
-
- projection = new String[] { BrowserContract.Bookmarks._ID };
- String selection = BrowserContract.ChromeSyncColumns.SERVER_UNIQUE + "=? AND "
- + BrowserContract.Bookmarks.ACCOUNT_NAME + "=? AND "
- + BrowserContract.Bookmarks.ACCOUNT_TYPE + "=?";
- String[] selArgs = new String[] {
- BrowserContract.ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR,
- name,
- type
- };
- return new CursorLoader(this,
- BrowserContract.Bookmarks.CONTENT_URI,
- projection,
- selection,
- selArgs,
- null);
- case LOADER_ID_FIND_FOLDER_BY_ID:
- projection = new String[] {
- BrowserContract.Bookmarks._ID,
- BrowserContract.Bookmarks.TITLE
- };
- return new CursorLoader(this,
- BookmarkUtils.getBookmarksUri(this),
- projection,
- BrowserContract.Bookmarks._ID + " = "
- + args.getLong(BrowserContract.Bookmarks._ID),
- null,
- null);
- case LOADER_ID_ALL_FOLDERS:
- projection = new String[] {
- BrowserContract.Bookmarks._ID,
- BrowserContract.Bookmarks.PARENT,
- BrowserContract.Bookmarks.TITLE,
- BrowserContract.Bookmarks.IS_FOLDER
- };
- return new CursorLoader(this,
- BookmarkUtils.getBookmarksUri(this),
- projection,
- BrowserContract.Bookmarks.IS_FOLDER + " != 0",
- null,
- null);
+ case LOADER_ID_ACCOUNTS:
+ return new AccountsLoader(this);
case LOADER_ID_FOLDER_CONTENTS:
projection = new String[] {
BrowserContract.Bookmarks._ID,
@@ -458,26 +455,25 @@ public class AddBookmarkPage extends Activity
BrowserContract.Bookmarks.IS_FOLDER
};
String where = BrowserContract.Bookmarks.IS_FOLDER + " != 0";
+ String whereArgs[] = null;
if (mEditingFolder) {
- where += " AND " + BrowserContract.Bookmarks._ID + " != "
- + mMap.getLong(BrowserContract.Bookmarks._ID);
+ where += " AND " + BrowserContract.Bookmarks._ID + " != ?";
+ whereArgs = new String[] { Long.toString(mMap.getLong(
+ BrowserContract.Bookmarks._ID)) };
+ }
+ long currentFolder;
+ Object data = mCrumbs.getTopData();
+ if (data != null) {
+ currentFolder = ((Folder) data).Id;
+ } else {
+ currentFolder = mRootFolder;
}
return new CursorLoader(this,
- getUriForFolder(mCurrentFolder),
+ getUriForFolder(currentFolder),
projection,
where,
- null,
+ whereArgs,
BrowserContract.Bookmarks._ID + " ASC");
- case LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK:
- projection = new String[] {
- BrowserContract.Bookmarks.PARENT
- };
- return new CursorLoader(this,
- BookmarkUtils.getBookmarksUri(this),
- projection,
- BrowserContract.Bookmarks.IS_FOLDER + " = 0",
- null,
- BrowserContract.Bookmarks.DATE_CREATED + " DESC");
default:
throw new AssertionError("Asking for nonexistant loader!");
}
@@ -486,101 +482,18 @@ public class AddBookmarkPage extends Activity
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
- case LOADER_ID_CHECK_FOR_DUPE:
- if (cursor != null && cursor.moveToFirst()) {
- // Site is bookmarked.
- mEditingExisting = true;
- showRemoveButton();
- mFakeTitle.setText(R.string.edit_bookmark);
- int index = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks.PARENT);
- mCurrentFolder = cursor.getLong(index);
- index = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks.TITLE);
- String title = cursor.getString(index);
- mTitle.setText(title);
- index = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks._ID);
- long id = cursor.getLong(index);
- mMap.putLong(BrowserContract.Bookmarks._ID, id);
+ case LOADER_ID_ACCOUNTS:
+ mAccountAdapter.clear();
+ while (cursor.moveToNext()) {
+ mAccountAdapter.add(new BookmarkAccount(this, cursor));
}
- onCurrentFolderFound();
- getLoaderManager().destroyLoader(LOADER_ID_CHECK_FOR_DUPE);
- break;
- case LOADER_ID_FIND_ROOT:
- long root;
- if (cursor != null && cursor.moveToFirst()) {
- root = cursor.getLong(0);
- } else {
- root = BrowserProvider2.FIXED_ID_ROOT;
- }
- onRootFolderFound(root);
- getLoaderManager().destroyLoader(LOADER_ID_FIND_ROOT);
+ getLoaderManager().destroyLoader(LOADER_ID_ACCOUNTS);
+ getLoaderManager().restartLoader(LOADER_ID_EDIT_INFO, null,
+ mEditInfoLoaderCallbacks);
break;
case LOADER_ID_FOLDER_CONTENTS:
mAdapter.changeCursor(cursor);
break;
- case LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK:
- LoaderManager manager = getLoaderManager();
- if (cursor != null && cursor.moveToFirst()) {
- // Find the parent
- long lastUsedFolder = cursor.getLong(0);
- if (lastUsedFolder != mRootFolder
- && lastUsedFolder != mCurrentFolder
- && lastUsedFolder != 0) {
- // Find out the parent's name
- Bundle b = new Bundle();
- b.putLong(BrowserContract.Bookmarks._ID, lastUsedFolder);
- manager.initLoader(LOADER_ID_FIND_FOLDER_BY_ID, b, this);
- }
- }
- manager.destroyLoader(LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK);
- break;
- case LOADER_ID_FIND_FOLDER_BY_ID:
- if (cursor != null && cursor.moveToFirst()) {
- long id = cursor.getLong(cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks._ID));
- String title = cursor.getString(cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks.TITLE));
- mFolderAdapter.addRecentFolder(id, title);
- }
- getLoaderManager().destroyLoader(LOADER_ID_FIND_FOLDER_BY_ID);
- break;
- case LOADER_ID_ALL_FOLDERS:
- long parent = mCurrentFolder;
- int idIndex = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks._ID);
- int titleIndex = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks.TITLE);
- int parentIndex = cursor.getColumnIndexOrThrow(
- BrowserContract.Bookmarks.PARENT);
- // If the user is editing anything inside the "Other Bookmarks"
- // folder, we need to stop searching up when we reach its parent.
- // Find the root folder
- moveCursorToFolder(cursor, mRootFolder, idIndex);
- // omniparent is the folder which contains root, and therefore
- // also the parent of the "Other Bookmarks" folder.
- long omniparent = cursor.getLong(parentIndex);
- Stack<Folder> folderStack = new Stack<Folder>();
- while ((parent != mRootFolder) && (parent != 0) && (parent != omniparent)) {
- // First, find the folder corresponding to the current
- // folder
- moveCursorToFolder(cursor, parent, idIndex);
- String name = cursor.getString(titleIndex);
- if (parent == mCurrentFolder) {
- ((TextView) mFolder.getSelectedView()).setText(name);
- }
- folderStack.push(new Folder(name, parent));
- parent = cursor.getLong(parentIndex);
- }
- while (!folderStack.isEmpty()) {
- Folder thisFolder = folderStack.pop();
- mCrumbs.pushView(thisFolder.Name, thisFolder);
- }
- getLoaderManager().destroyLoader(LOADER_ID_ALL_FOLDERS);
- break;
- default:
- break;
}
}
@@ -727,7 +640,7 @@ public class AddBookmarkPage extends Activity
mCancelButton.setOnClickListener(this);
mFolder = (FolderSpinner) findViewById(R.id.folder);
- mFolderAdapter = new FolderSpinnerAdapter(!mEditingFolder);
+ mFolderAdapter = new FolderSpinnerAdapter(this, !mEditingFolder);
mFolder.setAdapter(mFolderAdapter);
mFolder.setOnSetSelectionListener(this);
@@ -759,22 +672,22 @@ public class AddBookmarkPage extends Activity
mListView.setOnItemClickListener(this);
mListView.addEditText(mFolderNamer);
+ mAccountAdapter = new ArrayAdapter<BookmarkAccount>(this,
+ android.R.layout.simple_spinner_item);
+ mAccountAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ mAccountSpinner = (Spinner) findViewById(R.id.accounts);
+ mAccountSpinner.setAdapter(mAccountAdapter);
+ mAccountSpinner.setOnItemSelectedListener(this);
+
+
mFakeTitleHolder = findViewById(R.id.title_holder);
if (!window.getDecorView().isInTouchMode()) {
mButton.requestFocus();
}
- String[] accountInfo = getAccountNameAndType(this);
- if (accountInfo == null) {
- onRootFolderFound(BrowserProvider2.FIXED_ID_ROOT);
- } else {
- Bundle args = new Bundle();
- args.putString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, accountInfo[0]);
- args.putString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, accountInfo[1]);
- getLoaderManager().initLoader(LOADER_ID_FIND_ROOT, args, this);
- }
-
+ getLoaderManager().restartLoader(LOADER_ID_ACCOUNTS, null, this);
}
private void showRemoveButton() {
@@ -787,22 +700,13 @@ public class AddBookmarkPage extends Activity
// Called once we have determined which folder is the root folder
private void onRootFolderFound(long root) {
mRootFolder = root;
- if (mCurrentFolder == DEFAULT_FOLDER_ID) {
- mCurrentFolder = mRootFolder;
- }
+ mCurrentFolder = mRootFolder;
setupTopCrumb();
- if (mEditingExisting || TextUtils.isEmpty(mOriginalUrl)
- || !(mMap != null && mMap.getBoolean(CHECK_FOR_DUPE))) {
- onCurrentFolderFound();
- } else {
- // User is attempting to bookmark a site, rather than deliberately
- // editing a bookmark. Rather than let them create a duplicate
- // bookmark, see if the bookmark already exists.
- getLoaderManager().initLoader(LOADER_ID_CHECK_FOR_DUPE, null, this);
- }
+ onCurrentFolderFound();
}
private void setupTopCrumb() {
+ mCrumbs.clear();
String name = getString(R.string.bookmarks);
mTopLevelLabel = (TextView) mCrumbs.pushView(name, false,
new Folder(name, mRootFolder));
@@ -813,19 +717,12 @@ public class AddBookmarkPage extends Activity
private void onCurrentFolderFound() {
LoaderManager manager = getLoaderManager();
if (mCurrentFolder != mRootFolder) {
- // Find all the folders
- manager.initLoader(LOADER_ID_ALL_FOLDERS, null, this);
// Since we're not in the root folder, change the selection to other
// folder now. The text will get changed once we select the correct
// folder.
mFolder.setSelectionIgnoringSelectionChange(mEditingFolder ? 1 : 2);
} else {
setShowBookmarkIcon(true);
- if (!mEditingExisting) {
- // Find the most recently saved bookmark, so that we can include it in
- // the list of options to save the current bookmark.
- manager.initLoader(LOADER_ID_MOST_RECENTLY_SAVED_BOOKMARK, null, this);
- }
if (!mEditingFolder) {
// Initially the "Bookmarks" folder should be showing, rather than
// the home screen. In the editing folder case, home screen is not
@@ -834,22 +731,7 @@ public class AddBookmarkPage extends Activity
}
}
// Find the contents of the current folder
- manager.initLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
-}
- /**
- * Get the account name and type of the currently synced account.
- * @param context Context to access preferences.
- * @return null if no account name or type. Otherwise, the result will be
- * an array of two Strings, the accountName and accountType, respectively.
- */
- private String[] getAccountNameAndType(Context context) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- String accountName = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, null);
- String accountType = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, null);
- if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
- return null;
- }
- return new String[] { accountName, accountType };
+ manager.restartLoader(LOADER_ID_FOLDER_CONTENTS, null, this);
}
/**
@@ -1070,6 +952,22 @@ public class AddBookmarkPage extends Activity
return true;
}
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ if (mAccountSpinner == parent) {
+ long root = mAccountAdapter.getItem(position).rootFolderId;
+ if (root != mRootFolder) {
+ onRootFolderFound(root);
+ }
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Don't care
+ }
+
/*
* Class used as a proxy for the InputMethodManager to get to mFolderNamer
*/
@@ -1097,4 +995,162 @@ public class AddBookmarkPage extends Activity
return view == mEditText;
}
}
+
+ static class AccountsLoader extends CursorLoader {
+
+ static final String[] PROJECTION = new String[] {
+ Accounts.ACCOUNT_NAME,
+ Accounts.ACCOUNT_TYPE,
+ Accounts.ROOT_ID,
+ };
+
+ static final int COLUMN_INDEX_ACCOUNT_NAME = 0;
+ static final int COLUMN_INDEX_ACCOUNT_TYPE = 1;
+ static final int COLUMN_INDEX_ROOT_ID = 2;
+
+ public AccountsLoader(Context context) {
+ super(context, Accounts.CONTENT_URI, PROJECTION, null, null,
+ Accounts.ACCOUNT_NAME + " ASC");
+ }
+
+ }
+
+ static class BookmarkAccount {
+
+ private String mLabel;
+ String accountName, accountType;
+ long rootFolderId;
+
+ public BookmarkAccount(Context context, Cursor cursor) {
+ accountName = cursor.getString(
+ AccountsLoader.COLUMN_INDEX_ACCOUNT_NAME);
+ accountType = cursor.getString(
+ AccountsLoader.COLUMN_INDEX_ACCOUNT_TYPE);
+ rootFolderId = cursor.getLong(
+ AccountsLoader.COLUMN_INDEX_ROOT_ID);
+ mLabel = accountName;
+ if (TextUtils.isEmpty(mLabel)) {
+ mLabel = context.getString(R.string.local_bookmarks);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return mLabel;
+ }
+ }
+
+ static class EditBookmarkInfo {
+ long id = -1;
+ long parentId = -1;
+ String parentTitle;
+ String title;
+ String accountName;
+ String accountType;
+
+ long lastUsedId = -1;
+ String lastUsedTitle;
+ String lastUsedAccountName;
+ String lastUsedAccountType;
+ }
+
+ static class EditBookmarkInfoLoader extends AsyncTaskLoader<EditBookmarkInfo> {
+
+ private Context mContext;
+ private Bundle mMap;
+
+ public EditBookmarkInfoLoader(Context context, Bundle bundle) {
+ super(context);
+ mContext = context;
+ mMap = bundle;
+ }
+
+ @Override
+ public EditBookmarkInfo loadInBackground() {
+ final ContentResolver cr = mContext.getContentResolver();
+ EditBookmarkInfo info = new EditBookmarkInfo();
+ Cursor c = null;
+
+ try {
+ // First, let's lookup the bookmark (check for dupes, get needed info)
+ String url = mMap.getString(BrowserContract.Bookmarks.URL);
+ info.id = mMap.getLong(BrowserContract.Bookmarks._ID, -1);
+ boolean checkForDupe = mMap.getBoolean(CHECK_FOR_DUPE);
+ if (checkForDupe && info.id == -1 && !TextUtils.isEmpty(url)) {
+ c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
+ new String[] { BrowserContract.Bookmarks._ID},
+ BrowserContract.Bookmarks.URL + "=?",
+ new String[] { url }, null);
+ if (c.getCount() == 1 && c.moveToFirst()) {
+ info.id = c.getLong(0);
+ }
+ c.close();
+ }
+ if (info.id != -1) {
+ c = cr.query(ContentUris.withAppendedId(
+ BrowserContract.Bookmarks.CONTENT_URI, info.id),
+ new String[] {
+ BrowserContract.Bookmarks.PARENT,
+ BrowserContract.Bookmarks.ACCOUNT_NAME,
+ BrowserContract.Bookmarks.ACCOUNT_TYPE,
+ BrowserContract.Bookmarks.TITLE},
+ null, null, null);
+ if (c.moveToFirst()) {
+ info.parentId = c.getLong(0);
+ info.accountName = c.getString(1);
+ info.accountType = c.getString(2);
+ info.title = c.getString(3);
+ }
+ c.close();
+ c = cr.query(ContentUris.withAppendedId(
+ BrowserContract.Bookmarks.CONTENT_URI, info.parentId),
+ new String[] {
+ BrowserContract.Bookmarks.TITLE,},
+ null, null, null);
+ if (c.moveToFirst()) {
+ info.parentTitle = c.getString(0);
+ }
+ c.close();
+ }
+
+ // Figure out the last used folder/account
+ c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
+ new String[] {
+ BrowserContract.Bookmarks.PARENT,
+ }, null, null,
+ BrowserContract.Bookmarks.DATE_MODIFIED + " DESC LIMIT 1");
+ if (c.moveToFirst()) {
+ long parent = c.getLong(0);
+ c.close();
+ c = cr.query(BrowserContract.Bookmarks.CONTENT_URI,
+ new String[] {
+ BrowserContract.Bookmarks.TITLE,
+ BrowserContract.Bookmarks.ACCOUNT_NAME,
+ BrowserContract.Bookmarks.ACCOUNT_TYPE},
+ BrowserContract.Bookmarks._ID + "=?", new String[] {
+ Long.toString(parent)}, null);
+ if (c.moveToFirst()) {
+ info.lastUsedId = parent;
+ info.lastUsedTitle = c.getString(0);
+ info.lastUsedAccountName = c.getString(1);
+ info.lastUsedAccountType = c.getString(2);
+ }
+ c.close();
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+
+ return info;
+ }
+
+ @Override
+ protected void onStartLoading() {
+ forceLoad();
+ }
+
+ }
+
}
diff --git a/src/com/android/browser/AutoFillSettingsFragment.java b/src/com/android/browser/AutoFillSettingsFragment.java
index 3a7ae12..e87645e 100644
--- a/src/com/android/browser/AutoFillSettingsFragment.java
+++ b/src/com/android/browser/AutoFillSettingsFragment.java
@@ -53,6 +53,7 @@ public class AutoFillSettingsFragment extends Fragment {
// Used to display toast after DB interactions complete.
private Handler mHandler;
+ private BrowserSettings mSettings;
private final static int PROFILE_SAVED_MSG = 100;
private final static int PROFILE_DELETED_MSG = 101;
@@ -130,6 +131,7 @@ public class AutoFillSettingsFragment extends Fragment {
@Override
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
+ mSettings = BrowserSettings.getInstance();
}
@Override
@@ -177,7 +179,7 @@ public class AutoFillSettingsFragment extends Fragment {
mCountryEdit.getText().toString(),
mPhoneEdit.getText().toString());
- BrowserSettings.getInstance().setAutoFillProfile(getActivity(), newProfile,
+ mSettings.setAutoFillProfile(newProfile,
mHandler.obtainMessage(PROFILE_SAVED_MSG));
closeEditor();
}
@@ -200,7 +202,7 @@ public class AutoFillSettingsFragment extends Fragment {
// Update browser settings and native with a null profile. This will
// trigger the current profile to get deleted from the DB.
- BrowserSettings.getInstance().setAutoFillProfile(getActivity(), null,
+ mSettings.setAutoFillProfile(null,
mHandler.obtainMessage(PROFILE_DELETED_MSG));
updateButtonState();
@@ -215,7 +217,7 @@ public class AutoFillSettingsFragment extends Fragment {
});
// Populate the text boxes with any pre existing AutoFill data.
- AutoFillProfile activeProfile = BrowserSettings.getInstance().getAutoFillProfile();
+ AutoFillProfile activeProfile = mSettings.getAutoFillProfile();
if (activeProfile != null) {
mFullNameEdit.setText(activeProfile.getFullName());
mEmailEdit.setText(activeProfile.getEmailAddress());
diff --git a/src/com/android/browser/AutofillHandler.java b/src/com/android/browser/AutofillHandler.java
new file mode 100644
index 0000000..b6b237d
--- /dev/null
+++ b/src/com/android/browser/AutofillHandler.java
@@ -0,0 +1,202 @@
+
+/*
+ * Copyright (C) 2011 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.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.os.Message;
+import android.preference.PreferenceManager;
+import android.webkit.WebSettings.AutoFillProfile;
+
+import java.util.concurrent.CountDownLatch;
+
+public class AutofillHandler {
+
+ private AutoFillProfile mAutoFillProfile;
+ // Default to zero. In the case no profile is set up, the initial
+ // value will come from the AutoFillSettingsFragment when the user
+ // creates a profile. Otherwise, we'll read the ID of the last used
+ // profile from the prefs db.
+ private int mAutoFillActiveProfileId;
+ private static final int NO_AUTOFILL_PROFILE_SET = 0;
+
+ private CountDownLatch mLoaded = new CountDownLatch(1);
+ private Context mContext;
+
+ public AutofillHandler(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Load settings from the browser app's database. It is performed in
+ * an AsyncTask as it involves plenty of slow disk IO.
+ * NOTE: Strings used for the preferences must match those specified
+ * in the various preference XML files.
+ */
+ public void asyncLoadFromDb() {
+ // Run the initial settings load in an AsyncTask as it hits the
+ // disk multiple times through SharedPreferences and SQLite. We
+ // need to be certain though that this has completed before we start
+ // to load pages though, so in the worst case we will block waiting
+ // for it to finish in BrowserActivity.onCreate().
+ new LoadFromDb().start();
+ }
+
+ public void waitForLoad() {
+ try {
+ mLoaded.await();
+ } catch (InterruptedException e) {}
+ }
+
+ private class LoadFromDb extends Thread {
+
+ @Override
+ public void run() {
+ SharedPreferences p =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+
+ // Read the last active AutoFill profile id.
+ mAutoFillActiveProfileId = p.getInt(
+ PreferenceKeys.PREF_AUTOFILL_ACTIVE_PROFILE_ID,
+ mAutoFillActiveProfileId);
+
+ // Load the autofill profile data from the database. We use a database separate
+ // to the browser preference DB to make it easier to support multiple profiles
+ // and switching between them.
+ AutoFillProfileDatabase autoFillDb = AutoFillProfileDatabase.getInstance(mContext);
+ Cursor c = autoFillDb.getProfile(mAutoFillActiveProfileId);
+
+ if (c.getCount() > 0) {
+ c.moveToFirst();
+
+ String fullName = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.FULL_NAME));
+ String email = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.EMAIL_ADDRESS));
+ String company = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.COMPANY_NAME));
+ String addressLine1 = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.ADDRESS_LINE_1));
+ String addressLine2 = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.ADDRESS_LINE_2));
+ String city = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.CITY));
+ String state = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.STATE));
+ String zip = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.ZIP_CODE));
+ String country = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.COUNTRY));
+ String phone = c.getString(c.getColumnIndex(
+ AutoFillProfileDatabase.Profiles.PHONE_NUMBER));
+ mAutoFillProfile = new AutoFillProfile(mAutoFillActiveProfileId,
+ fullName, email, company, addressLine1, addressLine2, city,
+ state, zip, country, phone);
+ }
+ c.close();
+ autoFillDb.close();
+
+ mLoaded.countDown();
+ }
+ }
+
+ public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
+ int profileId = NO_AUTOFILL_PROFILE_SET;
+ if (profile != null) {
+ profileId = profile.getUniqueId();
+ // Update the AutoFill DB with the new profile.
+ new SaveProfileToDbTask(msg).execute(profile);
+ } else {
+ // Delete the current profile.
+ if (mAutoFillProfile != null) {
+ new DeleteProfileFromDbTask(msg).execute(mAutoFillProfile.getUniqueId());
+ }
+ }
+ // Make sure we set mAutoFillProfile before calling setActiveAutoFillProfileId
+ // Calling setActiveAutoFillProfileId will trigger an update of WebViews
+ // which will expect a new profile to be set
+ mAutoFillProfile = profile;
+ setActiveAutoFillProfileId(profileId);
+ }
+
+ public AutoFillProfile getAutoFillProfile() {
+ return mAutoFillProfile;
+ }
+
+ private void setActiveAutoFillProfileId(int activeProfileId) {
+ mAutoFillActiveProfileId = activeProfileId;
+ Editor ed = PreferenceManager.
+ getDefaultSharedPreferences(mContext).edit();
+ ed.putInt(PreferenceKeys.PREF_AUTOFILL_ACTIVE_PROFILE_ID, activeProfileId);
+ ed.apply();
+ }
+
+ private abstract class AutoFillProfileDbTask<T> extends AsyncTask<T, Void, Void> {
+ AutoFillProfileDatabase mAutoFillProfileDb;
+ Message mCompleteMessage;
+
+ public AutoFillProfileDbTask(Message msg) {
+ mCompleteMessage = msg;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (mCompleteMessage != null) {
+ mCompleteMessage.sendToTarget();
+ }
+ mAutoFillProfileDb.close();
+ }
+
+ @Override
+ abstract protected Void doInBackground(T... values);
+ }
+
+
+ private class SaveProfileToDbTask extends AutoFillProfileDbTask<AutoFillProfile> {
+ public SaveProfileToDbTask(Message msg) {
+ super(msg);
+ }
+
+ @Override
+ protected Void doInBackground(AutoFillProfile... values) {
+ mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
+ assert mAutoFillActiveProfileId != NO_AUTOFILL_PROFILE_SET;
+ AutoFillProfile newProfile = values[0];
+ mAutoFillProfileDb.addOrUpdateProfile(mAutoFillActiveProfileId, newProfile);
+ return null;
+ }
+ }
+
+ private class DeleteProfileFromDbTask extends AutoFillProfileDbTask<Integer> {
+ public DeleteProfileFromDbTask(Message msg) {
+ super(msg);
+ }
+
+ @Override
+ protected Void doInBackground(Integer... values) {
+ mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
+ int id = values[0];
+ assert id > 0;
+ mAutoFillProfileDb.dropProfile(id);
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 4f80e9d..7530732 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -17,14 +17,20 @@
package com.android.browser;
import com.android.browser.Tab.LockIcon;
+import com.android.internal.view.menu.MenuBuilder;
import android.animation.ObjectAnimator;
import android.app.Activity;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
@@ -72,10 +78,11 @@ public abstract class BaseUi implements UI, WebViewFactory {
private Drawable mSecLockIcon;
private Drawable mMixLockIcon;
+ protected Drawable mGenericFavicon;
private FrameLayout mBrowserFrameLayout;
protected FrameLayout mContentView;
- private FrameLayout mCustomViewContainer;
+ protected FrameLayout mCustomViewContainer;
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
@@ -86,7 +93,6 @@ public abstract class BaseUi implements UI, WebViewFactory {
private Toast mStopToast;
- private boolean mTitleShowing;
// the default <video> poster
private Bitmap mDefaultVideoPoster;
@@ -116,7 +122,23 @@ public abstract class BaseUi implements UI, WebViewFactory {
mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
.findViewById(R.id.fullscreen_custom_content);
frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
- mTitleShowing = false;
+ setFullscreen(BrowserSettings.getInstance().useFullscreen());
+ mGenericFavicon = res.getDrawable(
+ R.drawable.app_web_browser_sm);
+ }
+
+ @Override
+ public WebView createWebView(boolean privateBrowsing) {
+ // Create a new WebView
+ BrowserWebView w = new BrowserWebView(mActivity, null,
+ android.R.attr.webViewStyle, privateBrowsing);
+ initWebViewSettings(w);
+ return w;
+ }
+
+ @Override
+ public WebView createSubWebView(boolean privateBrowsing) {
+ return createWebView(privateBrowsing);
}
/**
@@ -129,11 +151,15 @@ public abstract class BaseUi implements UI, WebViewFactory {
w.setMapTrackballToArrowKeys(false); // use trackball directly
// Enable the built-in zoom
w.getSettings().setBuiltInZoomControls(true);
+ boolean supportsMultiTouch = mActivity.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH);
+ w.getSettings().setDisplayZoomControls(!supportsMultiTouch);
+ w.setExpandedTileBounds(true); // smoother scrolling
// Add this WebView to the settings observer list and update the
// settings
final BrowserSettings s = BrowserSettings.getInstance();
- s.addObserver(w.getSettings()).update(s, null);
+ s.startManagingSettings(w.getSettings());
}
private void cancelStopToast() {
@@ -164,8 +190,6 @@ public abstract class BaseUi implements UI, WebViewFactory {
public void onConfigurationChanged(Configuration config) {
}
- public abstract void editUrl(boolean clearInput);
-
// key handling
@Override
@@ -212,7 +236,7 @@ public abstract class BaseUi implements UI, WebViewFactory {
@Override
public boolean needsRestoreAllTabs() {
- return false;
+ return true;
}
@Override
@@ -300,8 +324,6 @@ public abstract class BaseUi implements UI, WebViewFactory {
Log.w(LOGTAG, "mContainer is already attached to content in"
+ " attachTabToContentView!");
}
- mainView.setNextFocusUpId(R.id.url_focused);
- mainView.setNextFocusDownId(R.id.url_focused);
mUiController.attachSubWindow(tab);
}
@@ -395,24 +417,43 @@ public abstract class BaseUi implements UI, WebViewFactory {
mContentView.addView(container, COVER_SCREEN_PARAMS);
}
+ protected void refreshWebView() {
+ WebView web = getWebView();
+ if (web != null) {
+ web.invalidate();
+ }
+ }
+
+ public void editUrl(boolean clearInput) {
+ if (mUiController.isInCustomActionMode()) {
+ mUiController.endActionMode();
+ }
+ showTitleBar();
+ getTitleBar().startEditingUrl(clearInput);
+ }
+
boolean canShowTitleBar() {
return !isTitleBarShowing()
&& !isActivityPaused()
&& (getActiveTab() != null)
- && (getActiveTab().getWebView() != null)
+ && (getWebView() != null)
&& !mUiController.isInCustomActionMode();
}
void showTitleBar() {
- mTitleShowing = true;
+ if (canShowTitleBar()) {
+ getTitleBar().show();
+ }
}
protected void hideTitleBar() {
- mTitleShowing = false;
+ if (getTitleBar().isShowing()) {
+ getTitleBar().hide();
+ }
}
protected boolean isTitleBarShowing() {
- return mTitleShowing;
+ return getTitleBar().isShowing();
}
protected abstract TitleBarBase getTitleBar();
@@ -421,24 +462,28 @@ public abstract class BaseUi implements UI, WebViewFactory {
WebView web = getWebView();
if (web != null) {
web.setTitleBarGravity(gravity);
- web.invalidate();
}
}
@Override
- public void showVoiceTitleBar(String title) {
- getTitleBar().setInVoiceMode(true);
+ public void showVoiceTitleBar(String title, List<String> results) {
+ getTitleBar().setInVoiceMode(true, results);
getTitleBar().setDisplayTitle(title);
}
@Override
public void revertVoiceTitleBar(Tab tab) {
- getTitleBar().setInVoiceMode(false);
+ getTitleBar().setInVoiceMode(false, null);
String url = tab.getUrl();
getTitleBar().setDisplayTitle(url);
}
@Override
+ public void registerDropdownChangeListener(DropdownChangeListener d) {
+ getTitleBar().registerDropdownChangeListener(d);
+ }
+
+ @Override
public void showComboView(boolean startWithHistory, Bundle extras) {
if (mComboView != null) {
return;
@@ -452,8 +497,9 @@ public abstract class BaseUi implements UI, WebViewFactory {
FrameLayout wrapper =
(FrameLayout) mContentView.findViewById(R.id.webview_wrapper);
wrapper.setVisibility(View.GONE);
- hideTitleBar();
+ getTitleBar().stopEditingUrl();
dismissIME();
+ hideTitleBar();
if (mActiveTab != null) {
WebView web = mActiveTab.getWebView();
mActiveTab.putInBackground();
@@ -559,7 +605,9 @@ public abstract class BaseUi implements UI, WebViewFactory {
protected void updateNavigationState(Tab tab) {
}
- protected void updateAutoLogin(Tab tab, boolean animate) {}
+ protected void updateAutoLogin(Tab tab, boolean animate) {
+ getTitleBar().updateAutoLogin(tab, animate);
+ }
/**
* Update the lock icon to correspond to our latest state.
@@ -605,11 +653,6 @@ public abstract class BaseUi implements UI, WebViewFactory {
@Override
public void onActionModeFinished(boolean inLoad) {
- if (inLoad) {
- // the titlebar was removed when the CAB was shown
- // if the page is loading, show it again
- showTitleBar();
- }
}
// active tabs page
@@ -718,16 +761,59 @@ public abstract class BaseUi implements UI, WebViewFactory {
warning.show();
}
- @Override
- public void registerDropdownChangeListener(DropdownChangeListener d) {
+ protected void captureTab(final Tab tab) {
+ captureTab(tab,
+ (int) mActivity.getResources()
+ .getDimension(R.dimen.qc_thumb_width),
+ (int) mActivity.getResources()
+ .getDimension(R.dimen.qc_thumb_height));
+ }
+
+ protected void captureTab(final Tab tab, int width, int height) {
+ if ((tab == null) || (tab.getWebView() == null)) return;
+ Bitmap sshot = Controller.createScreenshot(tab, width, height);
+ tab.setScreenshot(sshot);
}
protected WebView getWebView() {
- Tab tab = getActiveTab();
- if (tab != null) {
- return tab.getWebView();
+ if (mActiveTab != null) {
+ return mActiveTab.getWebView();
+ } else {
+ return null;
+ }
+ }
+
+ protected Menu getMenu() {
+ MenuBuilder menu = new MenuBuilder(mActivity);
+ mActivity.getMenuInflater().inflate(R.menu.browser, menu);
+ return menu;
+ }
+
+ public void setFullscreen(boolean enabled) {
+ if (enabled) {
+ mActivity.getWindow().setFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ } else {
+ mActivity.getWindow().clearFlags(
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
+ }
+
+ protected Drawable getFaviconDrawable(Bitmap icon) {
+ Drawable[] array = new Drawable[3];
+ array[0] = new PaintDrawable(Color.BLACK);
+ PaintDrawable p = new PaintDrawable(Color.WHITE);
+ array[1] = p;
+ if (icon == null) {
+ array[2] = mGenericFavicon;
+ } else {
+ array[2] = new BitmapDrawable(icon);
}
- return null;
+ LayerDrawable d = new LayerDrawable(array);
+ d.setLayerInset(1, 1, 1, 1, 1);
+ d.setLayerInset(2, 2, 2, 2, 2);
+ return d;
}
}
diff --git a/src/com/android/browser/BookmarkDragHandler.java b/src/com/android/browser/BookmarkDragHandler.java
new file mode 100644
index 0000000..0707058
--- /dev/null
+++ b/src/com/android/browser/BookmarkDragHandler.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 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.ClipData;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BrowserContract;
+import android.provider.BrowserContract.Bookmarks;
+import android.view.DragEvent;
+import android.view.View;
+import android.view.View.OnDragListener;
+
+public class BookmarkDragHandler {
+
+ public static interface BookmarkDragController {
+ boolean startDrag(Cursor item);
+ }
+
+ public static interface BookmarkDragAdapter {
+ void setBookmarkDragHandler(BookmarkDragHandler handler);
+ Cursor getItemForView(View v);
+ }
+
+ static class BookmarkDragState {
+ long id;
+ long parent;
+ }
+
+ static final String BOOKMARK_DRAG_LABEL = "com.android.browser.BOOKMARK_LABEL";
+
+ private Context mContext;
+ private BookmarkDragController mDragController;
+ private BookmarkDragAdapter mDragAdapter;
+
+ public BookmarkDragHandler(Context context, BookmarkDragController controller,
+ BookmarkDragAdapter adapter) {
+ mContext = context;
+ mDragController = controller;
+ mDragAdapter = adapter;
+ mDragAdapter.setBookmarkDragHandler(this);
+ }
+
+ public boolean startDrag(View view, Cursor item, long id) {
+ if (!mDragController.startDrag(item)) {
+ return false;
+ }
+ Uri uri = ContentUris.withAppendedId(
+ BrowserContract.Bookmarks.CONTENT_URI, id);
+ ClipData data = ClipData.newRawUri(BOOKMARK_DRAG_LABEL, uri);
+ BookmarkDragState state = new BookmarkDragState();
+ state.id = id;
+ state.parent = item.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
+ view.startDrag(data, new View.DragShadowBuilder(view), state, 0);
+ return true;
+ }
+
+ public void registerBookmarkDragHandler(View view) {
+ view.setOnDragListener(mBookmarkDragListener);
+ }
+
+ private OnDragListener mBookmarkDragListener = new OnDragListener() {
+
+ @Override
+ public boolean onDrag(View v, DragEvent event) {
+ Cursor c = mDragAdapter.getItemForView(v);
+ BookmarkDragState state = (BookmarkDragState) event.getLocalState();
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ return true;
+ case DragEvent.ACTION_DROP:
+ long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
+ if (id == state.id) {
+ // We dropped onto ourselves, show the context menu
+ v.showContextMenu();
+ return false;
+ }
+ long parent = c.getLong(BookmarksLoader.COLUMN_INDEX_PARENT);
+ if (isFolder(c)) {
+ parent = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
+ }
+ if (parent != state.parent) {
+ ContentResolver cr = mContext.getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put(Bookmarks.PARENT, parent);
+ Uri uri = event.getClipData().getItemAt(0).getUri();
+ cr.update(uri, values, null, null);
+ }
+ break;
+ }
+ return false;
+ }
+ };
+
+ static boolean isFolder(Cursor c) {
+ return c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
+ }
+}
diff --git a/src/com/android/browser/BookmarkItem.java b/src/com/android/browser/BookmarkItem.java
index 4e60073..e7f37a5 100644
--- a/src/com/android/browser/BookmarkItem.java
+++ b/src/com/android/browser/BookmarkItem.java
@@ -30,6 +30,8 @@ import android.widget.TextView;
*/
class BookmarkItem extends LinearLayout {
+ final static int MAX_TEXTVIEW_LEN = 80;
+
protected TextView mTextView;
protected TextView mUrlText;
protected ImageView mImageView;
@@ -63,6 +65,16 @@ class BookmarkItem extends LinearLayout {
item.mImageView.setImageDrawable(mImageView.getDrawable());
}
+ public void startMarquee() {
+ mTextView.setSelected(true);
+ mUrlText.setSelected(true);
+ }
+
+ public void stopMarquee() {
+ mTextView.setSelected(false);
+ mUrlText.setSelected(false);
+ }
+
/**
* Return the name assigned to this bookmark item.
*/
@@ -111,8 +123,8 @@ class BookmarkItem extends LinearLayout {
mTitle = name;
- if (name.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
- name = name.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN);
+ if (name.length() > MAX_TEXTVIEW_LEN) {
+ name = name.substring(0, MAX_TEXTVIEW_LEN);
}
mTextView.setText(name);
@@ -129,8 +141,8 @@ class BookmarkItem extends LinearLayout {
mUrl = url;
- if (url.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
- url = url.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN);
+ if (url.length() > MAX_TEXTVIEW_LEN) {
+ url = url.substring(0, MAX_TEXTVIEW_LEN);
}
mUrlText.setText(url);
diff --git a/src/com/android/browser/BookmarkUtils.java b/src/com/android/browser/BookmarkUtils.java
index 3aaf5d4..383dc7e 100644
--- a/src/com/android/browser/BookmarkUtils.java
+++ b/src/com/android/browser/BookmarkUtils.java
@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -42,7 +41,6 @@ import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.Browser;
import android.provider.BrowserContract;
-import android.util.DisplayMetrics;
public class BookmarkUtils {
private final static String LOGTAG = "BookmarkUtils";
@@ -218,10 +216,10 @@ public class BookmarkUtils {
}
/* package */ static Uri getBookmarksUri(Context context) {
- return addAccountInfo(context,
- BrowserContract.Bookmarks.CONTENT_URI.buildUpon()).build();
+ return BrowserContract.Bookmarks.CONTENT_URI;
}
+ @Deprecated
public static Uri.Builder addAccountInfo(Context context, Uri.Builder ub) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String accountType = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, null);
diff --git a/src/com/android/browser/BookmarksLoader.java b/src/com/android/browser/BookmarksLoader.java
index 7722392..bc06497 100644
--- a/src/com/android/browser/BookmarksLoader.java
+++ b/src/com/android/browser/BookmarksLoader.java
@@ -49,8 +49,8 @@ public class BookmarksLoader extends CursorLoader {
ChromeSyncColumns.SERVER_UNIQUE, // 9
};
- private String mAccountType;
- private String mAccountName;
+ String mAccountType;
+ String mAccountName;
public BookmarksLoader(Context context, String accountType, String accountName) {
super(context, addAccount(Bookmarks.CONTENT_URI_DEFAULT_FOLDER, accountType, accountName),
diff --git a/src/com/android/browser/BreadCrumbView.java b/src/com/android/browser/BreadCrumbView.java
index 9aaecd7..6706deb 100644
--- a/src/com/android/browser/BreadCrumbView.java
+++ b/src/com/android/browser/BreadCrumbView.java
@@ -41,8 +41,8 @@ import java.util.List;
public class BreadCrumbView extends LinearLayout implements OnClickListener {
private static final int DIVIDER_PADDING = 12; // dips
- interface Controller {
- public void onTop(int level, Object data);
+ public interface Controller {
+ public void onTop(BreadCrumbView view, int level, Object data);
}
private ImageButton mBackButton;
@@ -52,6 +52,7 @@ public class BreadCrumbView extends LinearLayout implements OnClickListener {
private Drawable mSeparatorDrawable;
private float mDividerPadding;
private int mMaxVisible = -1;
+ private Context mContext;
/**
* @param context
@@ -81,12 +82,14 @@ public class BreadCrumbView extends LinearLayout implements OnClickListener {
}
private void init(Context ctx) {
+ mContext = ctx;
+ setFocusable(true);
mUseBackButton = false;
mCrumbs = new ArrayList<Crumb>();
- TypedArray a = ctx.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+ TypedArray a = mContext.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
mSeparatorDrawable = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
a.recycle();
- mDividerPadding = DIVIDER_PADDING * ctx.getResources().getDisplayMetrics().density;
+ mDividerPadding = DIVIDER_PADDING * mContext.getResources().getDisplayMetrics().density;
addBackButton();
}
@@ -134,9 +137,9 @@ public class BreadCrumbView extends LinearLayout implements OnClickListener {
public void notifyController() {
if (mController != null) {
if (mCrumbs.size() > 0) {
- mController.onTop(mCrumbs.size(), getTopCrumb().data);
+ mController.onTop(this, mCrumbs.size(), getTopCrumb().data);
} else {
- mController.onTop(0, null);
+ mController.onTop(this, 0, null);
}
}
}
diff --git a/src/com/android/browser/Browser.java b/src/com/android/browser/Browser.java
index f49da5d..65eb0ce 100644
--- a/src/com/android/browser/Browser.java
+++ b/src/com/android/browser/Browser.java
@@ -16,12 +16,9 @@
package com.android.browser;
-import android.os.FileUtils;
-import android.util.Log;
-
import android.app.Application;
import android.content.Intent;
-import android.webkit.CookieManager;
+import android.util.Log;
import android.webkit.CookieSyncManager;
import dalvik.system.VMRuntime;
@@ -52,9 +49,6 @@ public class Browser extends Application {
public void onCreate() {
super.onCreate();
- // Set the umask so that native code creates files with the correct
- // permissions (0660)
- FileUtils.setUMask(FileUtils.S_IRWXO);
if (LOGV_ENABLED)
Log.v(LOGTAG, "Browser.onCreate: this=" + this);
@@ -63,7 +57,7 @@ public class Browser extends Application {
TARGET_HEAP_UTILIZATION);
// create CookieSyncManager with current Context
CookieSyncManager.createInstance(this);
- BrowserSettings.getInstance().asyncLoadFromDb(this);
+ BrowserSettings.initialize(getApplicationContext());
}
static Intent createBrowserViewIntent() {
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index a9b65fd..963f29f 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -62,11 +62,6 @@ public class BrowserActivity extends Activity {
BrowserSettings settings = BrowserSettings.getInstance();
- // We load the first set of BrowserSettings from the db asynchronously
- // but if it has not completed at this point, we have no choice but
- // to block waiting for them to finish loading. :(
- settings.waitForLoadFromDbToComplete();
-
// render the browser in OpenGL
if (settings.isHardwareAccelerated()) {
// Set the flag in the activity's window
@@ -77,12 +72,6 @@ public class BrowserActivity extends Activity {
this.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
}
- // enable this to test the browser in 32bit
- if (false) {
- getWindow().setFormat(PixelFormat.RGBX_8888);
- BitmapFactory.setDefaultConfig(Bitmap.Config.ARGB_8888);
- }
-
// If this was a web search request, pass it on to the default web
// search provider and finish this activity.
if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) {
diff --git a/src/com/android/browser/BrowserBookmarksAdapter.java b/src/com/android/browser/BrowserBookmarksAdapter.java
index 9e71077..7543528 100644
--- a/src/com/android/browser/BrowserBookmarksAdapter.java
+++ b/src/com/android/browser/BrowserBookmarksAdapter.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,10 +27,9 @@ import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-class BrowserBookmarksAdapter extends CursorAdapter {
+public class BrowserBookmarksAdapter extends CursorAdapter {
LayoutInflater mInflater;
int mCurrentView;
- Drawable mFaviconBackground;
/**
* Create a new BrowserBookmarksAdapter.
@@ -42,8 +40,6 @@ class BrowserBookmarksAdapter extends CursorAdapter {
super(context, null, 0);
mInflater = LayoutInflater.from(context);
selectView(defaultView);
- float density = context.getResources().getDisplayMetrics().density;
- mFaviconBackground = BookmarkUtils.createListFaviconBackground(context);
}
@Override
@@ -101,9 +97,7 @@ class BrowserBookmarksAdapter extends CursorAdapter {
} else {
favicon.setImageBitmap(faviconBitmap);
}
- //favicon.setBackgroundResource(R.drawable.bookmark_list_favicon_bg);
- // TODO: Switch to above instead of below once b/3353813 is fixed
- favicon.setBackgroundDrawable(mFaviconBackground);
+ favicon.setBackgroundResource(R.drawable.bookmark_list_favicon_bg);
}
}
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index c6bc2bc..448f881 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -16,7 +16,9 @@
package com.android.browser;
-import com.android.browser.BreadCrumbView.Crumb;
+import com.android.browser.BookmarkDragHandler.BookmarkDragController;
+import com.android.browser.view.BookmarkExpandableGridView;
+import com.android.browser.view.BookmarkExpandableGridView.BookmarkContextMenuInfo;
import android.app.Activity;
import android.app.Fragment;
@@ -25,11 +27,11 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentUris;
import android.content.Context;
+import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
@@ -40,6 +42,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.BrowserContract;
+import android.provider.BrowserContract.Accounts;
import android.provider.BrowserContract.ChromeSyncColumns;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -50,116 +53,115 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebIconDatabase.IconListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.GridView;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ListView;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Toast;
+import java.util.HashMap;
+
interface BookmarksPageCallbacks {
// Return true if handled
boolean onBookmarkSelected(Cursor c, boolean isFolder);
// Return true if handled
boolean onOpenInNewWindow(Cursor c);
- void onFolderChanged(int level, Uri uri);
}
/**
* View showing the user's bookmarks in the browser.
*/
public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener,
- LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, IconListener,
- BreadCrumbView.Controller, OnMenuItemClickListener, OnSharedPreferenceChangeListener {
+ LoaderManager.LoaderCallbacks<Cursor>, IconListener,
+ BreadCrumbView.Controller, OnMenuItemClickListener, OnChildClickListener {
static final String LOGTAG = "browser";
- static final int LOADER_BOOKMARKS = 1;
+ static final int LOADER_ACCOUNTS = 1;
+ static final int LOADER_BOOKMARKS = 100;
static final String EXTRA_DISABLE_WINDOW = "disable_new_window";
- static final String ACCOUNT_NAME_UNSYNCED = "Unsynced";
-
public static final String PREF_ACCOUNT_TYPE = "acct_type";
public static final String PREF_ACCOUNT_NAME = "acct_name";
+ static final String ACCOUNT_TYPE = "account_type";
+ static final String ACCOUNT_NAME = "account_name";
+
static final int VIEW_THUMBNAILS = 1;
static final int VIEW_LIST = 2;
static final String PREF_SELECTED_VIEW = "bookmarks_view";
BookmarksPageCallbacks mCallbacks;
View mRoot;
- GridView mGrid;
+ BookmarkExpandableGridView mGrid;
ListView mList;
- BrowserBookmarksAdapter mAdapter;
boolean mDisableNewWindow;
- boolean mCanceled = false;
boolean mEnableContextMenu = true;
- boolean mShowRootFolder = false;
View mEmptyView;
int mCurrentView;
View mHeader;
- ViewGroup mHeaderContainer;
- BreadCrumbView mCrumbs;
- int mCrumbVisibility = View.VISIBLE;
- int mCrumbMaxVisible = -1;
- boolean mCrumbBackButton = false;
+ HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>();
+ BookmarkDragHandler mDragHandler;
static BrowserBookmarksPage newInstance(BookmarksPageCallbacks cb,
Bundle args, ViewGroup headerContainer) {
BrowserBookmarksPage bbp = new BrowserBookmarksPage();
bbp.mCallbacks = cb;
- bbp.mHeaderContainer = headerContainer;
bbp.setArguments(args);
return bbp;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- switch (id) {
- case LOADER_BOOKMARKS: {
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(getActivity());
- String accountType = prefs.getString(PREF_ACCOUNT_TYPE, null);
- String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
- BookmarksLoader bl = new BookmarksLoader(getActivity(),
- accountType, accountName);
- if (mCrumbs != null) {
- Uri uri = (Uri) mCrumbs.getTopData();
- if (uri != null) {
- bl.setUri(uri);
- }
- }
- return bl;
- }
+ if (id == LOADER_ACCOUNTS) {
+ return new AccountsLoader(getActivity());
+ } else if (id >= LOADER_BOOKMARKS) {
+ String accountType = args.getString(ACCOUNT_TYPE);
+ String accountName = args.getString(ACCOUNT_NAME);
+ BookmarksLoader bl = new BookmarksLoader(getActivity(),
+ accountType, accountName);
+ return bl;
+ } else {
+ throw new UnsupportedOperationException("Unknown loader id " + id);
}
- throw new UnsupportedOperationException("Unknown loader id " + id);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
- switch (loader.getId()) {
- case LOADER_BOOKMARKS: {
- // Set the visibility of the empty vs. content views
- if (cursor == null || cursor.getCount() == 0) {
- mEmptyView.setVisibility(View.VISIBLE);
- mGrid.setVisibility(View.GONE);
- mList.setVisibility(View.GONE);
- } else {
- mEmptyView.setVisibility(View.GONE);
- setupBookmarkView();
- }
-
- // Give the new data to the adapter
- mAdapter.changeCursor(cursor);
- break;
+ if (loader.getId() == LOADER_ACCOUNTS) {
+ LoaderManager lm = getLoaderManager();
+ int id = LOADER_BOOKMARKS;
+ while (cursor.moveToNext()) {
+ String accountName = cursor.getString(0);
+ String accountType = cursor.getString(1);
+ Bundle args = new Bundle();
+ args.putString(ACCOUNT_NAME, accountName);
+ args.putString(ACCOUNT_TYPE, accountType);
+ BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
+ getActivity(), mCurrentView);
+ mBookmarkAdapters.put(id, adapter);
+ mGrid.addAccount(accountName, adapter);
+ lm.restartLoader(id, args, this);
+ id++;
}
+ // TODO: Figure out what a reload of these means
+ // Currently, a reload is triggered whenever bookmarks change
+ // This is less than ideal
+ // It also causes UI flickering as a new adapter is created
+ // instead of re-using an existing one when the account_name is the
+ // same.
+ // For now, this is a one-shot load
+ getLoaderManager().destroyLoader(LOADER_ACCOUNTS);
+ } else if (loader.getId() >= LOADER_BOOKMARKS) {
+ BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId());
+ adapter.changeCursor(cursor);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
- onLoadFinished(loader, null);
+ // TODO: Figure out what to do here (if anything?)
}
long getFolderId() {
@@ -181,37 +183,32 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
@Override
public boolean onContextItemSelected(MenuItem item) {
final Activity activity = getActivity();
- // It is possible that the view has been canceled when we get to
- // this point as back has a higher priority
- if (mCanceled) {
- return false;
- }
- AdapterView.AdapterContextMenuInfo i =
- (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+ BookmarkContextMenuInfo i = (BookmarkContextMenuInfo)item.getMenuInfo();
// If we have no menu info, we can't tell which item was selected.
if (i == null) {
return false;
}
+ BrowserBookmarksAdapter adapter = getChildAdapter(i.groupPosition);
switch (item.getItemId()) {
case R.id.open_context_menu_id:
- loadUrl(i.position);
+ loadUrl(adapter, i.childPosition);
break;
case R.id.edit_context_menu_id:
- editBookmark(i.position);
+ editBookmark(adapter, i.childPosition);
break;
case R.id.shortcut_context_menu_id:
- Cursor c = mAdapter.getItem(i.position);
+ Cursor c = adapter.getItem(i.childPosition);
activity.sendBroadcast(createShortcutIntent(getActivity(), c));
break;
case R.id.delete_context_menu_id:
- displayRemoveBookmarkDialog(i.position);
+ displayRemoveBookmarkDialog(adapter, i.childPosition);
break;
case R.id.new_window_context_menu_id:
- openInNewWindow(i.position);
+ openInNewWindow(adapter, i.childPosition);
break;
case R.id.share_link_context_menu_id: {
- Cursor cursor = mAdapter.getItem(i.position);
+ Cursor cursor = adapter.getItem(i.childPosition);
Controller.sharePage(activity,
cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE),
cursor.getString(BookmarksLoader.COLUMN_INDEX_URL),
@@ -220,16 +217,16 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
break;
}
case R.id.copy_url_context_menu_id:
- copy(getUrl(i.position));
+ copy(getUrl(adapter, i.childPosition));
break;
case R.id.homepage_context_menu_id: {
- BrowserSettings.getInstance().setHomePage(activity, getUrl(i.position));
+ BrowserSettings.getInstance().setHomePage(getUrl(adapter, i.childPosition));
Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
break;
}
// Only for the Most visited page
case R.id.save_to_bookmarks_menu_id: {
- Cursor cursor = mAdapter.getItem(i.position);
+ Cursor cursor = adapter.getItem(i.childPosition);
String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL);
// If the site is bookmarked, the item becomes remove from
@@ -270,8 +267,9 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- Cursor cursor = mAdapter.getItem(info.position);
+ BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo;
+ BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition);
+ Cursor cursor = adapter.getItem(info.childPosition);
if (!canEdit(cursor)) {
return;
}
@@ -330,55 +328,37 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
-
- setHasOptionsMenu(true);
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ mCurrentView = prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
+ // TODO: Support list view
+ mCurrentView = VIEW_THUMBNAILS;
Bundle args = getArguments();
mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false);
+
+ setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- Context context = getActivity();
-
mRoot = inflater.inflate(R.layout.bookmarks, container, false);
mEmptyView = mRoot.findViewById(android.R.id.empty);
- mGrid = (GridView) mRoot.findViewById(R.id.grid);
- mGrid.setOnItemClickListener(this);
- mGrid.setColumnWidth(Controller.getDesiredThumbnailWidth(getActivity()));
+ mGrid = (BookmarkExpandableGridView) mRoot.findViewById(R.id.grid);
+ mGrid.setOnChildClickListener(this);
+ mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
+ mGrid.setBreadcrumbController(this);
mList = (ListView) mRoot.findViewById(R.id.list);
- mList.setOnItemClickListener(this);
+ // TODO: mList.setOnItemClickListener(this);
setEnableContextMenu(mEnableContextMenu);
+ mDragHandler = new BookmarkDragHandler(getActivity(), mDragController,
+ mGrid.getDragAdapter());
- // Prep the header
- ViewGroup hc = mHeaderContainer;
- if (hc == null) {
- hc = (ViewGroup) mRoot.findViewById(R.id.header_container);
- hc.setVisibility(View.VISIBLE);
- }
- mHeader = inflater.inflate(R.layout.bookmarks_header, hc, false);
- hc.addView(mHeader);
- mCrumbs = (BreadCrumbView) mHeader.findViewById(R.id.crumbs);
- mCrumbs.setController(this);
- mCrumbs.setUseBackButton(mCrumbBackButton);
- mCrumbs.setMaxVisible(mCrumbMaxVisible);
- mCrumbs.setVisibility(mCrumbVisibility);
- String name = getString(R.string.bookmarks);
- mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
- if (mCallbacks != null) {
- mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
- }
// Start the loaders
LoaderManager lm = getLoaderManager();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(getActivity());
- prefs.registerOnSharedPreferenceChangeListener(this);
- mCurrentView =
- prefs.getInt(PREF_SELECTED_VIEW, getDefaultView());
- mAdapter = new BrowserBookmarksAdapter(getActivity(), mCurrentView);
- lm.restartLoader(LOADER_BOOKMARKS, null, this);
+ lm.restartLoader(LOADER_ACCOUNTS, null, this);
// Add our own listener in case there are favicons that have yet to be loaded.
CombinedBookmarkHistoryView.getIconListenerSet().addListener(this);
@@ -396,16 +376,14 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
@Override
public void onDestroyView() {
super.onDestroyView();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(getActivity());
- prefs.unregisterOnSharedPreferenceChangeListener(this);
- if (mHeaderContainer != null) {
- mHeaderContainer.removeView(mHeader);
- }
- mCrumbs.setController(null);
- mCrumbs = null;
- getLoaderManager().destroyLoader(LOADER_BOOKMARKS);
- mAdapter = null;
+ mGrid.setBreadcrumbController(null);
+ LoaderManager lm = getLoaderManager();
+ lm.destroyLoader(LOADER_ACCOUNTS);
+ for (int id : mBookmarkAdapters.keySet()) {
+ lm.destroyLoader(id);
+ }
+ mBookmarkAdapters.clear();
+
CombinedBookmarkHistoryView.getIconListenerSet().removeListener(this);
}
@@ -413,35 +391,52 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
public void onReceivedIcon(String url, Bitmap icon) {
// A new favicon has been loaded, so let anything attached to the adapter know about it
// so new icons will be loaded.
- mAdapter.notifyDataSetChanged();
+ // TODO: Notify all of data set changed
+ // TODO: Wait, is this even needed? Won't this trigger a DB change anyway?
}
- @Override
- public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
- // It is possible that the view has been canceled when we get to
- // this point as back has a higher priority
- if (mCanceled) {
- android.util.Log.e(LOGTAG, "item clicked when dismissing");
- return;
+ private BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
+ if (mCurrentView == VIEW_THUMBNAILS) {
+ return mGrid.getChildAdapter(groupPosition);
+ } else {
+ // TODO: Support expandable list
+ return null;
+ }
+ }
+
+ private BreadCrumbView getBreadCrumbs(int groupPosition) {
+ if (mCurrentView == VIEW_THUMBNAILS) {
+ return mGrid.getBreadCrumbs(groupPosition);
+ } else {
+ // TODO: Support expandable list
+ return null;
}
+ }
- Cursor cursor = mAdapter.getItem(position);
+ @Override
+ public boolean onChildClick(ExpandableListView parent, View v,
+ int groupPosition, int childPosition, long id) {
+ BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition);
+ Cursor cursor = adapter.getItem(childPosition);
boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0;
if (mCallbacks != null &&
mCallbacks.onBookmarkSelected(cursor, isFolder)) {
- return;
+ return true;
}
+ // TODO: Folder stuff
if (isFolder) {
String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Uri uri = ContentUris.withAppendedId(
BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id);
- if (mCrumbs != null) {
+ BreadCrumbView crumbs = getBreadCrumbs(groupPosition);
+ if (crumbs != null) {
// update crumbs
- mCrumbs.pushView(title, uri);
+ crumbs.pushView(title, uri);
}
- loadFolder(uri);
+ loadFolder(groupPosition, uri);
}
+ return true;
}
/* package */ static Intent createShortcutIntent(Context context, Cursor cursor) {
@@ -452,15 +447,15 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon);
}
- private void loadUrl(int position) {
- if (mCallbacks != null && mAdapter != null) {
- mCallbacks.onBookmarkSelected(mAdapter.getItem(position), false);
+ private void loadUrl(BrowserBookmarksAdapter adapter, int position) {
+ if (mCallbacks != null && adapter != null) {
+ mCallbacks.onBookmarkSelected(adapter.getItem(position), false);
}
}
- private void openInNewWindow(int position) {
+ private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) {
if (mCallbacks != null) {
- Cursor c = mAdapter.getItem(position);
+ Cursor c = adapter.getItem(position);
boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
if (isFolder) {
long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
@@ -497,9 +492,9 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
- private void editBookmark(int position) {
+ private void editBookmark(BrowserBookmarksAdapter adapter, int position) {
Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
- Cursor cursor = mAdapter.getItem(position);
+ Cursor cursor = adapter.getItem(position);
Bundle item = new Bundle();
item.putString(BrowserContract.Bookmarks.TITLE,
cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE));
@@ -520,18 +515,19 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
startActivity(intent);
}
- private void displayRemoveBookmarkDialog(final int position) {
+ private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter,
+ int position) {
// Put up a dialog asking if the user really wants to
// delete the bookmark
- Cursor cursor = mAdapter.getItem(position);
+ Cursor cursor = adapter.getItem(position);
long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID);
String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE);
Context context = getActivity();
BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null);
}
- private String getUrl(int position) {
- return getUrl(mAdapter.getItem(position));
+ private String getUrl(BrowserBookmarksAdapter adapter, int position) {
+ return getUrl(adapter.getItem(position));
}
/* package */ static String getUrl(Cursor c) {
@@ -563,6 +559,7 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
Resources res = getActivity().getResources();
int horizontalSpacing = (int) res.getDimension(R.dimen.combo_horizontalSpacing);
mGrid.setHorizontalSpacing(horizontalSpacing);
+ mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail);
int paddingLeftRight = (int) res.getDimension(R.dimen.combo_paddingLeftRight);
int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop);
mRoot.setPadding(paddingLeftRight, paddingTop,
@@ -578,10 +575,11 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
void selectView(int view) {
+ // TODO: Support list view
+ view = mCurrentView;
if (view == mCurrentView) {
return;
}
- mCurrentView = view;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
Editor edit = prefs.edit();
edit.putInt(PREF_SELECTED_VIEW, mCurrentView);
@@ -593,52 +591,53 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
private void setupBookmarkView() {
- mAdapter.selectView(mCurrentView);
- switch (mCurrentView) {
- case VIEW_THUMBNAILS:
- mList.setAdapter(null);
- if (mGrid.getAdapter() != mAdapter) {
- mGrid.setAdapter(mAdapter);
- }
- mGrid.setVisibility(View.VISIBLE);
- mList.setVisibility(View.GONE);
- break;
- case VIEW_LIST:
- mGrid.setAdapter(null);
- if (mList.getAdapter() != mAdapter) {
- mList.setAdapter(mAdapter);
- }
- mGrid.setVisibility(View.GONE);
- mList.setVisibility(View.VISIBLE);
- break;
- }
+ // TODO: Support list view
+// mAdapter.selectView(mCurrentView);
+// switch (mCurrentView) {
+// case VIEW_THUMBNAILS:
+// mList.setAdapter(null);
+// SharedPreferences prefs = PreferenceManager
+// .getDefaultSharedPreferences(getActivity());
+// String accountName = prefs.getString(PREF_ACCOUNT_NAME, null);
+// mGrid.addAccount(accountName, mAdapter);
+// mGrid.setVisibility(View.VISIBLE);
+// mList.setVisibility(View.GONE);
+// break;
+// case VIEW_LIST:
+// mGrid.clearAccounts();
+// if (mList.getAdapter() != mAdapter) {
+// mList.setAdapter(mAdapter);
+// }
+// mGrid.setVisibility(View.GONE);
+// mList.setVisibility(View.VISIBLE);
+// break;
+// }
}
/**
* BreadCrumb controller callback
*/
@Override
- public void onTop(int level, Object data) {
+ public void onTop(BreadCrumbView view, int level, Object data) {
+ int groupPosition = (Integer) view.getTag(R.id.group_position);
Uri uri = (Uri) data;
if (uri == null) {
// top level
uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER;
}
- loadFolder(uri);
+ loadFolder(groupPosition, uri);
}
/**
* @param uri
*/
- private void loadFolder(Uri uri) {
+ private void loadFolder(int groupPosition, Uri uri) {
LoaderManager manager = getLoaderManager();
- BookmarksLoader loader =
- (BookmarksLoader) ((Loader<?>) manager.getLoader(LOADER_BOOKMARKS));
+ // This assumes groups are ordered the same as loaders
+ BookmarksLoader loader = (BookmarksLoader) ((Loader<?>)
+ manager.getLoader(LOADER_BOOKMARKS + groupPosition));
loader.setUri(uri);
loader.forceLoad();
- if (mCallbacks != null) {
- mCallbacks.onFolderChanged(mCrumbs.getTopLevel(), uri);
- }
}
@Override
@@ -655,18 +654,9 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
public boolean onBackPressed() {
- if (canGoBack()) {
- mCrumbs.popView();
- return true;
- }
return false;
}
- private boolean canGoBack() {
- Crumb c = mCrumbs.getTopCrumb();
- return c != null && c.canGoBack;
- }
-
public void setCallbackListener(BookmarksPageCallbacks callbackListener) {
mCallbacks = callbackListener;
}
@@ -691,6 +681,14 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
}
+ private BookmarkDragController mDragController = new BookmarkDragController() {
+
+ @Override
+ public boolean startDrag(Cursor item) {
+ return canEdit(item);
+ }
+ };
+
private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> {
Context mContext;
BookmarkItem mHeader;
@@ -723,41 +721,17 @@ public class BrowserBookmarksPage extends Fragment implements View.OnCreateConte
}
}
- public void setBreadCrumbVisibility(int visibility) {
- mCrumbVisibility = visibility;
- if (mCrumbs != null) {
- mCrumbs.setVisibility(mCrumbVisibility);
- }
- }
+ static class AccountsLoader extends CursorLoader {
- public void setBreadCrumbUseBackButton(boolean use) {
- mCrumbBackButton = use;
- if (mCrumbs != null) {
- mCrumbs.setUseBackButton(mCrumbBackButton);
- }
- }
+ static String[] ACCOUNTS_PROJECTION = new String[] {
+ Accounts.ACCOUNT_NAME,
+ Accounts.ACCOUNT_TYPE
+ };
- public void setBreadCrumbMaxVisible(int max) {
- mCrumbMaxVisible = max;
- if (mCrumbs != null) {
- mCrumbs.setMaxVisible(mCrumbMaxVisible);
+ public AccountsLoader(Context context) {
+ super(context, Accounts.CONTENT_URI, ACCOUNTS_PROJECTION, null, null,
+ Accounts.ACCOUNT_NAME + " ASC");
}
- }
- @Override
- public void onSharedPreferenceChanged(
- SharedPreferences sharedPreferences, String key) {
- if (PREF_ACCOUNT_NAME.equals(key) || PREF_ACCOUNT_TYPE.equals(key)) {
- mCrumbs.setController(null);
- mCrumbs.clear();
- LoaderManager lm = getLoaderManager();
- lm.restartLoader(LOADER_BOOKMARKS, null, this);
- mCrumbs.setController(this);
- String name = getString(R.string.bookmarks);
- mCrumbs.pushView(name, false, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
- if (mCallbacks != null) {
- mCallbacks.onFolderChanged(1, BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
- }
- }
}
}
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 44f358d..e728254 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -59,6 +59,9 @@ import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
@@ -68,7 +71,7 @@ import android.widget.Toast;
* days of viewing.
*/
public class BrowserHistoryPage extends Fragment
- implements LoaderCallbacks<Cursor> {
+ implements LoaderCallbacks<Cursor>, OnChildClickListener {
static final int LOADER_HISTORY = 1;
static final int LOADER_MOST_VISITED = 2;
@@ -82,6 +85,7 @@ public class BrowserHistoryPage extends Fragment
ListView mGroupList, mChildList;
private ViewGroup mPrefsContainer;
private FragmentBreadCrumbs mFragmentBreadCrumbs;
+ private ExpandableListView mHistoryList;
// Implementation of WebIconDatabase.IconListener
class IconReceiver implements IconListener {
@@ -187,7 +191,7 @@ public class BrowserHistoryPage extends Fragment
switch (loader.getId()) {
case LOADER_HISTORY: {
mAdapter.changeCursor(data);
- if (!mAdapter.isEmpty()
+ if (!mAdapter.isEmpty() && mGroupList != null
&& mGroupList.getCheckedItemPosition() == ListView.INVALID_POSITION) {
selectGroup(0);
}
@@ -229,16 +233,39 @@ public class BrowserHistoryPage extends Fragment
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRoot = inflater.inflate(R.layout.history, container, false);
+ mAdapter = new HistoryAdapter(getActivity());
ViewStub stub = (ViewStub) mRoot.findViewById(R.id.pref_stub);
- stub.setLayoutResource(com.android.internal.R.layout.preference_list_content);
+ if (stub != null) {
+ inflateTwoPane(stub);
+ } else {
+ inflateSinglePane();
+ }
+
+ // Start the loaders
+ getLoaderManager().restartLoader(LOADER_HISTORY, null, this);
+ getLoaderManager().restartLoader(LOADER_MOST_VISITED, null, this);
+
+ // Register to receive icons in case they haven't all been loaded.
+ CombinedBookmarkHistoryView.getIconListenerSet().addListener(mIconReceiver);
+ return mRoot;
+ }
+
+ private void inflateSinglePane() {
+ mHistoryList = (ExpandableListView) mRoot.findViewById(R.id.history);
+ mHistoryList.setAdapter(mAdapter);
+ mHistoryList.setOnChildClickListener(this);
+ registerForContextMenu(mHistoryList);
+ }
+
+ private void inflateTwoPane(ViewStub stub) {
+ stub.setLayoutResource(R.layout.preference_list_content);
stub.inflate();
mGroupList = (ListView) mRoot.findViewById(android.R.id.list);
- mPrefsContainer = (ViewGroup) mRoot.findViewById(com.android.internal.R.id.prefs_frame);
+ mPrefsContainer = (ViewGroup) mRoot.findViewById(R.id.prefs_frame);
mFragmentBreadCrumbs = (FragmentBreadCrumbs) mRoot.findViewById(android.R.id.title);
mFragmentBreadCrumbs.setMaxVisible(1);
mFragmentBreadCrumbs.setActivity(getActivity());
mPrefsContainer.setVisibility(View.VISIBLE);
- mAdapter = new HistoryAdapter(getActivity());
mGroupList.setAdapter(new HistoryGroupWrapper(mAdapter));
mGroupList.setOnItemClickListener(mGroupItemClickListener);
mGroupList.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
@@ -247,16 +274,8 @@ public class BrowserHistoryPage extends Fragment
mChildList.setAdapter(mChildWrapper);
mChildList.setOnItemClickListener(mChildItemClickListener);
registerForContextMenu(mChildList);
- ViewGroup prefs = (ViewGroup) mRoot.findViewById(com.android.internal.R.id.prefs);
+ ViewGroup prefs = (ViewGroup) mRoot.findViewById(R.id.prefs);
prefs.addView(mChildList);
-
- // Start the loaders
- getLoaderManager().restartLoader(LOADER_HISTORY, null, this);
- getLoaderManager().restartLoader(LOADER_MOST_VISITED, null, this);
-
- // Register to receive icons in case they haven't all been loaded.
- CombinedBookmarkHistoryView.getIconListenerSet().addListener(mIconReceiver);
- return mRoot;
}
private OnItemClickListener mGroupItemClickListener = new OnItemClickListener() {
@@ -279,6 +298,13 @@ public class BrowserHistoryPage extends Fragment
};
@Override
+ public boolean onChildClick(ExpandableListView parent, View view,
+ int groupPosition, int childPosition, long id) {
+ mCallbacks.onUrlSelected(((HistoryItem) view).getUrl(), false);
+ return true;
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
CombinedBookmarkHistoryView.getIconListenerSet().removeListener(mIconReceiver);
@@ -341,17 +367,30 @@ public class BrowserHistoryPage extends Fragment
}
}
+ View getTargetView(ContextMenuInfo menuInfo) {
+ if (menuInfo instanceof AdapterContextMenuInfo) {
+ return ((AdapterContextMenuInfo) menuInfo).targetView;
+ }
+ if (menuInfo instanceof ExpandableListContextMenuInfo) {
+ return ((ExpandableListContextMenuInfo) menuInfo).targetView;
+ }
+ return null;
+ }
+
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- AdapterContextMenuInfo i = (AdapterContextMenuInfo) menuInfo;
+
+ View targetView = getTargetView(menuInfo);
+ if (!(targetView instanceof HistoryItem)) {
+ return;
+ }
+ HistoryItem historyItem = (HistoryItem) targetView;
// Inflate the menu
Activity parent = getActivity();
MenuInflater inflater = parent.getMenuInflater();
inflater.inflate(R.menu.historycontext, menu);
- HistoryItem historyItem = (HistoryItem) i.targetView;
-
// Setup the header
if (mContextHeader == null) {
mContextHeader = new HistoryItem(parent, false);
@@ -382,12 +421,11 @@ public class BrowserHistoryPage extends Fragment
@Override
public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo i =
- (AdapterContextMenuInfo) item.getMenuInfo();
- if (i == null) {
+ ContextMenuInfo menuInfo = item.getMenuInfo();
+ if (menuInfo == null) {
return false;
}
- HistoryItem historyItem = (HistoryItem) i.targetView;
+ HistoryItem historyItem = (HistoryItem) getTargetView(menuInfo);
String url = historyItem.getUrl();
String title = historyItem.getName();
Activity activity = getActivity();
@@ -417,7 +455,7 @@ public class BrowserHistoryPage extends Fragment
Browser.deleteFromHistory(activity.getContentResolver(), url);
return true;
case R.id.homepage_context_menu_id:
- BrowserSettings.getInstance().setHomePage(activity, url);
+ BrowserSettings.getInstance().setHomePage(url);
Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show();
return true;
default:
@@ -636,6 +674,7 @@ public class BrowserHistoryPage extends Fragment
item.getPaddingRight(),
item.getPaddingBottom());
item.setFaviconBackground(mFaviconBackground);
+ item.startMarquee();
} else {
item = (HistoryItem) convertView;
}
diff --git a/src/com/android/browser/BrowserPreferencesPage.java b/src/com/android/browser/BrowserPreferencesPage.java
index dae838f..8302011 100644
--- a/src/com/android/browser/BrowserPreferencesPage.java
+++ b/src/com/android/browser/BrowserPreferencesPage.java
@@ -21,7 +21,6 @@ import com.android.browser.preferences.DebugPreferencesFragment;
import android.app.ActionBar;
import android.os.Bundle;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceManager;
import android.view.MenuItem;
import java.util.List;
@@ -48,7 +47,7 @@ public class BrowserPreferencesPage extends PreferenceActivity {
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
- if (BrowserSettings.DEV_BUILD || BrowserSettings.getInstance().showDebugSettings()) {
+ if (BrowserSettings.getInstance().isDebugEnabled()) {
Header debug = new Header();
debug.title = getText(R.string.pref_development_title);
debug.fragment = DebugPreferencesFragment.class.getName();
@@ -57,16 +56,6 @@ public class BrowserPreferencesPage extends PreferenceActivity {
}
@Override
- protected void onPause() {
- super.onPause();
-
- // sync the shared preferences back to BrowserSettings
- BrowserSettings.getInstance().syncSharedPreferences(
- getApplicationContext(),
- PreferenceManager.getDefaultSharedPreferences(this));
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 9ae2a25..dd46314 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -1,6 +1,5 @@
-
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -18,409 +17,288 @@
package com.android.browser;
import com.android.browser.homepages.HomeProvider;
+import com.android.browser.provider.BrowserProvider;
import com.android.browser.search.SearchEngine;
import com.android.browser.search.SearchEngines;
import android.app.ActivityManager;
import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
+import android.os.Build;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.Browser;
-import android.provider.BrowserContract.Bookmarks;
-import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
import android.webkit.WebIconDatabase;
import android.webkit.WebSettings;
import android.webkit.WebSettings.AutoFillProfile;
+import android.webkit.WebSettings.LayoutAlgorithm;
+import android.webkit.WebSettings.PluginState;
+import android.webkit.WebSettings.TextSize;
+import android.webkit.WebSettings.ZoomDensity;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
-import java.util.HashMap;
-import java.util.Observable;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.WeakHashMap;
-/*
- * Package level class for storing various WebView and Browser settings. To use
- * this class:
- * BrowserSettings s = BrowserSettings.getInstance();
- * s.addObserver(webView.getSettings());
- * s.loadFromDb(context); // Only needed on app startup
- * s.javaScriptEnabled = true;
- * ... // set any other settings
- * s.update(); // this will update all the observers
- *
- * To remove an observer:
- * s.deleteObserver(webView.getSettings());
+/**
+ * Class for managing settings
*/
-public class BrowserSettings extends Observable implements OnSharedPreferenceChangeListener {
- // Private variables for settings
- // NOTE: these defaults need to be kept in sync with the XML
- // until the performance of PreferenceManager.setDefaultValues()
- // is improved.
- // Note: boolean variables are set inside reset function.
- private boolean loadsImagesAutomatically;
- private boolean javaScriptEnabled;
- private WebSettings.PluginState pluginState;
- private boolean javaScriptCanOpenWindowsAutomatically;
- private boolean showSecurityWarnings;
- private boolean rememberPasswords;
- private boolean saveFormData;
- private boolean autoFillEnabled;
- private boolean openInBackground;
- private String defaultTextEncodingName;
- private String homeUrl = "";
- private SearchEngine searchEngine;
- private boolean autoFitPage;
- private boolean loadsPageInOverviewMode;
- private boolean showDebugSettings;
- // HTML5 API flags
- private boolean appCacheEnabled;
- private boolean databaseEnabled;
- private boolean domStorageEnabled;
- private boolean geolocationEnabled;
- private boolean workersEnabled; // only affects V8. JSC does not have a similar setting
- // HTML5 API configuration params
- private long appCacheMaxSize = Long.MAX_VALUE;
- private String appCachePath; // default value set in loadFromDb().
- private String databasePath; // default value set in loadFromDb()
- private String geolocationDatabasePath; // default value set in loadFromDb()
- private WebStorageSizeManager webStorageSizeManager;
-
- private String jsFlags = "";
-
- private final static String TAG = "BrowserSettings";
-
- // Development settings
- public WebSettings.LayoutAlgorithm layoutAlgorithm =
- WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
- private boolean useWideViewPort = true;
- private int userAgent = 0;
- private boolean tracing = false;
- private boolean lightTouch = false;
- private boolean navDump = false;
- private boolean hardwareAccelerated = true;
- private boolean showVisualIndicator = false;
- // Lab settings
- private boolean quickControls = false;
- private boolean useMostVisitedHomepage = false;
- private boolean useInstant = false;
-
- // By default the error console is shown once the user navigates to about:debug.
- // The setting can be then toggled from the settings menu.
- private boolean showConsole = true;
-
- // Private preconfigured values
- private static int minimumFontSize = 1;
- private static int minimumLogicalFontSize = 1;
- private static int defaultFontSize = 16;
- private static int defaultFixedFontSize = 13;
- private static WebSettings.TextSize textSize =
- WebSettings.TextSize.NORMAL;
- private static WebSettings.ZoomDensity zoomDensity =
- WebSettings.ZoomDensity.MEDIUM;
- private static int pageCacheCapacity;
-
-
- private AutoFillProfile autoFillProfile;
- // Default to zero. In the case no profile is set up, the initial
- // value will come from the AutoFillSettingsFragment when the user
- // creates a profile. Otherwise, we'll read the ID of the last used
- // profile from the prefs db.
- private int autoFillActiveProfileId;
- private static final int NO_AUTOFILL_PROFILE_SET = 0;
-
- // Preference keys that are used outside this class
- public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
- public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
- public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
- public final static String PREF_HOMEPAGE = "homepage";
- public final static String PREF_SEARCH_ENGINE = "search_engine";
- public final static String PREF_CLEAR_FORM_DATA =
- "privacy_clear_form_data";
- public final static String PREF_CLEAR_PASSWORDS =
- "privacy_clear_passwords";
- public final static String PREF_EXTRAS_RESET_DEFAULTS =
- "reset_default_preferences";
- public final static String PREF_DEBUG_SETTINGS = "debug_menu";
- public final static String PREF_WEBSITE_SETTINGS = "website_settings";
- public final static String PREF_TEXT_SIZE = "text_size";
- public final static String PREF_DEFAULT_ZOOM = "default_zoom";
- public final static String PREF_DEFAULT_TEXT_ENCODING =
- "default_text_encoding";
- public final static String PREF_CLEAR_GEOLOCATION_ACCESS =
- "privacy_clear_geolocation_access";
- public final static String PREF_AUTOFILL_ENABLED = "autofill_enabled";
- public final static String PREF_AUTOFILL_PROFILE = "autofill_profile";
- public final static String PREF_AUTOFILL_ACTIVE_PROFILE_ID = "autofill_active_profile_id";
- public final static String PREF_HARDWARE_ACCEL = "enable_hardware_accel";
- public final static String PREF_VISUAL_INDICATOR = "enable_visual_indicator";
- public final static String PREF_USER_AGENT = "user_agent";
-
- public final static String PREF_QUICK_CONTROLS = "enable_quick_controls";
- public final static String PREF_MOST_VISITED_HOMEPAGE = "use_most_visited_homepage";
- public final static String PREF_PLUGIN_STATE = "plugin_state";
- public final static String PREF_USE_INSTANT = "use_instant_search";
-
- private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
- "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
- "like Gecko) Version/5.0 Safari/533.16";
+public class BrowserSettings implements OnSharedPreferenceChangeListener,
+ PreferenceKeys {
+
+ // TODO: Do something with this UserAgent stuff
+ private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (X11; " +
+ "Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) " +
+ "Chrome/11.0.696.34 Safari/534.24";
private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
- "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";
+ "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";
+ "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
- public final static int MAX_TEXTVIEW_LEN = 80;
-
- public static final String RLZ_PROVIDER = "com.google.android.partnersetup.rlzappprovider";
-
- public static final Uri RLZ_PROVIDER_URI = Uri.parse("content://" + RLZ_PROVIDER + "/");
-
- // Set to true to enable some of the about:debug options
- public static final boolean DEV_BUILD = false;
-
+ "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " +
+ "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
+
+ private static final String HONEYCOMB_USERAGENT = "Mozilla/5.0 (Linux; U; " +
+ "Android 3.1; en-us; Xoom Build/HMJ25) AppleWebKit/534.13 " +
+ "(KHTML, like Gecko) Version/4.0 Safari/534.13";
+
+ private static final String USER_AGENTS[] = { null,
+ DESKTOP_USERAGENT,
+ IPHONE_USERAGENT,
+ IPAD_USERAGENT,
+ FROYO_USERAGENT,
+ HONEYCOMB_USERAGENT,
+ };
+
+ private static BrowserSettings sInstance;
+
+ private Context mContext;
+ private SharedPreferences mPrefs;
+ private LinkedList<WeakReference<WebSettings>> mManagedSettings;
private Controller mController;
+ private WebStorageSizeManager mWebStorageSizeManager;
+ private AutofillHandler mAutofillHandler;
+ private WeakHashMap<WebSettings, String> mCustomUserAgents;
- // Single instance of the BrowserSettings for use in the Browser app.
- private static BrowserSettings sSingleton;
-
- // Private map of WebSettings to Observer objects used when deleting an
- // observer.
- private HashMap<WebSettings,Observer> mWebSettingsToObservers =
- new HashMap<WebSettings,Observer>();
+ // Cached settings
+ private SearchEngine mSearchEngine;
- private String mRlzValue = "";
+ public static void initialize(final Context context) {
+ sInstance = new BrowserSettings(context);
+ }
- private boolean mLoadFromDbComplete;
+ public static BrowserSettings getInstance() {
+ return sInstance;
+ }
- public void waitForLoadFromDbToComplete() {
- synchronized (sSingleton) {
- while (!mLoadFromDbComplete) {
- try {
- sSingleton.wait();
- } catch (InterruptedException e) { }
- }
+ private BrowserSettings(Context context) {
+ mContext = context;
+ mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ if (Build.VERSION.CODENAME.equals("REL")) {
+ // This is a release build, always startup with debug disabled
+ setDebugEnabled(false);
}
+ mAutofillHandler = new AutofillHandler(mContext);
+ mManagedSettings = new LinkedList<WeakReference<WebSettings>>();
+ mCustomUserAgents = new WeakHashMap<WebSettings, String>();
+ mWebStorageSizeManager = new WebStorageSizeManager(mContext,
+ new WebStorageSizeManager.StatFsDiskInfo(getAppCachePath()),
+ new WebStorageSizeManager.WebKitAppCacheInfo(getAppCachePath()));
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+ mAutofillHandler.asyncLoadFromDb();
}
- /*
- * An observer wrapper for updating a WebSettings object with the new
- * settings after a call to BrowserSettings.update().
- */
- static class Observer implements java.util.Observer {
- // Private WebSettings object that will be updated.
- private WebSettings mSettings;
+ public void setController(Controller controller) {
+ mController = controller;
+ syncSharedSettings();
- Observer(WebSettings w) {
- mSettings = w;
+ if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) {
+ ((InstantSearchEngine) mSearchEngine).setController(mController);
}
+ }
- public void update(Observable o, Object arg) {
- BrowserSettings b = (BrowserSettings)o;
- WebSettings s = mSettings;
-
- s.setLayoutAlgorithm(b.layoutAlgorithm);
- if (b.userAgent == 0) {
- // use the default ua string
- s.setUserAgentString(null);
- } else if (b.userAgent == 1) {
- 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);
- s.setJavaScriptEnabled(b.javaScriptEnabled);
- s.setShowVisualIndicator(b.showVisualIndicator);
- s.setPluginState(b.pluginState);
- s.setJavaScriptCanOpenWindowsAutomatically(
- b.javaScriptCanOpenWindowsAutomatically);
- s.setDefaultTextEncodingName(b.defaultTextEncodingName);
- s.setMinimumFontSize(b.minimumFontSize);
- s.setMinimumLogicalFontSize(b.minimumLogicalFontSize);
- s.setDefaultFontSize(b.defaultFontSize);
- s.setDefaultFixedFontSize(b.defaultFixedFontSize);
- s.setNavDump(b.navDump);
- s.setTextSize(b.textSize);
- s.setDefaultZoom(b.zoomDensity);
- s.setLightTouchEnabled(b.lightTouch);
- s.setSaveFormData(b.saveFormData);
- s.setAutoFillEnabled(b.autoFillEnabled);
- s.setSavePassword(b.rememberPasswords);
- s.setLoadWithOverviewMode(b.loadsPageInOverviewMode);
- s.setPageCacheCapacity(pageCacheCapacity);
-
- // WebView inside Browser doesn't want initial focus to be set.
- s.setNeedInitialFocus(false);
- // Browser supports multiple windows
- s.setSupportMultipleWindows(true);
- // enable smooth transition for better performance during panning or
- // zooming
- s.setEnableSmoothTransition(true);
- // disable content url access
- s.setAllowContentAccess(false);
-
- // HTML5 API flags
- s.setAppCacheEnabled(b.appCacheEnabled);
- s.setDatabaseEnabled(b.databaseEnabled);
- s.setDomStorageEnabled(b.domStorageEnabled);
- s.setWorkersEnabled(b.workersEnabled); // This only affects V8.
- s.setGeolocationEnabled(b.geolocationEnabled);
-
- // HTML5 configuration parameters.
- s.setAppCacheMaxSize(b.appCacheMaxSize);
- s.setAppCachePath(b.appCachePath);
- s.setDatabasePath(b.databasePath);
- s.setGeolocationDatabasePath(b.geolocationDatabasePath);
-
- // Active AutoFill profile data.
- s.setAutoFillProfile(b.autoFillProfile);
-
- b.updateTabControlSettings();
+ public void startManagingSettings(WebSettings settings) {
+ synchronized (mManagedSettings) {
+ syncStaticSettings(settings);
+ syncSetting(settings);
+ mManagedSettings.add(new WeakReference<WebSettings>(settings));
}
}
/**
- * Load settings from the browser app's database. It is performed in
- * an AsyncTask as it involves plenty of slow disk IO.
- * NOTE: Strings used for the preferences must match those specified
- * in the various preference XML files.
- * @param ctx A Context object used to query the browser's settings
- * database. If the database exists, the saved settings will be
- * stored in this BrowserSettings object. This will update all
- * observers of this object.
+ * Syncs all the settings that have a Preference UI
*/
- public void asyncLoadFromDb(final Context ctx) {
- mLoadFromDbComplete = false;
- // Run the initial settings load in an AsyncTask as it hits the
- // disk multiple times through SharedPreferences and SQLite. We
- // need to be certain though that this has completed before we start
- // to load pages though, so in the worst case we will block waiting
- // for it to finish in BrowserActivity.onCreate().
- new LoadFromDbTask(ctx).execute();
+ private void syncSetting(WebSettings settings) {
+ settings.setGeolocationEnabled(enableGeolocation());
+ settings.setJavaScriptEnabled(enableJavascript());
+ settings.setLightTouchEnabled(enableLightTouch());
+ settings.setNavDump(enableNavDump());
+ settings.setShowVisualIndicator(enableVisualIndicator());
+ settings.setDefaultTextEncodingName(getDefaultTextEncoding());
+ settings.setDefaultZoom(getDefaultZoom());
+ settings.setMinimumFontSize(getMinimumFontSize());
+ settings.setMinimumLogicalFontSize(getMinimumFontSize());
+ settings.setForceUserScalable(forceEnableUserScalable());
+ settings.setPluginState(getPluginState());
+ settings.setTextSize(getTextSize());
+ settings.setAutoFillEnabled(isAutofillEnabled());
+ settings.setLayoutAlgorithm(getLayoutAlgorithm());
+ settings.setJavaScriptCanOpenWindowsAutomatically(blockPopupWindows());
+ settings.setLoadsImagesAutomatically(loadImages());
+ settings.setLoadWithOverviewMode(loadPageInOverviewMode());
+ settings.setSavePassword(rememberPasswords());
+ settings.setSaveFormData(saveFormdata());
+ settings.setUseWideViewPort(isWideViewport());
+ settings.setAutoFillProfile(getAutoFillProfile());
+
+ String ua = mCustomUserAgents.get(settings);
+ if (enableUseragentSwitcher() && ua != null) {
+ settings.setUserAgentString(ua);
+ } else {
+ settings.setUserAgentString(USER_AGENTS[getUserAgent()]);
+ }
}
- private class LoadFromDbTask extends AsyncTask<Void, Void, Void> {
- private Context mContext;
+ /**
+ * Syncs all the settings that have no UI
+ * These cannot change, so we only need to set them once per WebSettings
+ */
+ private void syncStaticSettings(WebSettings settings) {
+ settings.setDefaultFontSize(16);
+ settings.setDefaultFixedFontSize(13);
+ settings.setPageCacheCapacity(getPageCacheCapacity());
+
+ // WebView inside Browser doesn't want initial focus to be set.
+ settings.setNeedInitialFocus(false);
+ // Browser supports multiple windows
+ settings.setSupportMultipleWindows(true);
+ // enable smooth transition for better performance during panning or
+ // zooming
+ settings.setEnableSmoothTransition(true);
+ // disable content url access
+ settings.setAllowContentAccess(false);
- public LoadFromDbTask(Context context) {
- mContext = context;
- }
+ // HTML5 API flags
+ settings.setAppCacheEnabled(true);
+ settings.setDatabaseEnabled(true);
+ settings.setDomStorageEnabled(true);
+ settings.setWorkersEnabled(true); // This only affects V8.
- protected Void doInBackground(Void... unused) {
- SharedPreferences p =
- PreferenceManager.getDefaultSharedPreferences(mContext);
- // Set the default value for the Application Caches path.
- appCachePath = mContext.getDir("appcache", 0).getPath();
- // Determine the maximum size of the application cache.
- webStorageSizeManager = new WebStorageSizeManager(
- mContext,
- new WebStorageSizeManager.StatFsDiskInfo(appCachePath),
- new WebStorageSizeManager.WebKitAppCacheInfo(appCachePath));
- appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
- // Set the default value for the Database path.
- databasePath = mContext.getDir("databases", 0).getPath();
- // Set the default value for the Geolocation database path.
- geolocationDatabasePath = mContext.getDir("geolocation", 0).getPath();
-
- if (p.getString(PREF_HOMEPAGE, null) == null) {
- // No home page preferences is set, set it to default.
- setHomePage(mContext, getFactoryResetHomeUrl(mContext));
- }
+ // HTML5 configuration parametersettings.
+ settings.setAppCacheMaxSize(mWebStorageSizeManager.getAppCacheMaxSize());
+ settings.setAppCachePath(getAppCachePath());
+ settings.setDatabasePath(mContext.getDir("databases", 0).getPath());
+ settings.setGeolocationDatabasePath(mContext.getDir("geolocation", 0).getPath());
+ }
- // the cost of one cached page is ~3M (measured using nytimes.com). For
- // low end devices, we only cache one page. For high end devices, we try
- // to cache more pages, currently choose 5.
- ActivityManager am = (ActivityManager) mContext
- .getSystemService(Context.ACTIVITY_SERVICE);
- if (am.getMemoryClass() > 16) {
- pageCacheCapacity = 5;
- } else {
- pageCacheCapacity = 1;
+ private void syncSharedSettings() {
+ CookieManager.getInstance().setAcceptCookie(acceptCookies());
+ if (mController != null) {
+ mController.setShouldShowErrorConsole(enableJavascriptConsole());
+ }
+ }
+
+ private void syncManagedSettings() {
+ syncSharedSettings();
+ synchronized (mManagedSettings) {
+ Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator();
+ while (iter.hasNext()) {
+ WeakReference<WebSettings> ref = iter.next();
+ WebSettings settings = ref.get();
+ if (settings == null) {
+ iter.remove();
+ continue;
+ }
+ syncSetting(settings);
}
+ }
+ }
- // Read the last active AutoFill profile id.
- autoFillActiveProfileId = p.getInt(
- PREF_AUTOFILL_ACTIVE_PROFILE_ID, autoFillActiveProfileId);
-
- // Load the autofill profile data from the database. We use a database separate
- // to the browser preference DB to make it easier to support multiple profiles
- // and switching between them.
- AutoFillProfileDatabase autoFillDb = AutoFillProfileDatabase.getInstance(mContext);
- Cursor c = autoFillDb.getProfile(autoFillActiveProfileId);
-
- if (c.getCount() > 0) {
- c.moveToFirst();
-
- String fullName = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.FULL_NAME));
- String email = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.EMAIL_ADDRESS));
- String company = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.COMPANY_NAME));
- String addressLine1 = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.ADDRESS_LINE_1));
- String addressLine2 = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.ADDRESS_LINE_2));
- String city = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.CITY));
- String state = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.STATE));
- String zip = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.ZIP_CODE));
- String country = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.COUNTRY));
- String phone = c.getString(c.getColumnIndex(
- AutoFillProfileDatabase.Profiles.PHONE_NUMBER));
- autoFillProfile = new AutoFillProfile(autoFillActiveProfileId,
- fullName, email, company, addressLine1, addressLine2, city,
- state, zip, country, phone);
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ syncManagedSettings();
+ if (PREF_SEARCH_ENGINE.equals(key)) {
+ updateSearchEngine(false);
+ }
+ if (PREF_USE_INSTANT_SEARCH.equals(key)) {
+ updateSearchEngine(true);
+ }
+ if (PREF_FULLSCREEN.equals(key)) {
+ if (mController.getUi() != null) {
+ mController.getUi().setFullscreen(useFullscreen());
}
- c.close();
- autoFillDb.close();
+ }
+ }
- // PreferenceManager.setDefaultValues is TOO SLOW, need to manually keep
- // the defaults in sync
- p.registerOnSharedPreferenceChangeListener(BrowserSettings.this);
- syncSharedPreferences(mContext, p);
+ static String getFactoryResetHomeUrl(Context context) {
+ String url = context.getResources().getString(R.string.homepage_base);
+ if (url.indexOf("{CID}") != -1) {
+ url = url.replace("{CID}",
+ BrowserProvider.getClientId(context.getContentResolver()));
+ }
+ return url;
+ }
- synchronized (sSingleton) {
- mLoadFromDbComplete = true;
- sSingleton.notify();
+ public LayoutAlgorithm getLayoutAlgorithm() {
+ LayoutAlgorithm layoutAlgorithm = LayoutAlgorithm.NORMAL;
+ if (autofitPages()) {
+ layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
+ }
+ if (isDebugEnabled()) {
+ if (isSmallScreen()) {
+ layoutAlgorithm = LayoutAlgorithm.SINGLE_COLUMN;
+ } else {
+ if (isNormalLayout()) {
+ layoutAlgorithm = LayoutAlgorithm.NORMAL;
+ } else {
+ layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
+ }
}
- return null;
}
+ return layoutAlgorithm;
}
- private void updateSearchEngine(Context ctx, String searchEngineName, boolean force) {
- if (force || searchEngine == null ||
- !searchEngine.getName().equals(searchEngineName)) {
- if (searchEngine != null) {
- if (searchEngine.supportsVoiceSearch()) {
+ // TODO: Cache
+ public int getPageCacheCapacity() {
+ // the cost of one cached page is ~3M (measured using nytimes.com). For
+ // low end devices, we only cache one page. For high end devices, we try
+ // to cache more pages, currently choose 5.
+ if (ActivityManager.staticGetMemoryClass() > 16) {
+ return 5;
+ } else {
+ return 1;
+ }
+ }
+
+ public WebStorageSizeManager getWebStorageSizeManager() {
+ return mWebStorageSizeManager;
+ }
+
+ // TODO: Cache
+ private String getAppCachePath() {
+ return mContext.getDir("appcache", 0).getPath();
+ }
+
+ private void updateSearchEngine(boolean force) {
+ String searchEngineName = getSearchEngineName();
+ if (force || mSearchEngine == null ||
+ !mSearchEngine.getName().equals(searchEngineName)) {
+ if (mSearchEngine != null) {
+ if (mSearchEngine.supportsVoiceSearch()) {
// One or more tabs could have been in voice search mode.
// Clear it, since the new SearchEngine may not support
// it, or may handle it differently.
@@ -428,585 +306,329 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha
mController.getTabControl().getTab(i).revertVoiceSearchMode();
}
}
- searchEngine.close();
+ mSearchEngine.close();
}
- searchEngine = SearchEngines.get(ctx, searchEngineName);
+ mSearchEngine = SearchEngines.get(mContext, searchEngineName);
- if (mController != null && (searchEngine instanceof InstantSearchEngine)) {
- ((InstantSearchEngine) searchEngine).setController(mController);
+ if (mController != null && (mSearchEngine instanceof InstantSearchEngine)) {
+ ((InstantSearchEngine) mSearchEngine).setController(mController);
}
}
}
- /* package */ void syncSharedPreferences(Context ctx, SharedPreferences p) {
-
- homeUrl =
- p.getString(PREF_HOMEPAGE, homeUrl);
-
- useInstant = p.getBoolean(PREF_USE_INSTANT, useInstant);
- String searchEngineName = p.getString(PREF_SEARCH_ENGINE,
- SearchEngine.GOOGLE);
- updateSearchEngine(ctx, searchEngineName, false);
-
- loadsImagesAutomatically = p.getBoolean("load_images",
- loadsImagesAutomatically);
- javaScriptEnabled = p.getBoolean("enable_javascript",
- javaScriptEnabled);
- pluginState = WebSettings.PluginState.valueOf(
- p.getString(PREF_PLUGIN_STATE, pluginState.name()));
- javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
- "block_popup_windows",
- !javaScriptCanOpenWindowsAutomatically);
- showSecurityWarnings = p.getBoolean("show_security_warnings",
- showSecurityWarnings);
- rememberPasswords = p.getBoolean("remember_passwords",
- rememberPasswords);
- saveFormData = p.getBoolean("save_formdata",
- saveFormData);
- autoFillEnabled = p.getBoolean("autofill_enabled", autoFillEnabled);
- boolean accept_cookies = p.getBoolean("accept_cookies",
- CookieManager.getInstance().acceptCookie());
- CookieManager.getInstance().setAcceptCookie(accept_cookies);
- openInBackground = p.getBoolean("open_in_background", openInBackground);
- textSize = WebSettings.TextSize.valueOf(
- p.getString(PREF_TEXT_SIZE, textSize.name()));
- zoomDensity = WebSettings.ZoomDensity.valueOf(
- p.getString(PREF_DEFAULT_ZOOM, zoomDensity.name()));
- autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
- loadsPageInOverviewMode = p.getBoolean("load_page",
- loadsPageInOverviewMode);
- useWideViewPort = true; // use wide view port for either setting
- if (autoFitPage) {
- layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
- } else {
- layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
- }
- defaultTextEncodingName =
- p.getString(PREF_DEFAULT_TEXT_ENCODING,
- defaultTextEncodingName);
-
- showDebugSettings =
- p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
- // Debug menu items have precidence if the menu is visible
- if (showDebugSettings) {
- boolean small_screen = p.getBoolean("small_screen",
- layoutAlgorithm ==
- WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
- if (small_screen) {
- layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
- } else {
- boolean normal_layout = p.getBoolean("normal_layout",
- layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
- if (normal_layout) {
- layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
- } else {
- layoutAlgorithm =
- WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
- }
- }
- useWideViewPort = p.getBoolean("wide_viewport", useWideViewPort);
- tracing = p.getBoolean("enable_tracing", tracing);
- lightTouch = p.getBoolean("enable_light_touch", lightTouch);
- navDump = p.getBoolean("enable_nav_dump", navDump);
- showVisualIndicator = p.getBoolean(PREF_VISUAL_INDICATOR, showVisualIndicator);
- }
-
- quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
- useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
-
- // Only set these if this is a dev build or debug is enabled
- if (DEV_BUILD || showDebugSettings()) {
- userAgent = Integer.parseInt(p.getString(PREF_USER_AGENT, "0"));
- hardwareAccelerated = p.getBoolean(PREF_HARDWARE_ACCEL, hardwareAccelerated);
+ public SearchEngine getSearchEngine() {
+ if (mSearchEngine == null) {
+ updateSearchEngine(false);
}
+ return mSearchEngine;
+ }
- // JS flags is loaded from DB even if showDebugSettings is false,
- // so that it can be set once and be effective all the time.
- jsFlags = p.getString("js_engine_flags", "");
-
- // Read the setting for showing/hiding the JS Console always so that should the
- // user enable debug settings, we already know if we should show the console.
- // The user will never see the console unless they navigate to about:debug,
- // regardless of the setting we read here. This setting is only used after debug
- // is enabled.
- showConsole = p.getBoolean("javascript_console", showConsole);
-
- // HTML5 API flags
- appCacheEnabled = p.getBoolean("enable_appcache", appCacheEnabled);
- databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
- domStorageEnabled = p.getBoolean("enable_domstorage", domStorageEnabled);
- geolocationEnabled = p.getBoolean("enable_geolocation", geolocationEnabled);
- workersEnabled = p.getBoolean("enable_workers", workersEnabled);
+ public boolean isDebugEnabled() {
+ return mPrefs.getBoolean(PREF_DEBUG_MENU, false);
+ }
- update();
+ public void setDebugEnabled(boolean value) {
+ mPrefs.edit().putBoolean(PREF_DEBUG_MENU, value).apply();
}
- public String getHomePage() {
- if (useMostVisitedHomepage) {
- return HomeProvider.MOST_VISITED;
+ public void clearCache() {
+ WebIconDatabase.getInstance().removeAllIcons();
+ if (mController != null) {
+ WebView current = mController.getCurrentWebView();
+ if (current != null) {
+ current.clearCache(true);
+ }
}
- return homeUrl;
}
- public SearchEngine getSearchEngine() {
- return searchEngine;
+ public void clearCookies() {
+ CookieManager.getInstance().removeAllCookie();
}
- public String getJsFlags() {
- return jsFlags;
+ public void clearHistory() {
+ ContentResolver resolver = mContext.getContentResolver();
+ Browser.clearHistory(resolver);
+ Browser.clearSearches(resolver);
}
- public WebStorageSizeManager getWebStorageSizeManager() {
- return webStorageSizeManager;
+ public void clearFormData() {
+ WebViewDatabase.getInstance(mContext).clearFormData();
+ if (mController!= null) {
+ WebView currentTopView = mController.getCurrentTopWebView();
+ if (currentTopView != null) {
+ currentTopView.clearFormData();
+ }
+ }
}
- public void setHomePage(Context context, String url) {
- Editor ed = PreferenceManager.
- getDefaultSharedPreferences(context).edit();
- ed.putString(PREF_HOMEPAGE, url);
- ed.apply();
- homeUrl = url;
+ public void clearPasswords() {
+ WebViewDatabase db = WebViewDatabase.getInstance(mContext);
+ db.clearUsernamePassword();
+ db.clearHttpAuthUsernamePassword();
}
- public WebSettings.TextSize getTextSize() {
- return textSize;
+ public void clearDatabases() {
+ WebStorage.getInstance().deleteAllData();
}
- public WebSettings.ZoomDensity getDefaultZoom() {
- return zoomDensity;
+ public void clearLocationAccess() {
+ GeolocationPermissions.getInstance().clearAll();
}
- public boolean openInBackground() {
- return openInBackground;
+ public void resetDefaultPreferences() {
+ mPrefs.edit().clear().apply();
+ syncManagedSettings();
}
- public boolean showSecurityWarnings() {
- return showSecurityWarnings;
+ public AutoFillProfile getAutoFillProfile() {
+ mAutofillHandler.waitForLoad();
+ return mAutofillHandler.getAutoFillProfile();
}
- public boolean isTracing() {
- return tracing;
+ public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
+ mAutofillHandler.waitForLoad();
+ mAutofillHandler.setAutoFillProfile(profile, msg);
}
- public boolean isLightTouch() {
- return lightTouch;
+ public void toggleDebugSettings() {
+ setDebugEnabled(!isDebugEnabled());
}
- public boolean isNavDump() {
- return navDump;
+ public boolean hasDesktopUseragent(WebView view) {
+ return view != null && mCustomUserAgents.get(view.getSettings()) != null;
}
- public boolean isHardwareAccelerated() {
- return hardwareAccelerated;
+ public void toggleDesktopUseragent(WebView view) {
+ WebSettings settings = view.getSettings();
+ if (mCustomUserAgents.get(settings) != null) {
+ mCustomUserAgents.remove(settings);
+ settings.setUserAgentString(USER_AGENTS[getUserAgent()]);
+ } else {
+ mCustomUserAgents.put(settings, DESKTOP_USERAGENT);
+ settings.setUserAgentString(DESKTOP_USERAGENT);
+ }
}
- public boolean showVisualIndicator() {
- return showVisualIndicator;
+ // -----------------------------
+ // getter/setters for accessibility_preferences.xml
+ // -----------------------------
+
+ // TODO: Cache
+ public TextSize getTextSize() {
+ String textSize = mPrefs.getString(PREF_TEXT_SIZE, "NORMAL");
+ return TextSize.valueOf(textSize);
}
- public boolean useQuickControls() {
- return quickControls;
+ public int getMinimumFontSize() {
+ return mPrefs.getInt(PREF_MIN_FONT_SIZE, 1);
}
- public boolean useMostVisitedHomepage() {
- return useMostVisitedHomepage;
+ public boolean forceEnableUserScalable() {
+ return mPrefs.getBoolean(PREF_FORCE_USERSCALABLE, false);
}
- public boolean useInstant() {
- return useInstant;
+ // -----------------------------
+ // getter/setters for advanced_preferences.xml
+ // -----------------------------
+
+ public String getSearchEngineName() {
+ return mPrefs.getString(PREF_SEARCH_ENGINE, SearchEngine.GOOGLE);
}
- public boolean showDebugSettings() {
- return showDebugSettings;
+ public boolean openInBackground() {
+ return mPrefs.getBoolean(PREF_OPEN_IN_BACKGROUND, false);
}
- public void toggleDebugSettings(Context context) {
- showDebugSettings = !showDebugSettings;
- navDump = showDebugSettings;
- syncSharedPreferences(context,
- PreferenceManager.getDefaultSharedPreferences(context));
- update();
+ public boolean enableJavascript() {
+ return mPrefs.getBoolean(PREF_ENABLE_JAVASCRIPT, true);
}
- public void setAutoFillProfile(Context ctx, AutoFillProfile profile, Message msg) {
- if (profile != null) {
- setActiveAutoFillProfileId(ctx, profile.getUniqueId());
- // Update the AutoFill DB with the new profile.
- new SaveProfileToDbTask(ctx, msg).execute(profile);
- } else {
- // Delete the current profile.
- if (autoFillProfile != null) {
- new DeleteProfileFromDbTask(ctx, msg).execute(autoFillProfile.getUniqueId());
- setActiveAutoFillProfileId(ctx, NO_AUTOFILL_PROFILE_SET);
- }
- }
- autoFillProfile = profile;
+ // TODO: Cache
+ public PluginState getPluginState() {
+ String state = mPrefs.getString(PREF_PLUGIN_STATE, "ON");
+ return PluginState.valueOf(state);
}
- public AutoFillProfile getAutoFillProfile() {
- return autoFillProfile;
+ // TODO: Cache
+ public ZoomDensity getDefaultZoom() {
+ String zoom = mPrefs.getString(PREF_DEFAULT_ZOOM, "MEDIUM");
+ return ZoomDensity.valueOf(zoom);
}
- private void setActiveAutoFillProfileId(Context context, int activeProfileId) {
- autoFillActiveProfileId = activeProfileId;
- Editor ed = PreferenceManager.
- getDefaultSharedPreferences(context).edit();
- ed.putInt(PREF_AUTOFILL_ACTIVE_PROFILE_ID, activeProfileId);
- ed.apply();
+ public boolean loadPageInOverviewMode() {
+ return mPrefs.getBoolean(PREF_LOAD_PAGE, true);
}
- /* package */ void disableAutoFill(Context ctx) {
- autoFillEnabled = false;
- Editor ed = PreferenceManager.getDefaultSharedPreferences(ctx).edit();
- ed.putBoolean(PREF_AUTOFILL_ENABLED, false);
- ed.apply();
+ public boolean autofitPages() {
+ return mPrefs.getBoolean(PREF_AUTOFIT_PAGES, true);
}
- /**
- * Add a WebSettings object to the list of observers that will be updated
- * when update() is called.
- *
- * @param s A WebSettings object that is strictly tied to the life of a
- * WebView.
- */
- public Observer addObserver(WebSettings s) {
- Observer old = mWebSettingsToObservers.get(s);
- if (old != null) {
- super.deleteObserver(old);
- }
- Observer o = new Observer(s);
- mWebSettingsToObservers.put(s, o);
- super.addObserver(o);
- return o;
+ public boolean blockPopupWindows() {
+ return mPrefs.getBoolean(PREF_BLOCK_POPUP_WINDOWS, true);
}
- /**
- * Delete the given WebSettings observer from the list of observers.
- * @param s The WebSettings object to be deleted.
- */
- public void deleteObserver(WebSettings s) {
- Observer o = mWebSettingsToObservers.get(s);
- if (o != null) {
- mWebSettingsToObservers.remove(s);
- super.deleteObserver(o);
- }
+ public boolean loadImages() {
+ return mPrefs.getBoolean(PREF_LOAD_IMAGES, true);
}
- /*
- * Application level method for obtaining a single app instance of the
- * BrowserSettings.
- */
- public static BrowserSettings getInstance() {
- if (sSingleton == null ) {
- sSingleton = new BrowserSettings();
- }
- return sSingleton;
+ public String getDefaultTextEncoding() {
+ return mPrefs.getString(PREF_DEFAULT_TEXT_ENCODING, null);
}
- /*
- * Package level method for associating the BrowserSettings with TabControl
- */
- /* package */void setController(Controller ctrl) {
- mController = ctrl;
- updateTabControlSettings();
+ // -----------------------------
+ // getter/setters for general_preferences.xml
+ // -----------------------------
- if (mController != null && (searchEngine instanceof InstantSearchEngine)) {
- ((InstantSearchEngine) searchEngine).setController(mController);
+ public String getHomePage() {
+ if (useMostVisitedHomepage()) {
+ return HomeProvider.MOST_VISITED;
}
+ return mPrefs.getString(PREF_HOMEPAGE, getFactoryResetHomeUrl(mContext));
}
- /*
- * Update all the observers of the object.
- */
- /*package*/ void update() {
- setChanged();
- notifyObservers();
+ public void setHomePage(String value) {
+ mPrefs.edit().putString(PREF_HOMEPAGE, value).apply();
}
- /*package*/ void clearCache(Context context) {
- WebIconDatabase.getInstance().removeAllIcons();
- if (mController != null) {
- WebView current = mController.getCurrentWebView();
- if (current != null) {
- current.clearCache(true);
- }
- }
+ public boolean isAutofillEnabled() {
+ return mPrefs.getBoolean(PREF_AUTOFILL_ENABLED, true);
}
- /*package*/ void clearCookies(Context context) {
- CookieManager.getInstance().removeAllCookie();
+ public void setAutofillEnabled(boolean value) {
+ mPrefs.edit().putBoolean(PREF_AUTOFILL_ENABLED, value).apply();
}
- /* package */void clearHistory(Context context) {
- ContentResolver resolver = context.getContentResolver();
- Browser.clearHistory(resolver);
- Browser.clearSearches(resolver);
- }
+ // -----------------------------
+ // getter/setters for debug_preferences.xml
+ // -----------------------------
- /* package */ void clearFormData(Context context) {
- WebViewDatabase.getInstance(context).clearFormData();
- if (mController!= null) {
- WebView currentTopView = mController.getCurrentTopWebView();
- if (currentTopView != null) {
- currentTopView.clearFormData();
- }
+ public boolean isHardwareAccelerated() {
+ if (!isDebugEnabled()) {
+ return true;
}
+ return mPrefs.getBoolean(PREF_ENABLE_HARDWARE_ACCEL, true);
}
- /*package*/ void clearPasswords(Context context) {
- WebViewDatabase db = WebViewDatabase.getInstance(context);
- db.clearUsernamePassword();
- db.clearHttpAuthUsernamePassword();
+ public int getUserAgent() {
+ if (!isDebugEnabled()) {
+ return 0;
+ }
+ return Integer.parseInt(mPrefs.getString(PREF_USER_AGENT, "0"));
}
- private void updateTabControlSettings() {
- // Enable/disable the error console.
- mController.setShouldShowErrorConsole(
- showDebugSettings && showConsole);
- }
+ // -----------------------------
+ // getter/setters for hidden_debug_preferences.xml
+ // -----------------------------
- /*package*/ void clearDatabases(Context context) {
- WebStorage.getInstance().deleteAllData();
+ public boolean enableVisualIndicator() {
+ if (!isDebugEnabled()) {
+ return false;
+ }
+ return mPrefs.getBoolean(PREF_ENABLE_VISUAL_INDICATOR, false);
}
- /*package*/ void clearLocationAccess(Context context) {
- GeolocationPermissions.getInstance().clearAll();
+ public boolean enableJavascriptConsole() {
+ if (!isDebugEnabled()) {
+ return false;
+ }
+ return mPrefs.getBoolean(PREF_JAVASCRIPT_CONSOLE, true);
}
- /*package*/ void resetDefaultPreferences(Context ctx) {
- reset();
- SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(ctx);
- p.edit().clear().apply();
- PreferenceManager.setDefaultValues(ctx, R.xml.general_preferences, true);
- PreferenceManager.setDefaultValues(ctx, R.xml.privacy_security_preferences, true);
- PreferenceManager.setDefaultValues(ctx, R.xml.advanced_preferences, true);
- // reset homeUrl
- setHomePage(ctx, getFactoryResetHomeUrl(ctx));
- // reset appcache max size
- appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
- setActiveAutoFillProfileId(ctx, NO_AUTOFILL_PROFILE_SET);
+ public boolean isSmallScreen() {
+ if (!isDebugEnabled()) {
+ return false;
+ }
+ return mPrefs.getBoolean(PREF_SMALL_SCREEN, false);
}
- /*package*/ static String getFactoryResetHomeUrl(Context context) {
- String url = context.getResources().getString(R.string.homepage_base);
- if (url.indexOf("{CID}") != -1) {
- url = url.replace("{CID}",
- BrowserProvider.getClientId(context.getContentResolver()));
+ public boolean isWideViewport() {
+ if (!isDebugEnabled()) {
+ return true;
}
- return url;
+ return mPrefs.getBoolean(PREF_WIDE_VIEWPORT, true);
}
- // Private constructor that does nothing.
- private BrowserSettings() {
- reset();
- }
-
- private void reset() {
- // Private variables for settings
- // NOTE: these defaults need to be kept in sync with the XML
- // until the performance of PreferenceManager.setDefaultValues()
- // is improved.
- loadsImagesAutomatically = true;
- javaScriptEnabled = true;
- pluginState = WebSettings.PluginState.ON;
- javaScriptCanOpenWindowsAutomatically = false;
- showSecurityWarnings = true;
- rememberPasswords = true;
- saveFormData = true;
- autoFillEnabled = true;
- openInBackground = false;
- autoFitPage = true;
- loadsPageInOverviewMode = true;
- showDebugSettings = false;
- // HTML5 API flags
- appCacheEnabled = true;
- databaseEnabled = true;
- domStorageEnabled = true;
- geolocationEnabled = true;
- workersEnabled = true; // only affects V8. JSC does not have a similar setting
+ public boolean isNormalLayout() {
+ if (!isDebugEnabled()) {
+ return false;
+ }
+ return mPrefs.getBoolean(PREF_NORMAL_LAYOUT, false);
}
- private abstract class AutoFillProfileDbTask<T> extends AsyncTask<T, Void, Void> {
- Context mContext;
- AutoFillProfileDatabase mAutoFillProfileDb;
- Message mCompleteMessage;
-
- public AutoFillProfileDbTask(Context ctx, Message msg) {
- mContext = ctx;
- mCompleteMessage = msg;
+ public boolean isTracing() {
+ if (!isDebugEnabled()) {
+ return false;
}
+ return mPrefs.getBoolean(PREF_ENABLE_TRACING, false);
+ }
- protected void onPostExecute(Void result) {
- if (mCompleteMessage != null) {
- mCompleteMessage.sendToTarget();
- }
- mAutoFillProfileDb.close();
+ public boolean enableLightTouch() {
+ if (!isDebugEnabled()) {
+ return false;
}
-
- abstract protected Void doInBackground(T... values);
+ return mPrefs.getBoolean(PREF_ENABLE_LIGHT_TOUCH, false);
}
-
- private class SaveProfileToDbTask extends AutoFillProfileDbTask<AutoFillProfile> {
- public SaveProfileToDbTask(Context ctx, Message msg) {
- super(ctx, msg);
+ public boolean enableNavDump() {
+ if (!isDebugEnabled()) {
+ return false;
}
+ return mPrefs.getBoolean(PREF_ENABLE_NAV_DUMP, false);
+ }
- protected Void doInBackground(AutoFillProfile... values) {
- mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
- assert autoFillActiveProfileId != NO_AUTOFILL_PROFILE_SET;
- AutoFillProfile newProfile = values[0];
- mAutoFillProfileDb.addOrUpdateProfile(autoFillActiveProfileId, newProfile);
- return null;
+ public String getJsEngineFlags() {
+ if (!isDebugEnabled()) {
+ return "";
}
+ return mPrefs.getString(PREF_JS_ENGINE_FLAGS, "");
}
- private class DeleteProfileFromDbTask extends AutoFillProfileDbTask<Integer> {
- public DeleteProfileFromDbTask(Context ctx, Message msg) {
- super(ctx, msg);
- }
+ // -----------------------------
+ // getter/setters for lab_preferences.xml
+ // -----------------------------
- protected Void doInBackground(Integer... values) {
- mAutoFillProfileDb = AutoFillProfileDatabase.getInstance(mContext);
- int id = values[0];
- assert id > 0;
- mAutoFillProfileDb.dropProfile(id);
- return null;
- }
+ public boolean useQuickControls() {
+ return mPrefs.getBoolean(PREF_ENABLE_QUICK_CONTROLS, false);
}
- @Override
- public void onSharedPreferenceChanged(
- SharedPreferences p, String key) {
- if (PREF_HARDWARE_ACCEL.equals(key)) {
- hardwareAccelerated = p.getBoolean(PREF_HARDWARE_ACCEL, hardwareAccelerated);
- } else if (PREF_VISUAL_INDICATOR.equals(key)) {
- showVisualIndicator = p.getBoolean(PREF_VISUAL_INDICATOR, showVisualIndicator);
- } else if (PREF_USER_AGENT.equals(key)) {
- userAgent = Integer.parseInt(p.getString(PREF_USER_AGENT, "0"));
- update();
- } else if (PREF_QUICK_CONTROLS.equals(key)) {
- quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
- } else if (PREF_MOST_VISITED_HOMEPAGE.equals(key)) {
- useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
- } else if (PREF_USE_INSTANT.equals(key)) {
- useInstant = p.getBoolean(PREF_USE_INSTANT, useInstant);
- updateSearchEngine(mController.getActivity(), SearchEngine.GOOGLE, true);
- } else if (PREF_SEARCH_ENGINE.equals(key)) {
- final String searchEngineName = p.getString(PREF_SEARCH_ENGINE,
- SearchEngine.GOOGLE);
- updateSearchEngine(mController.getActivity(), searchEngineName, false);
- }
+ public boolean useMostVisitedHomepage() {
+ return mPrefs.getBoolean(PREF_USE_MOST_VISITED_HOMEPAGE, false);
}
- /*package*/ String getRlzValue() {
- return mRlzValue;
+ public boolean useInstantSearch() {
+ return mPrefs.getBoolean(PREF_USE_INSTANT_SEARCH, false);
}
- /*package*/ void updateRlzValues(Context context) {
- // Use AsyncTask because this queries both RlzProvider and Bookmarks URIs
- new RlzUpdateTask(context).execute();
+ public boolean useFullscreen() {
+ return mPrefs.getBoolean(PREF_FULLSCREEN, false);
}
- private class RlzUpdateTask extends AsyncTask<Void, Void, Void> {
- private final Context context;
+ public boolean enableUseragentSwitcher() {
+ return mPrefs.getBoolean(PREF_ENABLE_USERAGENT_SWITCHER, false);
+ }
- public RlzUpdateTask(Context context) {
- this.context = context;
- }
+ // -----------------------------
+ // getter/setters for privacy_security_preferences.xml
+ // -----------------------------
- @Override
- protected Void doInBackground(Void...unused) {
- String rlz = retrieveRlzValue(context);
- if (!rlz.isEmpty()) {
- mRlzValue = rlz;
- updateHomePageRlzParameter(context);
- updateBookmarksRlzParameter(context);
- }
- return null;
- }
+ public boolean showSecurityWarnings() {
+ return mPrefs.getBoolean(PREF_SHOW_SECURITY_WARNINGS, true);
}
- // Update RLZ value if present in Home page
- private void updateHomePageRlzParameter(Context context) {
- Uri uri = Uri.parse(homeUrl);
- if ((uri.getQueryParameter("rlz") != null) && UrlUtils.isGoogleUri(uri)) {
- String newHomeUrl = updateRlzParameter(homeUrl);
- if (!homeUrl.equals(newHomeUrl)) {
- setHomePage(context, newHomeUrl);
- }
- }
+ public boolean acceptCookies() {
+ return mPrefs.getBoolean(PREF_ACCEPT_COOKIES, true);
}
- // Update RLZ value if present in bookmarks
- private void updateBookmarksRlzParameter(Context context) {
- Cursor cur = null;
- try {
- cur = context.getContentResolver().query(Bookmarks.CONTENT_URI_DEFAULT_FOLDER,
- new String[] { Bookmarks._ID, Bookmarks.URL }, "url LIKE '%rlz=%'", null, null);
- if ((cur == null) || (cur.getCount() == 0)) {
- return;
- }
- for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
- long id = cur.getLong(0);
- String url = cur.getString(1);
- if ((url == null) || url.isEmpty()) {
- continue;
- }
-
- Uri uri = Uri.parse(url);
- if ((uri.getQueryParameter("rlz") != null) && UrlUtils.isGoogleUri(uri)) {
- String newUrl = updateRlzParameter(url);
- if (!url.equals(newUrl)) {
- ContentValues values = new ContentValues();
- values.put(Bookmarks.URL, newUrl);
- Uri bookmarkUri = ContentUris.withAppendedId(
- BookmarkUtils.getBookmarksUri(context), id);
- context.getContentResolver().update(bookmarkUri, values, null, null);
- }
- }
- }
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
+ public boolean saveFormdata() {
+ return mPrefs.getBoolean(PREF_SAVE_FORMDATA, true);
}
- private String updateRlzParameter(String url) {
- Uri uri = Uri.parse(url);
- String oldRlz = uri.getQueryParameter("rlz");
- if (oldRlz != null) {
- return url.replace("rlz=" + oldRlz, "rlz=" + mRlzValue);
- }
- return url;
+ public boolean enableGeolocation() {
+ return mPrefs.getBoolean(PREF_ENABLE_GEOLOCATION, true);
}
- // Retrieve the RLZ value from the Rlz Provider
- private static String retrieveRlzValue(Context context) {
- String rlz = "";
- PackageManager pm = context.getPackageManager();
- if (pm.resolveContentProvider(RLZ_PROVIDER, 0) == null) {
- return rlz;
- }
-
- String ap = context.getResources().getString(R.string.rlz_access_point);
- if (ap.isEmpty()) {
- return rlz;
- }
-
- Uri rlzUri = Uri.withAppendedPath(RLZ_PROVIDER_URI, ap);
- Cursor cur = null;
- try {
- cur = context.getContentResolver().query(rlzUri, null, null, null, null);
- if (cur != null && cur.moveToFirst() && !cur.isNull(0)) {
- rlz = cur.getString(0);
- }
- } finally {
- if (cur != null) {
- cur.close();
- }
- }
- return rlz;
+ public boolean rememberPasswords() {
+ return mPrefs.getBoolean(PREF_REMEMBER_PASSWORDS, true);
}
+
}
diff --git a/src/com/android/browser/ScrollWebView.java b/src/com/android/browser/BrowserWebView.java
index 8c89e51..a1d8c2d 100644
--- a/src/com/android/browser/ScrollWebView.java
+++ b/src/com/android/browser/BrowserWebView.java
@@ -18,6 +18,7 @@ package com.android.browser;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -28,14 +29,15 @@ import java.util.Map;
/**
* Manage WebView scroll events
*/
-public class ScrollWebView extends WebView implements Runnable {
+public class BrowserWebView extends WebView implements Runnable {
private ScrollListener mScrollListener;
private boolean mIsCancelled;
private boolean mBackgroundRemoved = false;
private boolean mUserInitiated = false;
private TitleBarBase mTitleBar;
- private Bitmap mBitmap;
+ private int mCaptureSize;
+ private Bitmap mCapture;
/**
* @param context
@@ -43,7 +45,7 @@ public class ScrollWebView extends WebView implements Runnable {
* @param defStyle
* @param javascriptInterfaces
*/
- public ScrollWebView(Context context, AttributeSet attrs, int defStyle,
+ public BrowserWebView(Context context, AttributeSet attrs, int defStyle,
Map<String, Object> javascriptInterfaces, boolean privateBrowsing) {
super(context, attrs, defStyle, javascriptInterfaces, privateBrowsing);
}
@@ -53,24 +55,33 @@ public class ScrollWebView extends WebView implements Runnable {
* @param attrs
* @param defStyle
*/
- public ScrollWebView(
+ public BrowserWebView(
Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
super(context, attrs, defStyle, privateBrowsing);
+ init();
}
/**
* @param context
* @param attrs
*/
- public ScrollWebView(Context context, AttributeSet attrs) {
+ public BrowserWebView(Context context, AttributeSet attrs) {
super(context, attrs);
+ init();
}
/**
* @param context
*/
- public ScrollWebView(Context context) {
+ public BrowserWebView(Context context) {
super(context);
+ init();
+ }
+
+ private void init() {
+ mCaptureSize = mContext.getResources().getDimensionPixelSize(R.dimen.tab_capture_size);
+ mCapture = Bitmap.createBitmap(mCaptureSize, mCaptureSize,
+ Bitmap.Config.RGB_565);
}
@Override
@@ -140,6 +151,18 @@ public class ScrollWebView extends WebView implements Runnable {
public void onScroll(int visibleTitleHeight, boolean userInitiated);
}
+ protected Bitmap capture() {
+ if (mCapture == null) return null;
+ Canvas c = new Canvas(mCapture);
+ final int left = getScrollX();
+ final int top = getScrollY() + getVisibleTitleHeight();
+ c.translate(-left, -top);
+ float scale = mCaptureSize / (float) Math.max(getWidth(), getHeight());
+ c.scale(scale, scale, left, top);
+ onDraw(c);
+ return mCapture;
+ }
+
@Override
protected void onDraw(android.graphics.Canvas c) {
super.onDraw(c);
diff --git a/src/com/android/browser/BrowserYesNoPreference.java b/src/com/android/browser/BrowserYesNoPreference.java
index caea092..d5d5205 100644
--- a/src/com/android/browser/BrowserYesNoPreference.java
+++ b/src/com/android/browser/BrowserYesNoPreference.java
@@ -35,25 +35,25 @@ class BrowserYesNoPreference extends YesNoPreference {
if (positiveResult) {
setEnabled(false);
- Context context = getContext();
- if (BrowserSettings.PREF_CLEAR_CACHE.equals(getKey())) {
- BrowserSettings.getInstance().clearCache(context);
- BrowserSettings.getInstance().clearDatabases(context);
- } else if (BrowserSettings.PREF_CLEAR_COOKIES.equals(getKey())) {
- BrowserSettings.getInstance().clearCookies(context);
- } else if (BrowserSettings.PREF_CLEAR_HISTORY.equals(getKey())) {
- BrowserSettings.getInstance().clearHistory(context);
- } else if (BrowserSettings.PREF_CLEAR_FORM_DATA.equals(getKey())) {
- BrowserSettings.getInstance().clearFormData(context);
- } else if (BrowserSettings.PREF_CLEAR_PASSWORDS.equals(getKey())) {
- BrowserSettings.getInstance().clearPasswords(context);
- } else if (BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS.equals(
+ BrowserSettings settings = BrowserSettings.getInstance();
+ if (PreferenceKeys.PREF_PRIVACY_CLEAR_CACHE.equals(getKey())) {
+ settings.clearCache();
+ settings.clearDatabases();
+ } else if (PreferenceKeys.PREF_PRIVACY_CLEAR_COOKIES.equals(getKey())) {
+ settings.clearCookies();
+ } else if (PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY.equals(getKey())) {
+ settings.clearHistory();
+ } else if (PreferenceKeys.PREF_PRIVACY_CLEAR_FORM_DATA.equals(getKey())) {
+ settings.clearFormData();
+ } else if (PreferenceKeys.PREF_PRIVACY_CLEAR_PASSWORDS.equals(getKey())) {
+ settings.clearPasswords();
+ } else if (PreferenceKeys.PREF_RESET_DEFAULT_PREFERENCES.equals(
getKey())) {
- BrowserSettings.getInstance().resetDefaultPreferences(context);
+ settings.resetDefaultPreferences();
setEnabled(true);
- } else if (BrowserSettings.PREF_CLEAR_GEOLOCATION_ACCESS.equals(
+ } else if (PreferenceKeys.PREF_PRIVACY_CLEAR_GEOLOCATION_ACCESS.equals(
getKey())) {
- BrowserSettings.getInstance().clearLocationAccess(context);
+ settings.clearLocationAccess();
}
}
}
diff --git a/src/com/android/browser/CombinedBookmarkHistoryView.java b/src/com/android/browser/CombinedBookmarkHistoryView.java
index febf75b..1fdc260 100644
--- a/src/com/android/browser/CombinedBookmarkHistoryView.java
+++ b/src/com/android/browser/CombinedBookmarkHistoryView.java
@@ -204,27 +204,11 @@ public class CombinedBookmarkHistoryView extends LinearLayout
mUiController.onUrlSelected(BrowserBookmarksPage.getUrl(c), false);
return true;
}
-
- @Override
- public void onFolderChanged(int level, Uri uri) {
- final int toggleFlags = ActionBar.DISPLAY_SHOW_CUSTOM
- | ActionBar.DISPLAY_HOME_AS_UP;
- // 1 is "bookmarks" root folder
- if (level <= 1) {
- mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- mActionBar.setDisplayOptions(0, toggleFlags);
- } else {
- mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- mActionBar.setDisplayOptions(toggleFlags, toggleFlags);
- }
- }
};
private void initFragments(Bundle extras) {
mBookmarks = BrowserBookmarksPage.newInstance(mBookmarkCallbackWrapper,
extras, mBookmarksHeader);
- mBookmarks.setBreadCrumbMaxVisible(2);
- mBookmarks.setBreadCrumbUseBackButton(false);
mHistory = BrowserHistoryPage.newInstance(mUiController, extras);
}
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index dcb62a6..06f00c7 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -18,6 +18,7 @@ package com.android.browser;
import com.android.browser.IntentHandler.UrlData;
import com.android.browser.UI.DropdownChangeListener;
+import com.android.browser.provider.BrowserProvider;
import com.android.browser.search.SearchEngine;
import com.android.common.Search;
@@ -56,7 +57,6 @@ import android.provider.BrowserContract.Images;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Intents.Insert;
import android.speech.RecognizerIntent;
-import android.speech.RecognizerResultsIntent;
import android.text.TextUtils;
import android.util.Log;
import android.util.Patterns;
@@ -80,6 +80,7 @@ import android.webkit.WebIconDatabase;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Toast;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URLEncoder;
@@ -96,6 +97,7 @@ public class Controller
private static final String LOGTAG = "Controller";
private static final String SEND_APP_ID_EXTRA =
"android.speech.extras.SEND_APPLICATION_ID_EXTRA";
+ private static final String INCOGNITO_URI = "browser:incognito";
// public message ids
@@ -132,6 +134,9 @@ public class Controller
// "source" parameter for Google search through simplily type
final static String GOOGLE_SEARCH_SOURCE_TYPE = "browser-type";
+ // "no-crash-recovery" parameter in intetnt to suppress crash recovery
+ final static String NO_CRASH_RECOVERY = "no-crash-recovery";
+
private Activity mActivity;
private UI mUi;
private TabControl mTabControl;
@@ -197,6 +202,7 @@ public class Controller
// Tabs' notion of whether they represent bookmarked sites.
private ContentObserver mBookmarksObserver;
private DataController mDataController;
+ private CrashRecoveryHandler mCrashRecoveryHandler;
private static class ClearThumbnails extends AsyncTask<File, Void, Void> {
@Override
@@ -218,7 +224,7 @@ public class Controller
mDataController = DataController.getInstance(mActivity);
mTabControl = new TabControl(this);
mSettings.setController(this);
- mSettings.updateRlzValues(mActivity);
+ mCrashRecoveryHandler = new CrashRecoveryHandler(this);
mUrlHandler = new UrlHandler(this);
mIntentHandler = new IntentHandler(mActivity, this);
@@ -252,6 +258,16 @@ public class Controller
}
void start(final Bundle icicle, final Intent intent) {
+ boolean noCrashRecovery = intent.getBooleanExtra(NO_CRASH_RECOVERY, false);
+ if (icicle != null || noCrashRecovery) {
+ mCrashRecoveryHandler.clearState();
+ doStart(icicle, intent);
+ } else {
+ mCrashRecoveryHandler.startRecovery(intent);
+ }
+ }
+
+ void doStart(final Bundle icicle, final Intent intent) {
// Unless the last browser usage was within 24 hours, destroy any
// remaining incognito tabs.
@@ -266,10 +282,10 @@ public class Controller
|| lastActiveDate.after(today));
// Find out if we will restore any state and remember the tab.
- final int currentTab =
+ final long currentTabId =
mTabControl.canRestoreState(icicle, restoreIncognitoTabs);
- if (currentTab == -1) {
+ if (currentTabId == -1) {
// Not able to restore so we go ahead and clear session cookies. We
// must do this before trying to login the user as we don't want to
// clear any session cookies set during login.
@@ -279,31 +295,29 @@ public class Controller
GoogleAccountLogin.startLoginIfNeeded(mActivity,
new Runnable() {
@Override public void run() {
- start(icicle, intent, currentTab, restoreIncognitoTabs);
+ onPreloginFinished(icicle, intent, currentTabId, restoreIncognitoTabs);
}
});
}
- private void start(Bundle icicle, Intent intent, int currentTab,
+ private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
boolean restoreIncognitoTabs) {
- if (currentTab == -1) {
+ if (currentTabId == -1) {
final Bundle extra = intent.getExtras();
// Create an initial tab.
// If the intent is ACTION_VIEW and data is not null, the Browser is
// invoked to view the content by another application. In this case,
// the tab will be close when exit.
UrlData urlData = mIntentHandler.getUrlDataFromIntent(intent);
-
- String action = intent.getAction();
- final Tab t = mTabControl.createNewTab(
- (Intent.ACTION_VIEW.equals(action) &&
- intent.getData() != null)
- || RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS
- .equals(action),
- intent.getStringExtra(Browser.EXTRA_APPLICATION_ID),
- urlData.mUrl, false);
- addTab(t);
- setActiveTab(t);
+ Tab t = null;
+ if (urlData.isEmpty()) {
+ t = openTabToHomePage();
+ } else {
+ t = openTab(urlData);
+ }
+ if (t != null) {
+ t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
+ }
WebView webView = t.getWebView();
if (extra != null) {
int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
@@ -311,17 +325,8 @@ public class Controller
webView.setInitialScale(scale);
}
}
-
- if (urlData.isEmpty()) {
- loadUrl(webView, mSettings.getHomePage());
- } else {
- // monkey protection against delayed start
- if (t != null) {
- loadUrlDataIn(t, urlData);
- }
- }
} else {
- mTabControl.restoreState(icicle, currentTab, restoreIncognitoTabs,
+ mTabControl.restoreState(icicle, currentTabId, restoreIncognitoTabs,
mUi.needsRestoreAllTabs());
mUi.updateTabs(mTabControl.getTabs());
// TabControl.restoreState() will create a new tab even if
@@ -334,7 +339,7 @@ public class Controller
new ClearThumbnails().execute(mTabControl.getThumbnailDir()
.listFiles());
// Read JavaScript flags if it exists.
- String jsFlags = getSettings().getJsFlags();
+ String jsFlags = getSettings().getJsEngineFlags();
if (jsFlags.trim().length() != 0) {
getCurrentWebView().setJsFlags(jsFlags);
}
@@ -475,7 +480,12 @@ public class Controller
break;
case R.id.open_newtab_context_menu_id:
final Tab parent = mTabControl.getCurrentTab();
- final Tab newTab = openTab(parent, url, false);
+ final Tab newTab =
+ openTab(url,
+ (parent != null)
+ && parent.isPrivateBrowsingEnabled(),
+ !mSettings.openInBackground(),
+ true);
if (newTab != null && newTab != parent) {
parent.addChildTab(newTab);
}
@@ -610,6 +620,7 @@ public class Controller
mNetworkHandler.onPause();
WebView.disablePlatformNotifications();
+ mCrashRecoveryHandler.clearState();
}
void onSaveInstanceState(Bundle outState) {
@@ -911,6 +922,11 @@ public class Controller
}
mDataController.updateVisitedHistory(url);
WebIconDatabase.getInstance().retainIconForPageUrl(url);
+ if (!mActivityPaused) {
+ // Since we clear the state in onPause, don't backup the current
+ // state if we are already paused
+ mCrashRecoveryHandler.backupState();
+ }
}
@Override
@@ -1056,14 +1072,20 @@ public class Controller
mActivity.startActivity(intent);
}
- public void activateVoiceSearchMode(String title) {
- mUi.showVoiceTitleBar(title);
+ @Override
+ public void activateVoiceSearchMode(String title, List<String> results) {
+ mUi.showVoiceTitleBar(title, results);
}
public void revertVoiceSearchMode(Tab tab) {
mUi.revertVoiceTitleBar(tab);
}
+ public boolean supportsVoiceSearch() {
+ SearchEngine searchEngine = getSettings().getSearchEngine();
+ return (searchEngine != null && searchEngine.supportsVoiceSearch());
+ }
+
public void showCustomView(Tab tab, View view,
WebChromeClient.CustomViewCallback callback) {
if (tab.inForeground()) {
@@ -1098,7 +1120,7 @@ public class Controller
case PREFERENCES_PAGE:
if (resultCode == Activity.RESULT_OK && intent != null) {
String action = intent.getStringExtra(Intent.EXTRA_TEXT);
- if (BrowserSettings.PREF_CLEAR_HISTORY.equals(action)) {
+ if (PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY.equals(action)) {
mTabControl.removeParentChildRelationShips();
}
}
@@ -1161,7 +1183,11 @@ public class Controller
removeComboView();
if (!TextUtils.isEmpty(url)) {
if (newTab) {
- openTab(mTabControl.getCurrentTab(), url, false);
+ final Tab parent = mTabControl.getCurrentTab();
+ openTab(url,
+ (parent != null) && parent.isPrivateBrowsingEnabled(),
+ !mSettings.openInBackground(),
+ true);
} else {
final Tab currentTab = mTabControl.getCurrentTab();
dismissSubWindow(currentTab);
@@ -1335,8 +1361,7 @@ public class Controller
boolean showNewTab = mTabControl.canCreateNewTab();
MenuItem newTabItem
= menu.findItem(R.id.open_newtab_context_menu_id);
- newTabItem.setTitle(
- BrowserSettings.getInstance().openInBackground()
+ newTabItem.setTitle(getSettings().openInBackground()
? R.string.contextmenu_openlink_newwindow_background
: R.string.contextmenu_openlink_newwindow);
newTabItem.setVisible(showNewTab);
@@ -1363,8 +1388,12 @@ public class Controller
@Override
public boolean onMenuItemClick(MenuItem item) {
final Tab parent = mTabControl.getCurrentTab();
- final Tab newTab = openTab(parent,
- extra, false);
+ final Tab newTab =
+ openTab(extra,
+ (parent != null)
+ && parent.isPrivateBrowsingEnabled(),
+ !mSettings.openInBackground(),
+ true);
if (newTab != parent) {
parent.addChildTab(newTab);
}
@@ -1465,12 +1494,12 @@ public class Controller
PackageManager.MATCH_DEFAULT_ONLY);
menu.findItem(R.id.share_page_menu_id).setVisible(ri != null);
- boolean isNavDump = mSettings.isNavDump();
+ boolean isNavDump = mSettings.enableNavDump();
final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id);
nav.setVisible(isNavDump);
nav.setEnabled(isNavDump);
- boolean showDebugSettings = mSettings.showDebugSettings();
+ boolean showDebugSettings = mSettings.isDebugEnabled();
final MenuItem counter = menu.findItem(R.id.dump_counters_menu_id);
counter.setVisible(showDebugSettings);
counter.setEnabled(showDebugSettings);
@@ -1683,7 +1712,7 @@ public class Controller
Tab desiredTab = mTabControl.getTab(id);
if (desiredTab != null &&
desiredTab != mTabControl.getCurrentTab()) {
- switchToTab(id);
+ switchToTab(desiredTab);
}
break;
}
@@ -1774,7 +1803,6 @@ public class Controller
// title bar once again.
mExtendedMenuOpen = false;
mUi.onExtendedMenuClosed(mInLoad);
- mUi.onOptionsMenuOpened();
}
}
} else {
@@ -2103,7 +2131,8 @@ public class Controller
mTabControl.removeTab(tab);
}
- protected void setActiveTab(Tab tab) {
+ @Override
+ public void setActiveTab(Tab tab) {
// monkey protection against delayed start
if (tab != null) {
mTabControl.setCurrentTab(tab);
@@ -2116,9 +2145,9 @@ public class Controller
Tab current = mTabControl.getCurrentTab();
if (current != null
&& current.getWebView().copyBackForwardList().getSize() == 0) {
- Tab parent = current.getParentTab();
+ Tab parent = current.getParent();
if (parent != null) {
- switchToTab(mTabControl.getTabIndex(parent));
+ switchToTab(parent);
closeTab(current);
}
}
@@ -2135,7 +2164,7 @@ public class Controller
// TODO: analyze why the remove and add are necessary
mUi.attachTab(appTab);
if (mTabControl.getCurrentTab() != appTab) {
- switchToTab(mTabControl.getTabIndex(appTab));
+ switchToTab(appTab);
loadUrlDataIn(appTab, urlData);
} else {
// If the tab was the current tab, we have to attach
@@ -2169,92 +2198,74 @@ public class Controller
}
}
- @Override
- public Tab openTabToHomePage() {
- // check for max tabs
- if (mTabControl.canCreateNewTab()) {
- return openTabAndShow(null, new UrlData(mSettings.getHomePage()),
- false, null);
- } else {
- mUi.showMaxTabsWarning();
- return null;
+ // open a non inconito tab with the given url data
+ // and set as active tab
+ public Tab openTab(UrlData urlData) {
+ Tab tab = createNewTab(false, true, true);
+ if ((tab != null) && !urlData.isEmpty()) {
+ loadUrlDataIn(tab, urlData);
}
+ return tab;
}
- protected Tab openTab(Tab parent, String url, boolean forceForeground) {
- if (mSettings.openInBackground() && !forceForeground) {
- Tab tab = mTabControl.createNewTab(false, null, null,
- (parent != null) && parent.isPrivateBrowsingEnabled());
- if (tab != null) {
- addTab(tab);
- WebView view = tab.getWebView();
- loadUrl(view, url);
- }
- return tab;
- } else {
- return openTabAndShow(parent, new UrlData(url), false, null);
- }
+ @Override
+ public Tab openTabToHomePage() {
+ return openTab(mSettings.getHomePage(), false, true, false);
}
+ @Override
+ public Tab openIncognitoTab() {
+ return openTab(INCOGNITO_URI, true, true, false);
+ }
- // This method does a ton of stuff. It will attempt to create a new tab
- // if we haven't reached MAX_TABS. Otherwise it uses the current tab. If
- // url isn't null, it will load the given url.
- public Tab openTabAndShow(Tab parent, final UrlData urlData,
- boolean closeOnExit, String appId) {
- final Tab currentTab = mTabControl.getCurrentTab();
- if (mTabControl.canCreateNewTab()) {
- final Tab tab = mTabControl.createNewTab(closeOnExit, appId,
- urlData.mUrl,
- (parent != null) && parent.isPrivateBrowsingEnabled());
- WebView webview = tab.getWebView();
- // We must set the new tab as the current tab to reflect the old
- // animation behavior.
- addTab(tab);
- setActiveTab(tab);
- if (!urlData.isEmpty()) {
- loadUrlDataIn(tab, urlData);
- }
- return tab;
- } else {
- // Get rid of the subwindow if it exists
- dismissSubWindow(currentTab);
- if (!urlData.isEmpty()) {
- // Load the given url.
- loadUrlDataIn(currentTab, urlData);
+ @Override
+ public Tab openTab(String url, boolean incognito, boolean setActive,
+ boolean useCurrent) {
+ Tab tab = createNewTab(incognito, setActive, useCurrent);
+ if (tab != null) {
+ WebView w = tab.getWebView();
+ if (url != null) {
+ loadUrl(w, url);
}
- return currentTab;
}
+ return tab;
}
- @Override
- public Tab openIncognitoTab() {
+ // this method will attempt to create a new tab
+ // incognito: private browsing tab
+ // setActive: ste tab as current tab
+ // useCurrent: if no new tab can be created, return current tab
+ private Tab createNewTab(boolean incognito, boolean setActive,
+ boolean useCurrent) {
+ Tab tab = null;
if (mTabControl.canCreateNewTab()) {
- Tab currentTab = mTabControl.getCurrentTab();
- Tab tab = mTabControl.createNewTab(false, null,
- null, true);
+ tab = mTabControl.createNewTab(incognito);
addTab(tab);
- setActiveTab(tab);
- loadUrlDataIn(tab, new UrlData("browser:incognito"));
- return tab;
+ if (setActive) {
+ setActiveTab(tab);
+ }
} else {
- mUi.showMaxTabsWarning();
- return null;
+ if (useCurrent) {
+ tab = mTabControl.getCurrentTab();
+ // Get rid of the subwindow if it exists
+ dismissSubWindow(tab);
+ } else {
+ mUi.showMaxTabsWarning();
+ }
}
+ return tab;
}
/**
- * @param index Index of the tab to change to, as defined by
- * mTabControl.getTabIndex(Tab t).
+ * @param tab the tab to switch to
* @return boolean True if we successfully switched to a different tab. If
* the indexth tab is null, or if that tab is the same as
* the current one, return false.
*/
@Override
- public boolean switchToTab(int index) {
+ public boolean switchToTab(Tab tab) {
// hide combo view if open
removeComboView();
- Tab tab = mTabControl.getTab(index);
Tab currentTab = mTabControl.getCurrentTab();
if (tab == null || tab == currentTab) {
return false;
@@ -2267,25 +2278,20 @@ public class Controller
public void closeCurrentTab() {
// hide combo view if open
removeComboView();
- final Tab current = mTabControl.getCurrentTab();
if (mTabControl.getTabCount() == 1) {
mActivity.finish();
return;
}
- final Tab parent = current.getParentTab();
- int indexToShow = -1;
- if (parent != null) {
- indexToShow = mTabControl.getTabIndex(parent);
- } else {
- final int currentIndex = mTabControl.getCurrentIndex();
- // Try to move to the tab to the right
- indexToShow = currentIndex + 1;
- if (indexToShow > mTabControl.getTabCount() - 1) {
- // Try to move to the tab to the left
- indexToShow = currentIndex - 1;
+ final Tab current = mTabControl.getCurrentTab();
+ final int pos = mTabControl.getCurrentPosition();
+ Tab newTab = current.getParent();
+ if (newTab == null) {
+ newTab = mTabControl.getTab(pos + 1);
+ if (newTab == null) {
+ newTab = mTabControl.getTab(pos - 1);
}
}
- if (switchToTab(indexToShow)) {
+ if (switchToTab(newTab)) {
// Close window
closeTab(current);
}
@@ -2299,10 +2305,6 @@ public class Controller
public void closeTab(Tab tab) {
// hide combo view if open
removeComboView();
- int currentIndex = mTabControl.getCurrentIndex();
- int removeIndex = mTabControl.getTabIndex(tab);
- Tab newtab = mTabControl.getTab(currentIndex);
- setActiveTab(newtab);
removeTab(tab);
}
@@ -2370,18 +2372,12 @@ public class Controller
} else {
// Check to see if we are closing a window that was created by
// another window. If so, we switch back to that window.
- Tab parent = current.getParentTab();
+ Tab parent = current.getParent();
if (parent != null) {
- switchToTab(mTabControl.getTabIndex(parent));
+ switchToTab(parent);
// Now we close the other tab
closeTab(current);
} else {
- if (current.closeOnExit()) {
- // This will finish the activity if there is only one tab
- // open or it will switch to the next available tab if
- // available.
- closeCurrentTab();
- }
/*
* Instead of finishing the activity, simply push this to the back
* of the stack and let ActivityManager to choose the foreground
@@ -2414,12 +2410,6 @@ public class Controller
startSearch(result, false, bundle, false);
}
- @Override
- public void startSearch(String url) {
- startSearch(mSettings.getHomePage().equals(url) ? null : url, true,
- null, false);
- }
-
private void startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, boolean globalSearch) {
if (appSearchData == null) {
@@ -2441,21 +2431,22 @@ public class Controller
return bundle;
}
- /**
+ /**
* helper method for key handler
* returns the current tab if it can't advance
*/
- private int getNextTabIndex() {
- return Math.min(mTabControl.getTabCount() - 1,
- mTabControl.getCurrentIndex() + 1);
+ private Tab getNextTab() {
+ return mTabControl.getTab(Math.min(mTabControl.getTabCount() - 1,
+ mTabControl.getCurrentPosition() + 1));
}
/**
* helper method for key handler
* returns the current tab if it can't advance
*/
- private int getPrevTabIndex() {
- return Math.max(0, mTabControl.getCurrentIndex() - 1);
+ private Tab getPrevTab() {
+ return mTabControl.getTab(Math.max(0,
+ mTabControl.getCurrentPosition() - 1));
}
/**
@@ -2489,10 +2480,10 @@ public class Controller
if (event.isCtrlPressed()) {
if (event.isShiftPressed()) {
// prev tab
- switchToTab(getPrevTabIndex());
+ switchToTab(getPrevTab());
} else {
// next tab
- switchToTab(getNextTabIndex());
+ switchToTab(getNextTab());
}
return true;
}
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
new file mode 100644
index 0000000..9e98e76
--- /dev/null
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 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.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Parcel;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+public class CrashRecoveryHandler {
+
+ private static final String LOGTAG = "BrowserCrashRecovery";
+ private static final String STATE_FILE = "browser_state.parcel";
+ private static final int BUFFER_SIZE = 4096;
+
+ private Controller mController;
+
+ public CrashRecoveryHandler(Controller controller) {
+ mController = controller;
+ }
+
+ public void backupState() {
+ final Bundle state = new Bundle();
+ mController.onSaveInstanceState(state);
+ final Context context = mController.getActivity();
+ new Thread() {
+ @Override
+ public void run() {
+ Parcel p = Parcel.obtain();
+ try {
+ state.writeToParcel(p, 0);
+ FileOutputStream fout = context.openFileOutput(STATE_FILE,
+ Context.MODE_PRIVATE);
+ fout.write(p.marshall());
+ fout.close();
+ } catch (Exception e) {
+ Log.i(LOGTAG, "Failed to save persistent state", e);
+ } finally {
+ p.recycle();
+ }
+ }
+ }.start();
+ }
+
+ public void clearState() {
+ Context context = mController.getActivity();
+ context.deleteFile(STATE_FILE);
+ }
+
+ public void promptToRecover(final Bundle state, final Intent intent) {
+ new AlertDialog.Builder(mController.getActivity())
+ .setTitle(R.string.recover_title)
+ .setMessage(R.string.recover_prompt)
+ .setPositiveButton(R.string.recover_yes, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mController.doStart(state, intent);
+ }
+ })
+ .setNegativeButton(R.string.recover_no, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ clearState();
+ mController.doStart(null, intent);
+ }
+ })
+ .show();
+ }
+
+ public void startRecovery(Intent intent) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ Context context = mController.getActivity();
+ FileInputStream fin = context.openFileInput(STATE_FILE);
+ ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int read;
+ while ((read = fin.read(buffer)) > 0) {
+ dataStream.write(buffer, 0, read);
+ }
+ byte[] data = dataStream.toByteArray();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ Bundle state = parcel.readBundle();
+ promptToRecover(state, intent);
+ } catch (FileNotFoundException e) {
+ // No state to recover
+ mController.doStart(null, intent);
+ } catch (Exception e) {
+ Log.w(LOGTAG, "Failed to recover state!", e);
+ mController.doStart(null, intent);
+ } finally {
+ parcel.recycle();
+ }
+ }
+}
diff --git a/src/com/android/browser/InstantSearchEngine.java b/src/com/android/browser/InstantSearchEngine.java
index 85e494a..e2e9c8a 100644
--- a/src/com/android/browser/InstantSearchEngine.java
+++ b/src/com/android/browser/InstantSearchEngine.java
@@ -18,6 +18,7 @@ package com.android.browser;
import com.android.browser.Controller;
import com.android.browser.R;
import com.android.browser.UI.DropdownChangeListener;
+import com.android.browser.provider.BrowserProvider;
import com.android.browser.search.SearchEngine;
import android.app.SearchManager;
@@ -174,7 +175,12 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener
* visible tab.
*/
private void switchSearchboxIfNeeded() {
- final SearchBox searchBox = getCurrentWebview().getSearchBox();
+ final WebView current = getCurrentWebview();
+ if (current == null) {
+ return;
+ }
+
+ final SearchBox searchBox = current.getSearchBox();
if (searchBox != mSearchBox) {
if (mSearchBox != null) {
mSearchBox.removeSearchBoxListener(mListener);
@@ -188,7 +194,12 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener
}
private boolean isInstantPage() {
- String currentUrl = getCurrentWebview().getUrl();
+ final WebView current = getCurrentWebview();
+ if (current == null) {
+ return false;
+ }
+
+ final String currentUrl = current.getUrl();
if (currentUrl != null) {
Uri uri = Uri.parse(currentUrl);
@@ -210,7 +221,10 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener
mController.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
- getCurrentWebview().loadUrl(getInstantBaseUrl());
+ final WebView current = getCurrentWebview();
+ if (current != null) {
+ current.loadUrl(getInstantBaseUrl());
+ }
}
});
}
@@ -292,7 +306,12 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener
}
private int rescaleHeight(int height) {
- final float scale = getCurrentWebview().getScale();
+ final WebView current = getCurrentWebview();
+ if (current == null) {
+ return 0;
+ }
+
+ final float scale = current.getScale();
if (scale != 0) {
return (int) (height / scale);
}
@@ -306,8 +325,10 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener
if (rescaledHeight != mHeight) {
mHeight = rescaledHeight;
- mSearchBox.setDimensions(0, 0, 0, rescaledHeight);
- mSearchBox.onresize();
+ if (mSearchBox != null) {
+ mSearchBox.setDimensions(0, 0, 0, rescaledHeight);
+ mSearchBox.onresize();
+ }
}
}
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index b556638..8d1b784 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -134,7 +134,7 @@ public class IntentHandler {
}
if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false)) {
- mController.openTabAndShow(mTabControl.getCurrentTab(), urlData, false, null);
+ mController.openTab(urlData);
return;
}
final String appId = intent
@@ -146,12 +146,15 @@ public class IntentHandler {
&& !mActivity.getPackageName().equals(appId)
&& (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
if (activateVoiceSearch) {
- Tab appTab = mTabControl.getTabFromId(appId);
+ Tab appTab = mTabControl.getTabFromAppId(appId);
if (appTab != null) {
mController.reuseTab(appTab, appId, urlData);
return;
} else {
- mController.openTabAndShow(null, urlData, false, appId);
+ Tab tab = mController.openTab(urlData);
+ if (tab != null) {
+ tab.setAppId(appId);
+ }
}
} else {
// No matching application tab, try to find a regular tab
@@ -159,7 +162,7 @@ public class IntentHandler {
Tab appTab = mTabControl.findUnusedTabWithUrl(urlData.mUrl);
if (appTab != null) {
if (current != appTab) {
- mController.switchToTab(mTabControl.getTabIndex(appTab));
+ mController.switchToTab(appTab);
}
// Otherwise, we are already viewing the correct tab.
} else {
@@ -168,7 +171,10 @@ public class IntentHandler {
// MAX_TABS. Then the url will be opened in the current
// tab. If a new tab is created, it will have "true" for
// exit on close.
- mController.openTabAndShow(null, urlData, false, appId);
+ Tab tab = mController.openTab(urlData);
+ if (tab != null) {
+ tab.setAppId(appId);
+ }
}
}
} else {
@@ -187,7 +193,7 @@ public class IntentHandler {
} else if ("about:debug.nav".equals(urlData.mUrl)) {
current.getWebView().debugDump();
} else {
- mSettings.toggleDebugSettings(mActivity);
+ mSettings.toggleDebugSettings();
}
return;
}
@@ -221,17 +227,6 @@ public class IntentHandler {
headers.put(key, pairs.getString(key));
}
}
-
- // AppId will be set to the Browser for Search Bar initiated searches
- final String appId = intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
- if (mActivity.getPackageName().equals(appId)) {
- String rlz = mSettings.getRlzValue();
- Uri uri = Uri.parse(url);
- if (!rlz.isEmpty() && needsRlz(uri)) {
- Uri rlzUri = addRlzParameter(uri, rlz);
- url = rlzUri.toString();
- }
- }
}
} else if (Intent.ACTION_SEARCH.equals(action)
|| MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
@@ -375,19 +370,4 @@ public class IntentHandler {
}
}
- private static boolean needsRlz(Uri uri) {
- if ((uri.getQueryParameter("rlz") == null) &&
- (uri.getQueryParameter("q") != null) &&
- UrlUtils.isGoogleUri(uri)) {
- return true;
- }
- return false;
- }
-
- private static Uri addRlzParameter(Uri uri, String rlz) {
- if (rlz.isEmpty()) {
- return uri;
- }
- return uri.buildUpon().appendQueryParameter("rlz", rlz).build();
- }
}
diff --git a/src/com/android/browser/NavScreen.java b/src/com/android/browser/NavScreen.java
new file mode 100644
index 0000000..a5090fa
--- /dev/null
+++ b/src/com/android/browser/NavScreen.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2011 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.Context;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.Gallery;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.ListPopupWindow;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NavScreen extends LinearLayout implements OnClickListener {
+
+ UiController mUiController;
+ PhoneUi mUi;
+ Tab mTab;
+ Activity mActivity;
+
+ View mTopPanel;
+ ImageButton mBack;
+ ImageButton mRefresh;
+ ImageButton mForward;
+ ImageButton mTabs;
+ ImageButton mBookmarks;
+ ImageButton mMore;
+ ImageButton mNewTab;
+ ImageButton mNewIncognito;
+ FrameLayout mHolder;
+
+ Gallery mFlipper;
+ float mTabAspect = 0.66f;
+ int mTabWidth;
+ int mTabHeight;
+ TabAdapter mAdapter;
+ ListPopupWindow mPopup;
+ int mOrientation;
+
+ public NavScreen(Activity activity, UiController ctl, PhoneUi ui) {
+ super(activity);
+ mActivity = activity;
+ mUiController = ctl;
+ mUi = ui;
+ mOrientation = activity.getResources().getConfiguration().orientation;
+ init();
+ }
+
+ @Override
+ public void onMeasure(int wspec, int hspec) {
+ super.onMeasure(wspec, hspec);
+ mTabHeight = mFlipper.getMeasuredHeight();
+ mTabWidth = (int) (mTabHeight * mTabAspect);
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ protected Tab getSelectedTab() {
+ return (Tab) mFlipper.getSelectedItem();
+ }
+
+ protected void showMenu() {
+ Menu menu = mUi.getMenu();
+ menu.setGroupVisible(R.id.NAV_MENU, false);
+
+ MenuAdapter menuAdapter = new MenuAdapter(mContext);
+ menuAdapter.setMenu(menu);
+ ListPopupWindow popup = new ListPopupWindow(mContext);
+ popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
+ popup.setAdapter(menuAdapter);
+ popup.setModal(true);
+ popup.setAnchorView(mMore);
+ popup.setWidth((int) mContext.getResources().getDimension(
+ R.dimen.menu_width));
+ popup.show();
+ mPopup = popup;
+ }
+
+ protected float getToolbarHeight() {
+ return mActivity.getResources().getDimension(R.dimen.toolbar_height);
+ }
+
+ protected void dismissMenu() {
+ if (mPopup != null) {
+ mPopup.dismiss();
+ }
+ }
+
+ // for configuration changes
+ @Override
+ protected void onConfigurationChanged(Configuration newconfig) {
+ if (newconfig.orientation != mOrientation) {
+ int selIx = mFlipper.getSelectedItemPosition();
+ removeAllViews();
+ init();
+ mFlipper.setSelection(selIx);
+ mOrientation = newconfig.orientation;
+ }
+ }
+
+ private void init() {
+ LayoutInflater.from(mContext).inflate(R.layout.nav_screen, this);
+ LinearLayout content = (LinearLayout) findViewById(R.id.nav_screen);
+ mTopPanel = findViewById(R.id.navtop);
+ mBack = (ImageButton) findViewById(R.id.back);
+ mForward = (ImageButton) findViewById(R.id.forward);
+ mRefresh = (ImageButton) findViewById(R.id.refresh);
+ mTabs = (ImageButton) findViewById(R.id.tabs);
+ mBookmarks = (ImageButton) findViewById(R.id.bookmarks);
+ mNewTab = (ImageButton) findViewById(R.id.newtab);
+ mNewIncognito = (ImageButton) findViewById(R.id.newincognito);
+ mMore = (ImageButton) findViewById(R.id.more);
+ mBack.setOnClickListener(this);
+ mForward.setOnClickListener(this);
+ mRefresh.setOnClickListener(this);
+ mTabs.setOnClickListener(this);
+ mBookmarks.setOnClickListener(this);
+ mNewTab.setOnClickListener(this);
+ mNewIncognito.setOnClickListener(this);
+ mMore.setOnClickListener(this);
+ mHolder = (FrameLayout) findViewById(R.id.galleryholder);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mFlipper = new TabGallery(mContext);
+ mFlipper.setSpacing((int)(mContext.getResources()
+ .getDimension(R.dimen.nav_tab_spacing)));
+ mFlipper.setUnselectedAlpha(0.8f);
+ mFlipper.setLayoutParams(lp);
+ mHolder.addView(mFlipper, 0);
+ mAdapter = new TabAdapter(mContext, mUiController.getTabControl());
+ mFlipper.setAdapter(mAdapter);
+ setTab(mUi.getActiveTab(), true);
+ mFlipper.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view,
+ int position, long id) {
+ // post as runnable to prevent bug in gesturedetector
+ // when view is removed in click handler
+ // sends action_cancel before action_up
+ mFlipper.post(new Runnable() {
+ public void run() {
+ close();
+ }
+ });
+ }
+ });
+ mFlipper.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view,
+ int position, long id) {
+ final Tab tab = mAdapter.getItem(position);
+ setTab(tab, false);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+ }
+
+ private void setTab(Tab tab, boolean updateFlipper) {
+ mTab = tab;
+ // refresh state from tab
+ WebView web = tab.getWebView();
+ if (web != null) {
+ mBack.setImageResource(web.canGoBack()
+ ? R.drawable.ic_back_holo_dark
+ : R.drawable.ic_back_disabled_holo_dark);
+ mForward.setImageResource(web.canGoForward()
+ ? R.drawable.ic_forward_holo_dark
+ : R.drawable.ic_forward_disabled_holo_dark);
+ }
+ if (updateFlipper) {
+ mFlipper.setSelection(mUiController.getTabControl().getTabPosition(tab));
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ WebView web = (mTab != null) ? mTab.getWebView() : null;
+ if (web != null) {
+ if (mBack == v) {
+ mUi.hideNavScreen(true);
+ switchToSelected();
+ web.goBack();
+ } else if (mForward == v) {
+ mUi.hideNavScreen(true);
+ switchToSelected();
+ web.goForward();
+ } else if (mRefresh == v) {
+ mUi.hideNavScreen(true);
+ switchToSelected();
+ web.reload();
+ }
+ }
+ if (mBookmarks == v) {
+ mUi.hideNavScreen(false);
+ switchToSelected();
+ mUiController.bookmarksOrHistoryPicker(false);
+ } else if (mTabs == v) {
+ } else if (mNewTab == v) {
+ openNewTab();
+ } else if (mMore == v) {
+ showMenu();
+ } else if (mNewIncognito == v) {
+ mUi.hideNavScreen(true);
+ mUiController.openIncognitoTab();
+ }
+ }
+
+ private void openNewTab() {
+ Tab tab = mUiController.openTabToHomePage();
+ mAdapter.notifyDataSetChanged();
+
+ if (tab != null) {
+ // set tab as the selected in flipper, then hide
+ final int tix = mUi.mTabControl.getTabPosition(tab);
+ post(new Runnable() {
+ public void run() {
+ if (tix != -1) {
+ for (int i = mFlipper.getSelectedItemPosition();
+ i <= tix; i++) {
+ mFlipper.setSelection(i, true);
+ mFlipper.invalidate();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ mUi.hideNavScreen(true);
+ switchToSelected();
+ }
+ });
+ }
+ }
+
+ private void switchToSelected() {
+ Tab tab = (Tab) mFlipper.getSelectedItem();
+ if (tab != mUi.getActiveTab()) {
+ mUiController.setActiveTab(tab);
+ }
+ }
+
+ protected void close() {
+ close(true);
+ }
+
+ protected void close(boolean animate) {
+ mUi.hideNavScreen(animate);
+ switchToSelected();
+ }
+
+ class TabGallery extends Gallery {
+
+ public TabGallery(Context ctx) {
+ super(ctx);
+ setUnselectedAlpha(0.3f);
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+ return new Gallery.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+ return generateDefaultLayoutParams();
+ }
+
+ }
+
+ class TabAdapter extends BaseAdapter {
+
+ Context context;
+ TabControl tabControl;
+
+ public TabAdapter(Context ctx, TabControl tc) {
+ context = ctx;
+ tabControl = tc;
+ }
+
+ void onCloseTab(Tab tab) {
+ if (tab != null) {
+ mUiController.closeTab(tab);
+ if (tabControl.getTabCount() == 0) {
+ mUiController.openTabToHomePage();
+ mUi.hideNavScreen(false);
+ } else {
+ notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return tabControl.getTabCount();
+ }
+
+ @Override
+ public Tab getItem(int position) {
+ return tabControl.getTab(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ImageView content = null;
+ if (convertView == null) {
+ convertView = LayoutInflater.from(context).inflate(R.layout.nav_tab_view,
+ null);
+ content = (ImageView) convertView.findViewById(R.id.content);
+ content.setLayoutParams(new LayoutParams(mTabWidth, mTabHeight));
+ } else {
+ content = (ImageView) convertView.findViewById(R.id.content);
+ content.setLayoutParams(new LayoutParams(mTabWidth, mTabHeight));
+ }
+ View tbar = convertView.findViewById(R.id.titlebar);
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ ImageView icon = (ImageView) convertView.findViewById(R.id.favicon);
+ ImageButton close = (ImageButton) convertView.findViewById(R.id.closetab);
+ final Tab tab = getItem(position);
+ icon.setImageDrawable(mUi.getFaviconDrawable(tab.getFavicon()));
+ title.setText(tab.getUrl());
+ content.setScaleType(ScaleType.MATRIX);
+ Matrix matrix = new Matrix();
+ Bitmap screen = tab.getScreenshot();
+ if (screen != null) {
+ float scale = 1.0f;
+ if (mTabWidth > mTabHeight) {
+ scale = mTabWidth / (float) screen.getWidth();
+ } else {
+ scale = mTabHeight / (float) screen.getHeight();
+ }
+ matrix.setScale(scale, scale);
+ content.setImageMatrix(matrix);
+ content.setImageBitmap(screen);
+ }
+ close.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onCloseTab(tab);
+ }
+ });
+ tbar.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ close(false);
+ mUi.getTitleBar().setSkipTitleBarAnimations(true);
+ mUi.editUrl(false);
+ mUi.getTitleBar().setSkipTitleBarAnimations(false);
+ }
+ });
+ return convertView;
+ }
+ }
+
+ private class MenuAdapter extends BaseAdapter implements OnClickListener {
+
+ List<MenuItem> mItems;
+ LayoutInflater mInflater;
+
+ public MenuAdapter(Context ctx) {
+ mInflater = LayoutInflater.from(ctx);
+ mItems = new ArrayList<MenuItem>();
+ }
+
+ public void setMenu(Menu menu) {
+ mItems.clear();
+ for (int i = 0; i < menu.size(); i++) {
+ MenuItem item = menu.getItem(i);
+ if (item.isEnabled() && item.isVisible()) {
+ mItems.add(item);
+ }
+ }
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public MenuItem getItem(int position) {
+ return mItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getTag() != null) {
+ dismissMenu();
+ mActivity.closeOptionsMenu();
+ mUi.hideNavScreen(false);
+ mUiController.onOptionsItemSelected((MenuItem) v.getTag());
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final MenuItem item = mItems.get(position);
+ View view = mInflater.inflate(R.layout.qc_menu_item, null);
+ TextView label = (TextView) view.findViewById(R.id.title);
+ label.setText(item.getTitle());
+ label.setTag(item);
+ label.setOnClickListener(this);
+ return label;
+ }
+
+ }
+
+}
diff --git a/src/com/android/browser/PhoneUi.java b/src/com/android/browser/PhoneUi.java
index f1939e4..e838cd4 100644
--- a/src/com/android/browser/PhoneUi.java
+++ b/src/com/android/browser/PhoneUi.java
@@ -16,18 +16,19 @@
package com.android.browser;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.app.Activity;
-import android.content.Context;
-import android.graphics.PixelFormat;
import android.util.Log;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.WindowManager;
import android.webkit.WebView;
+import android.widget.FrameLayout;
/**
* Ui for regular phone screen sizes
@@ -35,13 +36,17 @@ import android.webkit.WebView;
public class PhoneUi extends BaseUi {
private static final String LOGTAG = "PhoneUi";
+ private static final float NAV_TAB_SCALE = 0.75f;
- private TitleBar mTitleBar;
+ private TitleBarPhone mTitleBar;
private ActiveTabsPage mActiveTabsPage;
- private TouchProxy mTitleOverlay;
+ private boolean mUseQuickControls;
+ private PieControl mPieControl;
+ private NavScreen mNavScreen;
boolean mExtendedMenuOpen;
boolean mOptionsMenuOpen;
+ boolean mAnimating;
/**
* @param browser
@@ -49,11 +54,13 @@ public class PhoneUi extends BaseUi {
*/
public PhoneUi(Activity browser, UiController controller) {
super(browser, controller);
- mTitleBar = new TitleBar(mActivity, mUiController, this);
+ mTitleBar = new TitleBarPhone(mActivity, mUiController, this,
+ mContentView);
// mTitleBar will be always be shown in the fully loaded mode on
// phone
mTitleBar.setProgress(100);
mActivity.getActionBar().hide();
+ setUseQuickControls(BrowserSettings.getInstance().useQuickControls());
}
@Override
@@ -62,23 +69,6 @@ public class PhoneUi extends BaseUi {
mActivity.getActionBar().hide();
}
- // webview factory
-
- @Override
- public WebView createWebView(boolean privateBrowsing) {
- // Create a new WebView
- WebView w = new WebView(mActivity, null,
- android.R.attr.webViewStyle, privateBrowsing);
- initWebViewSettings(w);
- return w;
- }
-
- @Override
- public WebView createSubWebView(boolean privateBrowsing) {
- WebView web = createWebView(privateBrowsing);
- return web;
- }
-
// lifecycle
@Override
@@ -100,8 +90,10 @@ public class PhoneUi extends BaseUi {
@Override
public void editUrl(boolean clearInput) {
- String url = getActiveTab().getUrl();
- mUiController.startSearch(url);
+ if (mUseQuickControls) {
+ getTitleBar().setShowProgressOnly(false);
+ }
+ super.editUrl(clearInput);
}
@Override
@@ -110,11 +102,31 @@ public class PhoneUi extends BaseUi {
// if tab page is showing, hide it
mUiController.removeActiveTabsPage(true);
return true;
+ } else if (mNavScreen != null) {
+ mNavScreen.close();
+ return true;
}
return super.onBackKey();
}
@Override
+ public boolean dispatchKey(int code, KeyEvent event) {
+ if (!isComboViewShowing()) {
+ switch (code) {
+ case KeyEvent.KEYCODE_MENU:
+ if (mNavScreen == null) {
+ showNavScreen();
+ return true;
+ } else {
+ mNavScreen.close();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
public void onProgressChanged(Tab tab) {
if (tab.inForeground()) {
int progress = tab.getLoadProgress();
@@ -122,9 +134,16 @@ public class PhoneUi extends BaseUi {
if (progress == 100) {
if (!mOptionsMenuOpen || !mExtendedMenuOpen) {
hideTitleBar();
+ if (mUseQuickControls) {
+ mTitleBar.setShowProgressOnly(false);
+ }
}
} else {
if (!mOptionsMenuOpen || mExtendedMenuOpen) {
+ if (mUseQuickControls && !mTitleBar.isEditingUrl()) {
+ mTitleBar.setShowProgressOnly(true);
+ setTitleGravity(Gravity.TOP);
+ }
showTitleBar();
}
}
@@ -132,41 +151,41 @@ public class PhoneUi extends BaseUi {
}
@Override
- public void setActiveTab(Tab tab) {
- super.setActiveTab(tab);
- WebView view = tab.getWebView();
+ public void setActiveTab(final Tab tab) {
+ captureTab(mActiveTab);
+ super.setActiveTab(tab, true);
+ setActiveTab(tab, true);
+ }
+
+ @Override
+ void setActiveTab(Tab tab, boolean needsAttaching) {
+ BrowserWebView view = (BrowserWebView) tab.getWebView();
// TabControl.setCurrentTab has been called before this,
// so the tab is guaranteed to have a webview
if (view == null) {
Log.e(LOGTAG, "active tab with no webview detected");
return;
}
- view.setEmbeddedTitleBar(getTitleBar());
+ // Request focus on the top window.
+ if (mUseQuickControls) {
+ mPieControl.forceToTop(mContentView);
+ view.setScrollListener(null);
+ } else {
+ // check if title bar is already attached by animation
+ if (mTitleBar.getParent() == null) {
+ view.setEmbeddedTitleBar(mTitleBar);
+ }
+ }
if (tab.isInVoiceSearchMode()) {
- showVoiceTitleBar(tab.getVoiceDisplayTitle());
+ showVoiceTitleBar(tab.getVoiceDisplayTitle(), tab.getVoiceSearchResults());
} else {
revertVoiceTitleBar(tab);
}
+ updateLockIconToLatest(tab);
tab.getTopWindow().requestFocus();
}
@Override
- protected void showTitleBar() {
- if (canShowTitleBar()) {
- setTitleGravity(Gravity.TOP);
- super.showTitleBar();
- }
- }
-
- @Override
- protected void hideTitleBar() {
- if (isTitleBarShowing()) {
- setTitleGravity(Gravity.NO_GRAVITY);
- super.hideTitleBar();
- }
- }
-
- @Override
protected TitleBarBase getTitleBar() {
return mTitleBar;
}
@@ -175,6 +194,7 @@ public class PhoneUi extends BaseUi {
@Override
public void showActiveTabsPage() {
+ captureTab(mActiveTab);
mActiveTabsPage = new ActiveTabsPage(mActivity, mUiController);
mTitleBar.setVisibility(View.GONE);
hideTitleBar();
@@ -200,91 +220,200 @@ public class PhoneUi extends BaseUi {
// menu handling callbacks
@Override
- public void onOptionsMenuOpened() {
- mOptionsMenuOpen = true;
- // options menu opened, show title bar
- showTitleBar();
- if (mTitleOverlay == null) {
- // This assumes that getTitleBar always returns the same View
- mTitleOverlay = new TouchProxy(mActivity, getTitleBar());
- }
- mActivity.getWindowManager().addView(mTitleOverlay,
- mTitleOverlay.getWindowLayoutParams());
- }
-
- @Override
- public void onExtendedMenuOpened() {
- // Switching the menu to expanded view, so hide the
- // title bar.
- mExtendedMenuOpen = true;
+ public void onContextMenuCreated(Menu menu) {
hideTitleBar();
}
@Override
- public void onOptionsMenuClosed(boolean inLoad) {
- mOptionsMenuOpen = false;
- mActivity.getWindowManager().removeView(mTitleOverlay);
- if (!inLoad && !getTitleBar().hasFocus()) {
- hideTitleBar();
+ public void onContextMenuClosed(Menu menu, boolean inLoad) {
+ if (inLoad) {
+ showTitleBar();
}
}
- @Override
- public void onExtendedMenuClosed(boolean inLoad) {
- mExtendedMenuOpen = false;
- showTitleBar();
- }
+ // action mode callbacks
@Override
- public void onContextMenuCreated(Menu menu) {
+ public void onActionModeStarted(ActionMode mode) {
hideTitleBar();
}
@Override
- public void onContextMenuClosed(Menu menu, boolean inLoad) {
+ public void onActionModeFinished(boolean inLoad) {
if (inLoad) {
+ if (mUseQuickControls) {
+ mTitleBar.setShowProgressOnly(true);
+ }
showTitleBar();
}
+ mActivity.getActionBar().hide();
}
- // action mode callbacks
-
@Override
- public void onActionModeStarted(ActionMode mode) {
- hideTitleBar();
+ protected void setTitleGravity(int gravity) {
+ if (mUseQuickControls) {
+ FrameLayout.LayoutParams lp =
+ (FrameLayout.LayoutParams) getTitleBar().getLayoutParams();
+ lp.gravity = gravity;
+ getTitleBar().setLayoutParams(lp);
+ } else {
+ super.setTitleGravity(gravity);
+ }
+ }
+
+ private void setUseQuickControls(boolean useQuickControls) {
+ mUseQuickControls = useQuickControls;
+ getTitleBar().setUseQuickControls(mUseQuickControls);
+ if (useQuickControls) {
+ mPieControl = new PieControl(mActivity, mUiController, this);
+ mPieControl.attachToContainer(mContentView);
+ WebView web = getWebView();
+ if (web != null) {
+ web.setEmbeddedTitleBar(null);
+ }
+ } else {
+ if (mPieControl != null) {
+ mPieControl.removeFromContainer(mContentView);
+ }
+ WebView web = getWebView();
+ if (web != null) {
+ web.setEmbeddedTitleBar(mTitleBar);
+ }
+ setTitleGravity(Gravity.NO_GRAVITY);
+ }
}
@Override
- public boolean dispatchKey(int code, KeyEvent event) {
- return false;
+ protected void captureTab(final Tab tab) {
+ if (tab == null) return;
+ if (mUseQuickControls) {
+ super.captureTab(tab);
+ } else {
+ BrowserWebView web = (BrowserWebView) tab.getWebView();
+ if (web != null) {
+ tab.setScreenshot(web.capture());
+ }
+ }
}
- static class TouchProxy extends View {
+ void showNavScreen() {
+ if (mAnimating) return;
+ mAnimating = true;
+ mNavScreen = new NavScreen(mActivity, mUiController, this);
+ float yoffset = 0;
+ WebView web = getWebView();
+ if (web != null) {
+ yoffset = mNavScreen.getToolbarHeight() -
+ web.getVisibleTitleHeight();
+ }
+ // Add the custom view to its container.
+ mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_GRAVITY_CENTER);
+ mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ObjectAnimator animx = ObjectAnimator.ofFloat(mContentView,
+ "scaleX", 1.0f, NAV_TAB_SCALE);
+ ObjectAnimator animy = ObjectAnimator.ofFloat(mContentView,
+ "scaleY", 1.0f, NAV_TAB_SCALE);
+ ObjectAnimator translatey = ObjectAnimator.ofFloat(mContentView,
+ "translationY", 0, yoffset * NAV_TAB_SCALE);
+ AnimatorSet anims = new AnimatorSet();
+ anims.setDuration(200);
+ anims.addListener(new AnimatorListener() {
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
- View mTarget;
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishShowNavScreen();
+ }
- TouchProxy(Context context, View target) {
- super(context);
- mTarget = target;
- }
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- return mTarget.dispatchTouchEvent(event);
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+ });
+ anims.playTogether(animx, animy, translatey);
+ anims.start();
+ }
+
+ private void finishShowNavScreen() {
+ // Hide the content view.
+ mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mContentView.setVisibility(View.GONE);
+ mContentView.setScaleX(1.0f);
+ mContentView.setScaleY(1.0f);
+ mContentView.setTranslationY(0);
+ BrowserWebView web = (BrowserWebView) getWebView();
+ if (web != null) {
+ mActiveTab.setScreenshot(web.capture());
}
+ // Finally show the custom view container.
+ mCustomViewContainer.setVisibility(View.VISIBLE);
+ mCustomViewContainer.bringToFront();
+ mAnimating = false;
+ }
+
+ void hideNavScreen(boolean animateToPage) {
+ if (mAnimating || mNavScreen == null) return;
+ mAnimating = true;
+ mNavScreen.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (animateToPage) {
+ float yoffset = 0;
+ WebView web = mNavScreen.getSelectedTab().getWebView();
+ if (web != null) {
+ yoffset = mNavScreen.getToolbarHeight() -
+ web.getVisibleTitleHeight();
+ }
+ ObjectAnimator animx = ObjectAnimator.ofFloat(mNavScreen, "scaleX",
+ 1.0f, 1 / NAV_TAB_SCALE);
+ ObjectAnimator animy = ObjectAnimator.ofFloat(mNavScreen, "scaleY",
+ 1.0f, 1 / NAV_TAB_SCALE);
+ ObjectAnimator translatey = ObjectAnimator.ofFloat(mNavScreen,
+ "translationY", 0, -yoffset);
+ AnimatorSet anims = new AnimatorSet();
+ anims.setDuration(200);
+ anims.addListener(new AnimatorListener() {
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishHideNavScreen();
+ }
- WindowManager.LayoutParams getWindowLayoutParams() {
- WindowManager.LayoutParams params =
- new WindowManager.LayoutParams(
- mTarget.getWidth(),
- mTarget.getHeight(),
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSPARENT);
- params.gravity = Gravity.TOP | Gravity.LEFT;
- params.y = mTarget.getTop();
- params.x = mTarget.getLeft();
- return params;
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+ });
+ anims.playTogether(animx, animy, translatey);
+ anims.start();
+ } else {
+ finishHideNavScreen();
}
+
}
+
+ private void finishHideNavScreen() {
+ // Hide the custom view.
+ mNavScreen.setVisibility(View.GONE);
+ mNavScreen.setLayerType(View.LAYER_TYPE_NONE, null);
+ // Remove the custom view from its container.
+ mCustomViewContainer.removeView(mNavScreen);
+ mNavScreen = null;
+ mCustomViewContainer.setVisibility(View.GONE);
+ // Show the content view.
+ mContentView.setVisibility(View.VISIBLE);
+ mAnimating = false;
+ }
+
}
diff --git a/src/com/android/browser/PieControl.java b/src/com/android/browser/PieControl.java
index 38ed1bb..8bcd972 100644
--- a/src/com/android/browser/PieControl.java
+++ b/src/com/android/browser/PieControl.java
@@ -50,7 +50,7 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
private Activity mActivity;
private UiController mUiController;
- private XLargeUi mUi;
+ private BaseUi mUi;
private PieMenu mPie;
private PieItem mBack;
private PieItem mForward;
@@ -66,7 +66,7 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
private TextView mTabsCount;
private int mItemSize;
- public PieControl(Activity activity, UiController controller, XLargeUi ui) {
+ public PieControl(Activity activity, UiController controller, BaseUi ui) {
mActivity = activity;
mUiController = controller;
mUi = ui;
@@ -107,7 +107,7 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
menuview.setLayoutListener(new OnLayoutListener() {
@Override
public void onLayout(int ax, int ay, boolean left) {
- mActivity.openOptionsMenu();
+ buildMenu();
}
});
@@ -128,10 +128,10 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
// level 2
mPie.addItem(mForward);
mPie.addItem(mRefresh);
+ mPie.addItem(mOptions);
mPie.addItem(mShowTabs);
mPie.addItem(mNewTab);
mPie.addItem(mClose);
- mPie.addItem(mOptions);
mPie.setController(this);
}
container.addView(mPie);
@@ -142,11 +142,13 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
mUi.captureTab(mUi.getActiveTab());
mTabAdapter.setTabs(tabs);
PieStackView sym = (PieStackView) mShowTabs.getPieView();
- sym.setCurrent(mUiController.getTabControl().getCurrentIndex());
+ sym.setCurrent(mUiController.getTabControl().getCurrentPosition());
}
- protected void onMenuOpened(Menu menu) {
+ private void buildMenu() {
+ Menu menu = mUi.getMenu();
+ menu.setGroupVisible(R.id.NAV_MENU, false);
mMenuAdapter.setMenu(menu);
}
@@ -205,12 +207,12 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
web.reload();
}
} else if (mUrl.getView() == v) {
- mUi.showTitleBarAndEdit();
+ mUi.editUrl(false);
} else if (mBookmarks.getView() == v) {
mUiController.bookmarksOrHistoryPicker(false);
} else if (mNewTab.getView() == v) {
mUiController.openTabToHomePage();
- mUi.showTitleBarAndEdit();
+ mUi.editUrl(false);
} else if (mClose.getView() == v) {
mUiController.closeCurrentTab();
}
@@ -279,8 +281,7 @@ public class PieControl implements OnClickListener, PieMenu.PieController {
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- mUiController.switchToTab(mUiController.getTabControl()
- .getTabIndex(tab));
+ mUiController.switchToTab(tab);
}
});
return view;
diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java
new file mode 100644
index 0000000..cff9f70
--- /dev/null
+++ b/src/com/android/browser/PreferenceKeys.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 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;
+
+public interface PreferenceKeys {
+
+ static final String PREF_AUTOFILL_ACTIVE_PROFILE_ID = "autofill_active_profile_id";
+ static final String PREF_DEBUG_MENU = "debug_menu";
+
+ // ----------------------
+ // Keys for accessibility_preferences.xml
+ // ----------------------
+ static final String PREF_MIN_FONT_SIZE = "min_font_size";
+ static final String PREF_TEXT_SIZE = "text_size";
+ static final String PREF_FORCE_USERSCALABLE = "force_userscalable";
+
+ // ----------------------
+ // Keys for advanced_preferences.xml
+ // ----------------------
+ static final String PREF_AUTOFIT_PAGES = "autofit_pages";
+ static final String PREF_BLOCK_POPUP_WINDOWS = "block_popup_windows";
+ static final String PREF_DEFAULT_TEXT_ENCODING = "default_text_encoding";
+ static final String PREF_DEFAULT_ZOOM = "default_zoom";
+ static final String PREF_ENABLE_JAVASCRIPT = "enable_javascript";
+ static final String PREF_LOAD_IMAGES = "load_images";
+ static final String PREF_LOAD_PAGE = "load_page";
+ static final String PREF_OPEN_IN_BACKGROUND = "open_in_background";
+ static final String PREF_PLUGIN_STATE = "plugin_state";
+ static final String PREF_RESET_DEFAULT_PREFERENCES = "reset_default_preferences";
+ static final String PREF_SEARCH_ENGINE = "search_engine";
+ static final String PREF_WEBSITE_SETTINGS = "website_settings";
+
+ // ----------------------
+ // Keys for debug_preferences.xml
+ // ----------------------
+ static final String PREF_ENABLE_HARDWARE_ACCEL = "enable_hardware_accel";
+ static final String PREF_USER_AGENT = "user_agent";
+
+ // ----------------------
+ // Keys for general_preferences.xml
+ // ----------------------
+ static final String PREF_AUTOFILL_ENABLED = "autofill_enabled";
+ static final String PREF_AUTOFILL_PROFILE = "autofill_profile";
+ static final String PREF_HOMEPAGE = "homepage";
+ static final String PREF_SYNC_WITH_CHROME = "sync_with_chrome";
+
+ // ----------------------
+ // Keys for hidden_debug_preferences.xml
+ // ----------------------
+ static final String PREF_ENABLE_LIGHT_TOUCH = "enable_light_touch";
+ static final String PREF_ENABLE_NAV_DUMP = "enable_nav_dump";
+ static final String PREF_ENABLE_TRACING = "enable_tracing";
+ static final String PREF_ENABLE_VISUAL_INDICATOR = "enable_visual_indicator";
+ static final String PREF_JAVASCRIPT_CONSOLE = "javascript_console";
+ static final String PREF_JS_ENGINE_FLAGS = "js_engine_flags";
+ static final String PREF_NORMAL_LAYOUT = "normal_layout";
+ static final String PREF_SMALL_SCREEN = "small_screen";
+ static final String PREF_WIDE_VIEWPORT = "wide_viewport";
+
+ // ----------------------
+ // Keys for lab_preferences.xml
+ // ----------------------
+ static final String PREF_ENABLE_QUICK_CONTROLS = "enable_quick_controls";
+ static final String PREF_USE_MOST_VISITED_HOMEPAGE = "use_most_visited_homepage";
+ static final String PREF_USE_INSTANT_SEARCH = "use_instant_search";
+ static final String PREF_FULLSCREEN = "fullscreen";
+ static final String PREF_ENABLE_USERAGENT_SWITCHER = "enable_useragent_switcher";
+
+ // ----------------------
+ // Keys for privacy_security_preferences.xml
+ // ----------------------
+ static final String PREF_ACCEPT_COOKIES = "accept_cookies";
+ static final String PREF_ENABLE_GEOLOCATION = "enable_geolocation";
+ static final String PREF_PRIVACY_CLEAR_CACHE = "privacy_clear_cache";
+ static final String PREF_PRIVACY_CLEAR_COOKIES = "privacy_clear_cookies";
+ static final String PREF_PRIVACY_CLEAR_FORM_DATA = "privacy_clear_form_data";
+ static final String PREF_PRIVACY_CLEAR_GEOLOCATION_ACCESS = "privacy_clear_geolocation_access";
+ static final String PREF_PRIVACY_CLEAR_HISTORY = "privacy_clear_history";
+ static final String PREF_PRIVACY_CLEAR_PASSWORDS = "privacy_clear_passwords";
+ static final String PREF_REMEMBER_PASSWORDS = "remember_passwords";
+ static final String PREF_SAVE_FORMDATA = "save_formdata";
+ static final String PREF_SHOW_SECURITY_WARNINGS = "show_security_warnings";
+
+}
diff --git a/src/com/android/browser/ShortcutActivity.java b/src/com/android/browser/ShortcutActivity.java
index 16a4cbe..af1788d 100644
--- a/src/com/android/browser/ShortcutActivity.java
+++ b/src/com/android/browser/ShortcutActivity.java
@@ -38,8 +38,6 @@ public class ShortcutActivity extends Activity
mBookmarks = (BrowserBookmarksPage) getFragmentManager()
.findFragmentById(R.id.bookmarks);
mBookmarks.setEnableContextMenu(false);
- mBookmarks.setBreadCrumbMaxVisible(2);
- mBookmarks.setBreadCrumbUseBackButton(true);
mBookmarks.setCallbackListener(this);
View cancel = findViewById(R.id.cancel);
if (cancel != null) {
@@ -73,10 +71,6 @@ public class ShortcutActivity extends Activity
}
@Override
- public void onFolderChanged(int level, Uri uri) {
- }
-
- @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.cancel:
diff --git a/src/com/android/browser/SuggestionsAdapter.java b/src/com/android/browser/SuggestionsAdapter.java
index ecdaa15..242e170 100644
--- a/src/com/android/browser/SuggestionsAdapter.java
+++ b/src/com/android/browser/SuggestionsAdapter.java
@@ -71,6 +71,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
final Object mResultsLock = new Object();
List<String> mVoiceResults;
boolean mIncognitoMode;
+ BrowserSettings mSettings;
interface CompletionListener {
@@ -82,6 +83,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
public SuggestionsAdapter(Context ctx, CompletionListener listener) {
mContext = ctx;
+ mSettings = BrowserSettings.getInstance();
mListener = listener;
mLinesPortrait = mContext.getResources().
getInteger(R.integer.max_suggest_lines_portrait);
@@ -276,7 +278,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
}
private boolean shouldProcessEmptyQuery() {
- final SearchEngine searchEngine = BrowserSettings.getInstance().getSearchEngine();
+ final SearchEngine searchEngine = mSettings.getSearchEngine();
return searchEngine.wantsEmptyQuery();
}
@@ -470,7 +472,6 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
Uri.Builder ub = BrowserContract.Combined.CONTENT_URI.buildUpon();
ub.appendQueryParameter(BrowserContract.PARAM_LIMIT,
Integer.toString(Math.max(mLinesLandscape, mLinesPortrait)));
- BookmarkUtils.addAccountInfo(mContext, ub);
mCursor =
mContext.getContentResolver().query(ub.build(), COMBINED_PROJECTION,
selection,
@@ -541,7 +542,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
if (mCursor != null) {
mCursor.close();
}
- SearchEngine searchEngine = BrowserSettings.getInstance().getSearchEngine();
+ SearchEngine searchEngine = mSettings.getSearchEngine();
if (!TextUtils.isEmpty(constraint)) {
if (searchEngine != null && searchEngine.supportsSuggestions()) {
mCursor = searchEngine.getSuggestions(mContext, constraint.toString());
@@ -560,7 +561,7 @@ public class SuggestionsAdapter extends BaseAdapter implements Filterable,
}
private boolean useInstant() {
- return BrowserSettings.getInstance().useInstant();
+ return mSettings.useInstantSearch();
}
public void clearCache() {
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 863fc95..e1dd1ca 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -88,6 +88,9 @@ class Tab {
Activity mActivity;
private WebViewController mWebViewController;
+ // The tab ID
+ private long mId;
+
// The Geolocation permissions prompt
private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
// Main WebView wrapper
@@ -104,12 +107,10 @@ class Tab {
private Bundle mSavedState;
// Parent Tab. This is the Tab that created this Tab, or null if the Tab was
// created by the UI
- private Tab mParentTab;
+ private Tab mParent;
// Tab that constructed by this Tab. This is used when this Tab is
// destroyed, it clears all mParentTab values in the children.
- private Vector<Tab> mChildTabs;
- // If true, the tab will be removed when back out of the first page.
- private boolean mCloseOnExit;
+ private Vector<Tab> mChildren;
// If true, the tab is in the foreground of the current activity.
private boolean mInForeground;
// If true, the tab is in page loading state (after onPageStarted,
@@ -139,6 +140,7 @@ class Tab {
DownloadTouchIcon mTouchIconLoader;
private Bitmap mScreenshot;
+ private BrowserSettings mSettings;
// All the state needed for a page
private static class PageState {
@@ -182,18 +184,11 @@ class Tab {
private PageState mCurrentState;
// Used for saving and restoring each Tab
- // TODO: Figure out who uses what and where
- // Some of these aren't use in this class, and some are only used in
- // restoring state but not saving it - FIX THIS
- static final String WEBVIEW = "webview";
- static final String NUMTABS = "numTabs";
- static final String CURRTAB = "currentTab";
+ static final String ID = "ID";
static final String CURRURL = "currentUrl";
static final String CURRTITLE = "currentTitle";
- static final String CLOSEONEXIT = "closeonexit";
static final String PARENTTAB = "parentTab";
static final String APPID = "appid";
- static final String ORIGINALURL = "originalUrl";
static final String INCOGNITO = "privateBrowsingEnabled";
static final String SCREENSHOT = "screenshot";
@@ -313,7 +308,9 @@ class Tab {
mVoiceSearchData.mLastVoiceSearchTitle
= mVoiceSearchData.mVoiceSearchResults.get(index);
if (mInForeground) {
- mWebViewController.activateVoiceSearchMode(mVoiceSearchData.mLastVoiceSearchTitle);
+ mWebViewController.activateVoiceSearchMode(
+ mVoiceSearchData.mLastVoiceSearchTitle,
+ mVoiceSearchData.mVoiceSearchResults);
}
if (mVoiceSearchData.mVoiceSearchHtmls != null) {
// When index was found it was already ensured that it was valid
@@ -709,7 +706,7 @@ class Tab {
setLockIconType(LockIcon.LOCK_ICON_UNSECURE);
return;
}
- if (BrowserSettings.getInstance().showSecurityWarnings()) {
+ if (mSettings.showSecurityWarnings()) {
final LayoutInflater factory =
LayoutInflater.from(mActivity);
final View warningsView =
@@ -856,9 +853,9 @@ class Tab {
mWebViewController.attachSubWindow(Tab.this);
transport.setWebView(mSubView);
} else {
- final Tab newTab = mWebViewController.openTabAndShow(
- Tab.this,
- IntentHandler.EMPTY_URL_DATA, false, null);
+ final Tab newTab = mWebViewController.openTab(null,
+ Tab.this.isPrivateBrowsingEnabled(),
+ true, true);
if (newTab != Tab.this) {
Tab.this.addChildTab(newTab);
}
@@ -935,18 +932,16 @@ class Tab {
@Override
public void onRequestFocus(WebView view) {
if (!mInForeground) {
- mWebViewController.switchToTab(mWebViewController.getTabControl().getTabIndex(
- Tab.this));
+ mWebViewController.switchToTab(Tab.this);
}
}
@Override
public void onCloseWindow(WebView window) {
- if (mParentTab != null) {
+ if (mParent != null) {
// JavaScript can only close popup window.
if (mInForeground) {
- mWebViewController.switchToTab(mWebViewController.getTabControl()
- .getTabIndex(mParentTab));
+ mWebViewController.switchToTab(mParent);
}
mWebViewController.closeTab(Tab.this);
}
@@ -1015,7 +1010,7 @@ class Tab {
public void onExceededDatabaseQuota(String url,
String databaseIdentifier, long currentQuota, long estimatedSize,
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
- BrowserSettings.getInstance().getWebStorageSizeManager()
+ mSettings.getWebStorageSizeManager()
.onExceededDatabaseQuota(url, databaseIdentifier,
currentQuota, estimatedSize, totalUsedQuota,
quotaUpdater);
@@ -1034,7 +1029,7 @@ class Tab {
@Override
public void onReachedMaxAppCacheSize(long spaceNeeded,
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
- BrowserSettings.getInstance().getWebStorageSizeManager()
+ mSettings.getWebStorageSizeManager()
.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota,
quotaUpdater);
}
@@ -1172,10 +1167,7 @@ class Tab {
if (disableAutoFill.isChecked()) {
// Disable autofill and show a toast with how to turn it on again.
- BrowserSettings s = BrowserSettings.getInstance();
- s.addObserver(mMainView.getSettings());
- s.disableAutoFill(mActivity);
- s.update();
+ mSettings.setAutofillEnabled(false);
Toast.makeText(mActivity,
R.string.autofill_setup_dialog_negative_toast,
Toast.LENGTH_LONG).show();
@@ -1290,14 +1282,13 @@ class Tab {
// remove later
// Construct a new tab
- Tab(WebViewController wvcontroller, WebView w, boolean closeOnExit, String appId,
- String url) {
+ Tab(WebViewController wvcontroller, WebView w) {
mWebViewController = wvcontroller;
mActivity = mWebViewController.getActivity();
- mCloseOnExit = closeOnExit;
- mAppId = appId;
+ mSettings = BrowserSettings.getInstance();
mDataController = DataController.getInstance(mActivity);
- mCurrentState = new PageState(mActivity, w.isPrivateBrowsingEnabled());
+ mCurrentState = new PageState(mActivity, w != null
+ ? w.isPrivateBrowsingEnabled() : false);
mInPageLoad = false;
mInForeground = false;
@@ -1328,6 +1319,14 @@ class Tab {
setWebView(w);
}
+ public void setId(long id) {
+ mId = id;
+ }
+
+ public long getId() {
+ return mId;
+ }
+
/**
* Sets the WebView for this tab, correctly removing the old WebView from
* the container view.
@@ -1366,7 +1365,6 @@ class Tab {
void destroy() {
if (mMainView != null) {
dismissSubWindow();
- BrowserSettings.getInstance().deleteObserver(mMainView.getSettings());
// save the WebView to call destroy() after detach it from the tab
WebView webView = mMainView;
setWebView(null);
@@ -1379,14 +1377,14 @@ class Tab {
*/
void removeFromTree() {
// detach the children
- if (mChildTabs != null) {
- for(Tab t : mChildTabs) {
- t.setParentTab(null);
+ if (mChildren != null) {
+ for(Tab t : mChildren) {
+ t.setParent(null);
}
}
// remove itself from the parent list
- if (mParentTab != null) {
- mParentTab.mChildTabs.remove(this);
+ if (mParent != null) {
+ mParent.mChildren.remove(this);
}
}
@@ -1428,8 +1426,6 @@ class Tab {
void dismissSubWindow() {
if (mSubView != null) {
mWebViewController.endActionMode();
- BrowserSettings.getInstance().deleteObserver(
- mSubView.getSettings());
mSubView.destroy();
mSubView = null;
mSubViewContainer = null;
@@ -1440,37 +1436,45 @@ class Tab {
/**
* Set the parent tab of this tab.
*/
- void setParentTab(Tab parent) {
- mParentTab = parent;
+ void setParent(Tab parent) {
+ mParent = parent;
// This tab may have been freed due to low memory. If that is the case,
- // the parent tab index is already saved. If we are changing that index
+ // the parent tab id is already saved. If we are changing that id
// (most likely due to removing the parent tab) we must update the
- // parent tab index in the saved Bundle.
+ // parent tab id in the saved Bundle.
if (mSavedState != null) {
if (parent == null) {
mSavedState.remove(PARENTTAB);
} else {
- mSavedState.putInt(PARENTTAB, mWebViewController.getTabControl()
- .getTabIndex(parent));
+ mSavedState.putLong(PARENTTAB, parent.getId());
}
}
}
/**
+ * If this Tab was created through another Tab, then this method returns
+ * that Tab.
+ * @return the Tab parent or null
+ */
+ public Tab getParent() {
+ return mParent;
+ }
+
+ /**
* When a Tab is created through the content of another Tab, then we
* associate the Tabs.
* @param child the Tab that was created from this Tab
*/
void addChildTab(Tab child) {
- if (mChildTabs == null) {
- mChildTabs = new Vector<Tab>();
+ if (mChildren == null) {
+ mChildren = new Vector<Tab>();
}
- mChildTabs.add(child);
- child.setParentTab(this);
+ mChildren.add(child);
+ child.setParent(this);
}
- Vector<Tab> getChildTabs() {
- return mChildTabs;
+ Vector<Tab> getChildren() {
+ return mChildren;
}
void resume() {
@@ -1658,24 +1662,6 @@ class Tab {
return mErrorConsole;
}
- /**
- * If this Tab was created through another Tab, then this method returns
- * that Tab.
- * @return the Tab parent or null
- */
- public Tab getParentTab() {
- return mParentTab;
- }
-
- /**
- * Return whether this tab should be closed when it is backing out of the
- * first page.
- * @return TRUE if this tab should be closed when exit.
- */
- boolean closeOnExit() {
- return mCloseOnExit;
- }
-
private void setLockIconType(LockIcon icon) {
mCurrentState.mLockIcon = icon;
mWebViewController.onUpdatedLockIcon(this);
@@ -1740,16 +1726,15 @@ class Tab {
// Store some extra info for displaying the tab in the picker.
final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
+ mSavedState.putLong(ID, mId);
mSavedState.putString(CURRURL, mCurrentState.mUrl);
mSavedState.putString(CURRTITLE, mCurrentState.mTitle);
- mSavedState.putBoolean(CLOSEONEXIT, mCloseOnExit);
if (mAppId != null) {
mSavedState.putString(APPID, mAppId);
}
// Remember the parent tab so the relationship can be restored.
- if (mParentTab != null) {
- mSavedState.putInt(PARENTTAB, mWebViewController.getTabControl().getTabIndex(
- mParentTab));
+ if (mParent != null) {
+ mSavedState.putLong(PARENTTAB, mParent.mId);
}
if (mScreenshot != null) {
mSavedState.putParcelable(SCREENSHOT, mScreenshot);
@@ -1767,7 +1752,7 @@ class Tab {
// Restore the internal state even if the WebView fails to restore.
// This will maintain the app id, original url and close-on-exit values.
mSavedState = null;
- mCloseOnExit = b.getBoolean(CLOSEONEXIT);
+ mId = b.getLong(ID);
mAppId = b.getString(APPID);
mScreenshot = b.getParcelable(SCREENSHOT);
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index 7abb203..6c3949a 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -16,7 +16,7 @@
package com.android.browser;
-import com.android.browser.ScrollWebView.ScrollListener;
+import com.android.browser.BrowserWebView.ScrollListener;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
@@ -166,7 +166,7 @@ public class TabBar extends LinearLayout
TabView tv = buildTabView(tab);
mTabs.addTab(tv);
}
- mTabs.setSelectedTab(mTabControl.getCurrentIndex());
+ mTabs.setSelectedTab(mTabControl.getCurrentPosition());
}
@Override
@@ -213,7 +213,7 @@ public class TabBar extends LinearLayout
mUi.hideTitleBar();
} else {
mUi.stopWebViewScrolling();
- mUi.showTitleBarAndEdit();
+ mUi.editUrl(false);
}
} else if (mUi.isTitleBarShowing() && !isLoading()) {
mUi.stopEditingUrl();
@@ -221,11 +221,12 @@ public class TabBar extends LinearLayout
} else {
showUrlBar();
}
- } else {
+ } else if (view instanceof TabView) {
+ final Tab tab = ((TabView) view).mTab;
int ix = mTabs.getChildIndex(view);
if (ix >= 0) {
mTabs.setSelectedTab(ix);
- mUiController.switchToTab(ix);
+ mUiController.switchToTab(tab);
}
}
}
@@ -616,7 +617,7 @@ public class TabBar extends LinearLayout
// TabChangeListener implementation
public void onSetActiveTab(Tab tab) {
- mTabs.setSelectedTab(mTabControl.getTabIndex(tab));
+ mTabs.setSelectedTab(mTabControl.getTabPosition(tab));
TabView tv = mTabMap.get(tab);
if (tv != null) {
tv.setProgress(tv.mTab.getLoadProgress());
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index af9928a..1fe9053 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -16,11 +16,8 @@
package com.android.browser;
-import com.android.browser.IntentHandler.UrlData;
-
import android.os.Bundle;
import android.util.Log;
-import android.webkit.WebBackForwardList;
import android.webkit.WebView;
import java.io.File;
@@ -32,6 +29,13 @@ import java.util.Vector;
class TabControl {
// Log Tag
private static final String LOGTAG = "TabControl";
+
+ // next Tab ID
+ private static long sNextId = 0;
+
+ private static final String POSITIONS = "positions";
+ private static final String CURRENT = "current";
+
// Maximum number of tabs.
private int mMaxTabs;
// Private array of WebViews that are used as tabs.
@@ -57,6 +61,10 @@ class TabControl {
mTabQueue = new ArrayList<Tab>(mMaxTabs);
}
+ static long getNextId() {
+ return sNextId++;
+ }
+
File getThumbnailDir() {
return mThumbnailDir;
}
@@ -107,13 +115,13 @@ class TabControl {
}
/**
- * Return the tab at the specified index.
- * @return The Tab for the specified index or null if the tab does not
+ * Return the tab at the specified position.
+ * @return The Tab for the specified position or null if the tab does not
* exist.
*/
- Tab getTab(int index) {
- if (index >= 0 && index < mTabs.size()) {
- return mTabs.get(index);
+ Tab getTab(int position) {
+ if (position >= 0 && position < mTabs.size()) {
+ return mTabs.get(position);
}
return null;
}
@@ -127,19 +135,19 @@ class TabControl {
}
/**
- * Return the current tab index.
- * @return The current tab index
+ * Return the current tab position.
+ * @return The current tab position
*/
- int getCurrentIndex() {
+ int getCurrentPosition() {
return mCurrentTab;
}
/**
- * Given a Tab, find it's index
+ * Given a Tab, find it's position
* @param Tab to find
- * @return index of Tab or -1 if not found
+ * @return position of Tab or -1 if not found
*/
- int getTabIndex(Tab tab) {
+ int getTabPosition(Tab tab) {
if (tab == null) {
return -1;
}
@@ -156,7 +164,8 @@ class TabControl {
*/
boolean hasAnyOpenIncognitoTabs() {
for (Tab tab : mTabs) {
- if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
+ if (tab.getWebView() != null
+ && tab.getWebView().isPrivateBrowsingEnabled()) {
return true;
}
}
@@ -168,8 +177,7 @@ class TabControl {
* @return The newly createTab or null if we have reached the maximum
* number of open tabs.
*/
- Tab createNewTab(boolean closeOnExit, String appId, String url,
- boolean privateBrowsing) {
+ Tab createNewTab(boolean privateBrowsing) {
int size = mTabs.size();
// Return false if we have maxed out on tabs
if (mMaxTabs == size) {
@@ -178,7 +186,8 @@ class TabControl {
final WebView w = createNewWebView(privateBrowsing);
// Create a new tab and add it to the tab list
- Tab t = new Tab(mController, w, closeOnExit, appId, url);
+ Tab t = new Tab(mController, w);
+ t.setId(getNextId());
mTabs.add(t);
// Initially put the tab in the background.
t.putInBackground();
@@ -190,7 +199,7 @@ class TabControl {
* appId(null), url(null), and privateBrowsing(false).
*/
Tab createNewTab() {
- return createNewTab(false, null, null, false);
+ return createNewTab(false);
}
/**
@@ -225,7 +234,7 @@ class TabControl {
} else {
// If a tab that is earlier in the list gets removed, the current
// index no longer points to the correct tab.
- mCurrentTab = getTabIndex(current);
+ mCurrentTab = getTabPosition(current);
}
// destroy the tab
@@ -233,17 +242,6 @@ class TabControl {
// clear it's references to parent and children
t.removeFromTree();
- // The tab indices have shifted, update all the saved state so we point
- // to the correct index.
- for (Tab tab : mTabs) {
- Vector<Tab> children = tab.getChildTabs();
- if (children != null) {
- for (Tab child : children) {
- child.setParentTab(tab);
- }
- }
- }
-
// Remove it from the queue of viewed tabs.
mTabQueue.remove(t);
return true;
@@ -268,61 +266,59 @@ class TabControl {
return mTabs.size();
}
-
/**
- * Save the state of all the Tabs.
- * @param outState The Bundle to save the state to.
+ * save the tab state:
+ * current position
+ * position sorted array of tab ids
+ * for each tab id, save the tab state
+ * @param outState
*/
void saveState(Bundle outState) {
final int numTabs = getTabCount();
- outState.putInt(Tab.NUMTABS, numTabs);
- final int index = getCurrentIndex();
- outState.putInt(Tab.CURRTAB, (index >= 0 && index < numTabs) ? index : 0);
- for (int i = 0; i < numTabs; i++) {
- final Tab t = getTab(i);
- if (t.saveState()) {
- outState.putBundle(Tab.WEBVIEW + i, t.getSavedState());
+ long[] ids = new long[numTabs];
+ int i = 0;
+ for (Tab tab : mTabs) {
+ ids[i++] = tab.getId();
+ if (tab.saveState()) {
+ outState.putBundle(Long.toString(tab.getId()), tab.getSavedState());
}
}
+ outState.putLongArray(POSITIONS, ids);
+ final long cid = getCurrentTab().getId();
+ outState.putLong(CURRENT, cid);
}
/**
* Check if the state can be restored. If the state can be restored, the
- * current tab index is returned. This can be passed to restoreState below
+ * current tab id is returned. This can be passed to restoreState below
* in order to restore the correct tab. Otherwise, -1 is returned and the
* state cannot be restored.
*/
- int canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
- final int numTabs = (inState == null)
- ? - 1 : inState.getInt(Tab.NUMTABS, -1);
- if (numTabs == -1) {
+ long canRestoreState(Bundle inState, boolean restoreIncognitoTabs) {
+ final long[] ids = (inState == null) ? null : inState.getLongArray(POSITIONS);
+ if (ids == null) {
return -1;
}
- final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
-
- // Determine whether the saved current tab can be restored, and if not,
- // which tab will take its place.
- int currentTab = -1;
+ final long oldcurrent = inState.getLong(CURRENT);
+ long current = -1;
if (restoreIncognitoTabs ||
- !inState.getBundle(Tab.WEBVIEW + oldCurrentTab)
- .getBoolean(Tab.INCOGNITO)) {
- currentTab = oldCurrentTab;
+ !inState.getBundle(Long.toString(oldcurrent)).getBoolean(Tab.INCOGNITO)) {
+ current = oldcurrent;
} else {
- for (int i = 0; i < numTabs; i++) {
- if (!inState.getBundle(Tab.WEBVIEW + i)
- .getBoolean(Tab.INCOGNITO)) {
- currentTab = i;
+ // pick first non incognito tab
+ for (long id : ids) {
+ if (!inState.getBundle(Long.toString(id)).getBoolean(Tab.INCOGNITO)) {
+ current = id;
break;
}
}
}
-
- return currentTab;
+ return current;
}
/**
* Restore the state of all the tabs.
- * @param currentTab The tab index to restore.
+ * @param currentId The tab id to restore.
* @param inState The saved state of all the tabs.
* @param restoreIncognitoTabs Restoring private browsing tabs
* @param restoreAll All webviews get restored, not just the current tab
@@ -330,29 +326,29 @@ class TabControl {
* @return True if there were previous tabs that were restored. False if
* there was no saved state or restoring the state failed.
*/
- void restoreState(Bundle inState, int currentTab,
+ void restoreState(Bundle inState, long currentId,
boolean restoreIncognitoTabs, boolean restoreAll) {
- if (currentTab == -1) {
+ if (currentId == -1) {
return;
}
-
- // If currentTab is valid, numTabs must be present.
- final int numTabs = inState.getInt(Tab.NUMTABS, -1);
-
- // Map saved tab indices to new indices, in case any incognito tabs
- // need to not be restored.
- HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
- originalTabIndices.put(-1, -1);
- for (int i = 0; i < numTabs; i++) {
- Bundle state = inState.getBundle(Tab.WEBVIEW + i);
-
- if (!restoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
- originalTabIndices.put(i, -1);
- } else if (i == currentTab || restoreAll) {
+ long[] ids = inState.getLongArray(POSITIONS);
+ long maxId = -Long.MAX_VALUE;
+ HashMap<Long, Tab> tabMap = new HashMap<Long, Tab>();
+ for (long id : ids) {
+ if (id > maxId) {
+ maxId = id;
+ }
+ final String idkey = Long.toString(id);
+ Bundle state = inState.getBundle(idkey);
+ if (!restoreIncognitoTabs && state != null
+ && state.getBoolean(Tab.INCOGNITO)) {
+ // ignore tab
+ } else if (id == currentId || restoreAll) {
Tab t = createNewTab();
+ tabMap.put(id, t);
// Me must set the current tab before restoring the state
// so that all the client classes are set.
- if (i == currentTab) {
+ if (id == currentId) {
setCurrentTab(t);
}
if (!t.restoreState(state)) {
@@ -360,11 +356,12 @@ class TabControl {
t.getWebView().loadUrl(BrowserSettings.getInstance()
.getHomePage());
}
- originalTabIndices.put(i, getTabCount() - 1);
} else {
// Create a new tab and don't restore the state yet, add it
// to the tab list
- Tab t = new Tab(mController, null, false, null, null);
+ Tab t = new Tab(mController, null);
+ t.setId(id);
+ tabMap.put(id, t);
if (state != null) {
t.setSavedState(state);
// Need to maintain the app id and original url so we
@@ -374,21 +371,22 @@ class TabControl {
mTabs.add(t);
// added the tab to the front as they are not current
mTabQueue.add(0, t);
- originalTabIndices.put(i, getTabCount() - 1);
}
- }
-
- // Rebuild the tree of tabs. Do this after all tabs have been
- // created/restored so that the parent tab exists.
- for (int i = 0; i < numTabs; i++) {
- final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
- final Tab t = getTab(i);
- if (b != null && t != null) {
- final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
- if (parentIndex != -1) {
- final Tab parent = getTab(parentIndex);
+ // make sure that there is no id overlap between the restored
+ // and new tabs
+ sNextId = maxId + 1;
+
+ }
+ // restore parent/child relationships
+ for (long id : ids) {
+ final Tab tab = tabMap.get(id);
+ final Bundle b = inState.getBundle(Long.toString(id));
+ if ((b != null) && (tab != null)) {
+ final long parentId = b.getLong(Tab.PARENTTAB, -1);
+ if (parentId != -1) {
+ final Tab parent = tabMap.get(parentId);
if (parent != null) {
- parent.addChildTab(t);
+ parent.addChildTab(tab);
}
}
}
@@ -443,7 +441,7 @@ class TabControl {
for (Tab t : mTabQueue) {
if (t != null && t.getWebView() != null) {
openTabCount++;
- if (t != current && t != current.getParentTab()) {
+ if (t != current && t != current.getParent()) {
tabsToGo.add(t);
}
}
@@ -462,9 +460,7 @@ class TabControl {
* @param view The WebView used to find the tab.
*/
Tab getTabFromView(WebView view) {
- final int size = getTabCount();
- for (int i = 0; i < size; i++) {
- final Tab t = getTab(i);
+ for (Tab t : mTabs) {
if (t.getSubWebView() == view || t.getWebView() == view) {
return t;
}
@@ -476,13 +472,11 @@ class TabControl {
* Return the tab with the matching application id.
* @param id The application identifier.
*/
- Tab getTabFromId(String id) {
+ Tab getTabFromAppId(String id) {
if (id == null) {
return null;
}
- final int size = getTabCount();
- for (int i = 0; i < size; i++) {
- final Tab t = getTab(i);
+ for (Tab t : mTabs) {
if (id.equals(t.getAppId())) {
return t;
}
@@ -494,9 +488,7 @@ class TabControl {
* Stop loading in all opened WebView including subWindows.
*/
void stopAllLoading() {
- final int size = getTabCount();
- for (int i = 0; i < size; i++) {
- final Tab t = getTab(i);
+ for (Tab t : mTabs) {
final WebView webview = t.getWebView();
if (webview != null) {
webview.stopLoading();
@@ -539,10 +531,8 @@ class TabControl {
return t;
}
// Now check all the rest.
- final int size = getTabCount();
- for (int i = 0; i < size; i++) {
- t = getTab(i);
- if (tabMatchesUrl(t, url)) {
+ for (Tab tab : mTabs) {
+ if (tabMatchesUrl(tab, url)) {
return t;
}
}
diff --git a/src/com/android/browser/TitleBar.java b/src/com/android/browser/TitleBar.java
deleted file mode 100644
index 686416c..0000000
--- a/src/com/android/browser/TitleBar.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.speech.RecognizerIntent;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.style.ImageSpan;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-
-/**
- * This class represents a title bar for a particular "tab" or "window" in the
- * browser.
- */
-public class TitleBar extends TitleBarBase implements OnFocusChangeListener,
- OnClickListener {
-
- private Activity mActivity;
- private ImageButton mBookmarkButton;
- private PageProgressView mHorizontalProgress;
- private ImageButton mStopButton;
- private Drawable mBookmarkDrawable;
- private Drawable mVoiceDrawable;
- private boolean mInLoad;
- private Intent mVoiceSearchIntent;
- private ImageSpan mArcsSpan;
-
- public TitleBar(Activity activity, UiController controller, PhoneUi ui) {
- super(activity, controller, ui);
- LayoutInflater factory = LayoutInflater.from(activity);
- factory.inflate(R.layout.title_bar, this);
- mActivity = activity;
-
- mUrlInput = (UrlInputView) findViewById(R.id.url_input);
- mUrlInput.setCompoundDrawablePadding(5);
- mUrlInput.setContainer(this);
- mUrlInput.setSelectAllOnFocus(true);
- mUrlInput.setController(mUiController);
- mUrlInput.setUrlInputListener(this);
- mUrlInput.setOnFocusChangeListener(this);
-
- mLockIcon = (ImageView) findViewById(R.id.lock);
- mFavicon = (ImageView) findViewById(R.id.favicon);
- mStopButton = (ImageButton) findViewById(R.id.stop);
- mBookmarkButton = (ImageButton) findViewById(R.id.bookmark);
- mStopButton.setOnClickListener(this);
- mBookmarkButton.setOnClickListener(this);
-
- mHorizontalProgress = (PageProgressView) findViewById(
- R.id.progress_horizontal);
- mVoiceSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
- mVoiceSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
- RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
- // This extra tells voice search not to send the application id in its
- // results intent - http://b/2546173
- //
- // TODO: Make a constant for this extra.
- mVoiceSearchIntent.putExtra("android.speech.extras.SEND_APPLICATION_ID_EXTRA",
- false);
- PackageManager pm = activity.getPackageManager();
- ResolveInfo ri = pm.resolveActivity(mVoiceSearchIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- Resources resources = getResources();
- if (ri == null) {
- mVoiceSearchIntent = null;
- } else {
- mVoiceDrawable = resources.getDrawable(
- android.R.drawable.ic_btn_speak_now);
- }
- mBookmarkDrawable = mBookmarkButton.getDrawable();
- mArcsSpan = new ImageSpan(activity, R.drawable.arcs,
- ImageSpan.ALIGN_BASELINE);
- }
-
- @Override
- public void createContextMenu(ContextMenu menu) {
- MenuInflater inflater = mActivity.getMenuInflater();
- inflater.inflate(R.menu.title_context, menu);
- mActivity.onCreateContextMenu(menu, this, null);
- }
-
- /**
- * Change the TitleBar to or from voice mode. If there is no package to
- * handle voice search, the TitleBar cannot be set to voice mode.
- */
- @Override
- void setInVoiceMode(boolean inVoiceMode) {
- if (mInVoiceMode == inVoiceMode) return;
- mInVoiceMode = inVoiceMode && mVoiceSearchIntent != null;
- Drawable titleDrawable;
- if (mInVoiceMode) {
- mBookmarkButton.setImageDrawable(mVoiceDrawable);
- mUrlInput.setEllipsize(null);
- mBookmarkButton.setVisibility(View.VISIBLE);
- mStopButton.setVisibility(View.GONE);
- } else {
- if (mInLoad) {
- mBookmarkButton.setVisibility(View.GONE);
- mStopButton.setVisibility(View.VISIBLE);
- } else {
- mBookmarkButton.setVisibility(View.VISIBLE);
- mStopButton.setVisibility(View.GONE);
- mBookmarkButton.setImageDrawable(mBookmarkDrawable);
- }
- mUrlInput.setEllipsize(TextUtils.TruncateAt.END);
- }
- mUrlInput.setSingleLine(!mInVoiceMode);
- }
-
- /**
- * Update the progress, from 0 to 100.
- */
- @Override
- void setProgress(int newProgress) {
- if (newProgress >= PROGRESS_MAX) {
- mHorizontalProgress.setVisibility(View.GONE);
- if (!mInVoiceMode) {
- mBookmarkButton.setImageDrawable(mBookmarkDrawable);
- mBookmarkButton.setVisibility(View.VISIBLE);
- mStopButton.setVisibility(View.GONE);
- }
- mInLoad = false;
- } else {
- mHorizontalProgress.setProgress(newProgress * PageProgressView.MAX_PROGRESS
- / PROGRESS_MAX);
- if (!mInLoad) {
- mHorizontalProgress.setVisibility(View.VISIBLE);
- if (!mInVoiceMode) {
- mBookmarkButton.setVisibility(View.GONE);
- mStopButton.setVisibility(View.VISIBLE);
- }
- mInLoad = true;
- }
- }
- }
-
- /**
- * Update the text displayed in the title bar.
- * @param title String to display. If null, the new tab string will be
- * shown.
- */
- @Override
- void setDisplayTitle(String title) {
- if (title == null) {
- mUrlInput.setText(R.string.new_tab);
- } else {
- if (mInVoiceMode) {
- // Add two spaces. The second one will be replaced with an
- // image, and the first one will put space between it and the
- // text
- SpannableString spannable = new SpannableString(title + " ");
- int end = spannable.length();
- spannable.setSpan(mArcsSpan, end - 1, end,
- Spanned.SPAN_MARK_POINT);
- mUrlInput.setText(spannable);
- } else {
- mUrlInput.setText(title);
- }
- }
- }
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (v == mUrlInput && hasFocus) {
- mActivity.closeOptionsMenu();
- }
- }
-
- @Override
- public void onClick(View v) {
- if (v == mStopButton) {
- mUiController.stopLoading();
- } else if (v == mBookmarkButton) {
- mUiController.bookmarkCurrentPage(AddBookmarkPage.DEFAULT_FOLDER_ID,
- true);
- }
- }
-
- @Override
- public void setCurrentUrlIsBookmark(boolean isBookmark) {
- mBookmarkButton.setActivated(isBookmark);
- }
-}
diff --git a/src/com/android/browser/TitleBarBase.java b/src/com/android/browser/TitleBarBase.java
index b905d4e..4dc960c 100644
--- a/src/com/android/browser/TitleBarBase.java
+++ b/src/com/android/browser/TitleBarBase.java
@@ -16,27 +16,51 @@
package com.android.browser;
+import com.android.browser.UI.DropdownChangeListener;
import com.android.browser.UrlInputView.UrlInputListener;
+import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
import android.speech.RecognizerResultsIntent;
+import android.text.TextUtils;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.webkit.WebView;
+import android.widget.AbsoluteLayout;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import java.util.List;
/**
* Base class for a title bar used by the browser.
*/
-public class TitleBarBase extends LinearLayout implements UrlInputListener {
+public class TitleBarBase extends RelativeLayout
+ implements OnClickListener, OnFocusChangeListener, UrlInputListener,
+ TextChangeWatcher, DeviceAccountLogin.AutoLoginCallback {
protected static final int PROGRESS_MAX = 100;
@@ -44,22 +68,206 @@ public class TitleBarBase extends LinearLayout implements UrlInputListener {
protected ImageView mFavicon;
protected ImageView mLockIcon;
- protected Drawable mGenericFavicon;
protected UiController mUiController;
protected BaseUi mBaseUi;
+ protected FrameLayout mParent;
+ protected PageProgressView mProgress;
protected UrlInputView mUrlInput;
protected boolean mInVoiceMode;
+ protected View mContainer;
+
+
+ // Auto-login UI
+ protected View mAutoLogin;
+ protected Spinner mAutoLoginAccount;
+ protected Button mAutoLoginLogin;
+ protected ProgressBar mAutoLoginProgress;
+ protected TextView mAutoLoginError;
+ protected View mAutoLoginCancel;
+ protected DeviceAccountLogin mAutoLoginHandler;
+ protected ArrayAdapter<String> mAccountsAdapter;
+ protected boolean mUseQuickControls;
- public TitleBarBase(Context context, UiController controller, BaseUi ui) {
+ //state
+ protected boolean mShowing;
+ protected boolean mInLoad;
+ protected boolean mSkipTitleBarAnimations;
+ private Animator mTitleBarAnimator;
+
+ public TitleBarBase(Context context, UiController controller, BaseUi ui,
+ FrameLayout parent) {
super(context, null);
mUiController = controller;
mBaseUi = ui;
- mGenericFavicon = context.getResources().getDrawable(
- R.drawable.app_web_browser_sm);
+ mParent = parent;
+ }
+
+ protected void initLayout(Context context, int layoutId) {
+ LayoutInflater factory = LayoutInflater.from(context);
+ factory.inflate(layoutId, this);
+ mContainer = findViewById(R.id.taburlbar);
+ mProgress = (PageProgressView) findViewById(R.id.progress);
+ mUrlInput = (UrlInputView) findViewById(R.id.url);
+ mLockIcon = (ImageView) findViewById(R.id.lock);
+ mUrlInput.setUrlInputListener(this);
+ mUrlInput.setController(mUiController);
+ mUrlInput.setOnFocusChangeListener(this);
+ mUrlInput.setSelectAllOnFocus(true);
+ mUrlInput.addQueryTextWatcher(this);
+ mAutoLogin = findViewById(R.id.autologin);
+ mAutoLoginAccount = (Spinner) findViewById(R.id.autologin_account);
+ mAutoLoginLogin = (Button) findViewById(R.id.autologin_login);
+ mAutoLoginLogin.setOnClickListener(this);
+ mAutoLoginProgress = (ProgressBar) findViewById(R.id.autologin_progress);
+ mAutoLoginError = (TextView) findViewById(R.id.autologin_error);
+ mAutoLoginCancel = mAutoLogin.findViewById(R.id.autologin_close);
+ mAutoLoginCancel.setOnClickListener(this);
+ }
+
+ protected void setupUrlInput() {
+ }
+
+ protected void setUseQuickControls(boolean use) {
+ mUseQuickControls = use;
+ setLayoutParams(makeLayoutParams());
+ }
+
+ void setShowProgressOnly(boolean progress) {
+ if (progress && !inAutoLogin()) {
+ mContainer.setVisibility(View.GONE);
+ } else {
+ mContainer.setVisibility(View.VISIBLE);
+ }
+ }
+
+ void setSkipTitleBarAnimations(boolean skip) {
+ mSkipTitleBarAnimations = skip;
+ }
+
+ void show() {
+ if (mUseQuickControls) {
+ mParent.addView(this);
+ } else {
+ if (!mSkipTitleBarAnimations) {
+ cancelTitleBarAnimation(false);
+ int visibleHeight = getVisibleTitleHeight();
+ float startPos = (-getEmbeddedHeight() + visibleHeight);
+ if (getTranslationY() != 0) {
+ startPos = Math.max(startPos, getTranslationY());
+ }
+ mTitleBarAnimator = ObjectAnimator.ofFloat(this,
+ "translationY",
+ startPos, 0);
+ mTitleBarAnimator.start();
+ }
+ mBaseUi.setTitleGravity(Gravity.TOP);
+ }
+ mShowing = true;
+ }
+
+ void hide() {
+ if (mUseQuickControls) {
+ mParent.removeView(this);
+ } else {
+ if (!mSkipTitleBarAnimations) {
+ cancelTitleBarAnimation(false);
+ int visibleHeight = getVisibleTitleHeight();
+ mTitleBarAnimator = ObjectAnimator.ofFloat(this,
+ "translationY", getTranslationY(),
+ (-getEmbeddedHeight() + visibleHeight));
+ mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
+ mTitleBarAnimator.start();
+ } else {
+ mBaseUi.setTitleGravity(Gravity.NO_GRAVITY);
+ }
+ }
+ mShowing = false;
+ }
+
+ boolean isShowing() {
+ return mShowing;
+ }
+
+ void cancelTitleBarAnimation(boolean reset) {
+ if (mTitleBarAnimator != null) {
+ mTitleBarAnimator.cancel();
+ mTitleBarAnimator = null;
+ }
+ if (reset) {
+ setTranslationY(0);
+ }
+ }
+
+ private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
+
+ boolean mWasCanceled;
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCanceled = false;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mWasCanceled) {
+ setTranslationY(0);
+ }
+ mBaseUi.setTitleGravity(Gravity.NO_GRAVITY);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCanceled = true;
+ }
+ };
+
+ private int getVisibleTitleHeight() {
+ Tab tab = mBaseUi.getActiveTab();
+ WebView webview = tab != null ? tab.getWebView() : null;
+ return webview != null ? webview.getVisibleTitleHeight() : 0;
}
- /* package */ void setProgress(int newProgress) {}
- /* package */ void setDisplayTitle(String title) {}
+ /**
+ * Update the progress, from 0 to 100.
+ */
+ void setProgress(int newProgress) {
+ if (newProgress >= PROGRESS_MAX) {
+ mProgress.setProgress(PageProgressView.MAX_PROGRESS);
+ mProgress.setVisibility(View.GONE);
+ mInLoad = false;
+ onProgressStopped();
+ // check if needs to be hidden
+ if (!isEditingUrl() && !inAutoLogin()) {
+ hide();
+ if (mUseQuickControls) {
+ setShowProgressOnly(false);
+ }
+ }
+ } else {
+ if (!mInLoad) {
+ mProgress.setVisibility(View.VISIBLE);
+ mInLoad = true;
+ onProgressStarted();
+ }
+ mProgress.setProgress(newProgress * PageProgressView.MAX_PROGRESS
+ / PROGRESS_MAX);
+ if (!mShowing) {
+ if (mUseQuickControls && !isEditingUrl()) {
+ setShowProgressOnly(true);
+ }
+ show();
+ }
+ }
+ }
+
+ protected void onProgressStarted() {
+ }
+
+ protected void onProgressStopped() {
+ }
/* package */ void setLock(Drawable d) {
assert mLockIcon != null;
@@ -72,28 +280,206 @@ public class TitleBarBase extends LinearLayout implements UrlInputListener {
}
/* package */ void setFavicon(Bitmap icon) {
- assert mFavicon != null;
- Drawable[] array = new Drawable[3];
- array[0] = new PaintDrawable(Color.BLACK);
- PaintDrawable p = new PaintDrawable(Color.WHITE);
- array[1] = p;
- if (icon == null) {
- array[2] = mGenericFavicon;
+ mFavicon.setImageDrawable(mBaseUi.getFaviconDrawable(icon));
+ }
+
+ public int getEmbeddedHeight() {
+ int height = mContainer.getHeight();
+ if (mAutoLogin.getVisibility() == View.VISIBLE) {
+ height += mAutoLogin.getHeight();
+ }
+ return height;
+ }
+
+ protected void updateAutoLogin(Tab tab, boolean animate) {
+ DeviceAccountLogin login = tab.getDeviceAccountLogin();
+ if (login != null) {
+ mAutoLoginHandler = login;
+ ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext,
+ android.R.style.Theme_Holo_Light);
+ mAccountsAdapter = new ArrayAdapter<String>(wrapper,
+ android.R.layout.simple_spinner_item, login.getAccountNames());
+ mAccountsAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ mAutoLoginAccount.setAdapter(mAccountsAdapter);
+ mAutoLoginAccount.setSelection(0);
+ mAutoLoginAccount.setEnabled(true);
+ mAutoLoginLogin.setEnabled(true);
+ mAutoLoginProgress.setVisibility(View.INVISIBLE);
+ mAutoLoginError.setVisibility(View.GONE);
+ switch (login.getState()) {
+ case DeviceAccountLogin.PROCESSING:
+ mAutoLoginAccount.setEnabled(false);
+ mAutoLoginLogin.setEnabled(false);
+ mAutoLoginProgress.setVisibility(View.VISIBLE);
+ break;
+ case DeviceAccountLogin.FAILED:
+ mAutoLoginProgress.setVisibility(View.INVISIBLE);
+ mAutoLoginError.setVisibility(View.VISIBLE);
+ break;
+ case DeviceAccountLogin.INITIAL:
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ showAutoLogin(animate);
+ } else {
+ hideAutoLogin(animate);
+ }
+ }
+
+ protected void showAutoLogin(boolean animate) {
+ if (mUseQuickControls) {
+ mBaseUi.showTitleBar();
+ }
+ mAutoLogin.setVisibility(View.VISIBLE);
+ if (animate) {
+ mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), R.anim.autologin_enter));
+ }
+ }
+
+ protected void hideAutoLogin(boolean animate) {
+ mAutoLoginHandler = null;
+ if (mUseQuickControls) {
+ mBaseUi.hideTitleBar();
+ mAutoLogin.setVisibility(View.GONE);
+ mBaseUi.refreshWebView();
} else {
- array[2] = new BitmapDrawable(icon);
+ if (animate) {
+ Animation anim = AnimationUtils.loadAnimation(getContext(),
+ R.anim.autologin_exit);
+ anim.setAnimationListener(new AnimationListener() {
+ @Override
+ public void onAnimationEnd(Animation a) {
+ mAutoLogin.setVisibility(View.GONE);
+ mBaseUi.refreshWebView();
+ }
+
+ @Override
+ public void onAnimationStart(Animation a) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation a) {
+ }
+ });
+ mAutoLogin.startAnimation(anim);
+ } else if (mAutoLogin.getAnimation() == null) {
+ mAutoLogin.setVisibility(View.GONE);
+ mBaseUi.refreshWebView();
+ }
}
- LayerDrawable d = new LayerDrawable(array);
- d.setLayerInset(1, 1, 1, 1, 1);
- d.setLayerInset(2, 2, 2, 2, 2);
- mFavicon.setImageDrawable(d);
}
- /* package */ void setInVoiceMode(boolean inVoiceMode) {}
+ @Override
+ public void loginFailed() {
+ mAutoLoginAccount.setEnabled(true);
+ mAutoLoginLogin.setEnabled(true);
+ mAutoLoginProgress.setVisibility(View.INVISIBLE);
+ mAutoLoginError.setVisibility(View.VISIBLE);
+ }
+
- /* package */ void setIncognitoMode(boolean incognito) {}
+ protected boolean inAutoLogin() {
+ return mAutoLoginHandler != null;
+ }
- public int getEmbeddedHeight() {
- return getHeight();
+ @Override
+ public void onClick(View v) {
+ if (mAutoLoginCancel == v) {
+ if (mAutoLoginHandler != null) {
+ mAutoLoginHandler.cancel();
+ mAutoLoginHandler = null;
+ }
+ hideAutoLogin(true);
+ } else if (mAutoLoginLogin == v) {
+ if (mAutoLoginHandler != null) {
+ mAutoLoginAccount.setEnabled(false);
+ mAutoLoginLogin.setEnabled(false);
+ mAutoLoginProgress.setVisibility(View.VISIBLE);
+ mAutoLoginError.setVisibility(View.GONE);
+ mAutoLoginHandler.login(
+ mAutoLoginAccount.getSelectedItemPosition(), this);
+ }
+ }
+ }
+
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ // if losing focus and not in touch mode, leave as is
+ if (hasFocus || view.isInTouchMode() || mUrlInput.needsUpdate()) {
+ setFocusState(hasFocus);
+ }
+ if (hasFocus) {
+ mUrlInput.forceIme();
+ if (mInVoiceMode) {
+ mUrlInput.forceFilter();
+ }
+ } else if (!mUrlInput.needsUpdate()) {
+ mUrlInput.dismissDropDown();
+ mUrlInput.hideIME();
+ if (mUrlInput.getText().length() == 0) {
+ Tab currentTab = mUiController.getTabControl().getCurrentTab();
+ if (currentTab != null) {
+ mUrlInput.setText(currentTab.getUrl(), false);
+ }
+ }
+ }
+ mUrlInput.clearNeedsUpdate();
+ }
+
+ protected void setFocusState(boolean focus) {
+ if (focus) {
+ updateSearchMode(false);
+ }
+ }
+
+ protected void updateSearchMode(boolean userEdited) {
+ setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText()));
+ }
+
+ protected void setSearchMode(boolean voiceSearchEnabled) {}
+
+ boolean isEditingUrl() {
+ return mUrlInput.hasFocus();
+ }
+
+ void stopEditingUrl() {
+ mUrlInput.clearFocus();
+ }
+
+ void setDisplayTitle(String title) {
+ if (!isEditingUrl()) {
+ mUrlInput.setText(title, false);
+ }
+ }
+
+ // UrlInput text watcher
+
+ @Override
+ public void onTextChanged(String newText) {
+ if (mUrlInput.hasFocus()) {
+ // check if input field is empty and adjust voice search state
+ updateSearchMode(true);
+ // clear voice mode when user types
+ setInVoiceMode(false, null);
+ }
+ }
+
+ // voicesearch
+
+ public void setInVoiceMode(boolean voicemode, List<String> voiceResults) {
+ mInVoiceMode = voicemode;
+ mUrlInput.setVoiceResults(voiceResults);
+ }
+
+ void setIncognitoMode(boolean incognito) {
+ mUrlInput.setIncognitoMode(incognito);
+ }
+
+ void clearCompletions() {
+ mUrlInput.setSuggestedText(null);
}
// UrlInputListener implementation
@@ -157,4 +543,58 @@ public class TitleBarBase extends LinearLayout implements UrlInputListener {
public void setCurrentUrlIsBookmark(boolean isBookmark) {
}
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent evt) {
+ if (evt.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ // catch back key in order to do slightly more cleanup than usual
+ mUrlInput.clearFocus();
+ return true;
+ }
+ return super.dispatchKeyEventPreIme(evt);
+ }
+
+ protected WebView getCurrentWebView() {
+ Tab t = mBaseUi.getActiveTab();
+ if (t != null) {
+ return t.getWebView();
+ } else {
+ return null;
+ }
+ }
+
+ void registerDropdownChangeListener(DropdownChangeListener d) {
+ mUrlInput.registerDropdownChangeListener(d);
+ }
+
+ /**
+ * called from the Ui when the user wants to edit
+ * @param clearInput clear the input field
+ */
+ void startEditingUrl(boolean clearInput) {
+ // editing takes preference of progress
+ mContainer.setVisibility(View.VISIBLE);
+ if (mUseQuickControls) {
+ mProgress.setVisibility(View.GONE);
+ }
+ if (!mUrlInput.hasFocus()) {
+ mUrlInput.requestFocus();
+ }
+ if (clearInput) {
+ mUrlInput.setText("");
+ } else if (mInVoiceMode) {
+ mUrlInput.showDropDown();
+ }
+ }
+
+ private ViewGroup.LayoutParams makeLayoutParams() {
+ if (mUseQuickControls) {
+ return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT);
+ } else {
+ return new AbsoluteLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
+ 0, 0);
+ }
+ }
+
}
diff --git a/src/com/android/browser/TitleBarPhone.java b/src/com/android/browser/TitleBarPhone.java
new file mode 100644
index 0000000..9242f99
--- /dev/null
+++ b/src/com/android/browser/TitleBarPhone.java
@@ -0,0 +1,151 @@
+/*
+ * 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 com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.List;
+
+/**
+ * This class represents a title bar for a particular "tab" or "window" in the
+ * browser.
+ */
+public class TitleBarPhone extends TitleBarBase implements OnFocusChangeListener,
+ OnClickListener, TextChangeWatcher {
+
+ private Activity mActivity;
+ private ImageView mStopButton;
+ private ImageView mVoiceButton;
+ private boolean mHasLockIcon;
+
+ public TitleBarPhone(Activity activity, UiController controller, PhoneUi ui,
+ FrameLayout parent) {
+ super(activity, controller, ui, parent);
+ mActivity = activity;
+ initLayout(activity, R.layout.title_bar);
+ }
+
+ @Override
+ protected void initLayout(Context context, int layoutId) {
+ super.initLayout(context, layoutId);
+ mLockIcon = (ImageView) findViewById(R.id.lock);
+ mFavicon = (ImageView) findViewById(R.id.favicon);
+ mStopButton = (ImageView) findViewById(R.id.stop);
+ mStopButton.setOnClickListener(this);
+ mVoiceButton = (ImageView) findViewById(R.id.voice);
+ mVoiceButton.setOnClickListener(this);
+ setFocusState(false);
+ }
+
+ @Override
+ public void createContextMenu(ContextMenu menu) {
+ MenuInflater inflater = mActivity.getMenuInflater();
+ inflater.inflate(R.menu.title_context, menu);
+ mActivity.onCreateContextMenu(menu, this, null);
+ }
+
+ @Override
+ public void setInVoiceMode(boolean voicemode, List<String> voiceResults) {
+ super.setInVoiceMode(voicemode, voiceResults);
+ }
+
+ @Override
+ protected void setSearchMode(boolean voiceSearchEnabled) {
+ boolean showvoicebutton = voiceSearchEnabled &&
+ mUiController.supportsVoiceSearch();
+ mVoiceButton.setVisibility(showvoicebutton ? View.VISIBLE :
+ View.GONE);
+ }
+
+ @Override
+ protected void setFocusState(boolean focus) {
+ super.setFocusState(focus);
+ if (focus) {
+ mHasLockIcon = (mLockIcon.getVisibility() == View.VISIBLE);
+ mLockIcon.setVisibility(View.GONE);
+ mStopButton.setVisibility(View.GONE);
+ mVoiceButton.setVisibility(View.VISIBLE);
+ } else {
+ mLockIcon.setVisibility(mHasLockIcon ? View.VISIBLE : View.GONE);
+ if (mInLoad) {
+ mStopButton.setVisibility(View.VISIBLE);
+ } else {
+ mStopButton.setVisibility(View.GONE);
+ }
+ mVoiceButton.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ protected void onProgressStarted() {
+ setFocusState(mUrlInput.hasFocus());
+ }
+
+ @Override
+ protected void onProgressStopped() {
+ setFocusState(mUrlInput.hasFocus());
+ }
+
+ /**
+ * Update the text displayed in the title bar.
+ * @param title String to display. If null, the new tab string will be
+ * shown.
+ */
+ @Override
+ void setDisplayTitle(String title) {
+ if (title == null) {
+ mUrlInput.setText(R.string.new_tab);
+ } else {
+ mUrlInput.setText(title);
+ }
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v == mUrlInput) {
+ if (hasFocus) {
+ mActivity.closeOptionsMenu();
+ }
+ }
+ super.onFocusChange(v, hasFocus);
+ if (!hasFocus) {
+ mBaseUi.hideTitleBar();
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mStopButton) {
+ mUiController.stopLoading();
+ } else if (v == mVoiceButton) {
+ mUiController.startVoiceSearch();
+ } else {
+ super.onClick(v);
+ }
+ }
+
+}
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index e91597f..8c03e4c 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -16,41 +16,24 @@
package com.android.browser;
-import com.android.browser.UI.DropdownChangeListener;
import com.android.browser.autocomplete.SuggestedTextController.TextChangeWatcher;
-import com.android.browser.search.SearchEngine;
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
-import android.content.res.Configuration;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.preference.PreferenceManager;
import android.text.TextUtils;
-import android.view.ContextThemeWrapper;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
-import android.view.ViewGroup;
-import android.view.animation.Animation;
-import android.view.animation.Animation.AnimationListener;
-import android.view.animation.AnimationUtils;
import android.webkit.WebView;
-import android.widget.AbsoluteLayout;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.Spinner;
-import android.widget.TextView;
import java.util.List;
@@ -66,39 +49,25 @@ public class TitleBarXLarge extends TitleBarBase
private Drawable mStopDrawable;
private Drawable mReloadDrawable;
- private View mContainer;
+ private View mUrlContainer;
private ImageButton mBackButton;
private ImageButton mForwardButton;
private ImageView mStar;
private ImageView mUrlIcon;
private ImageView mSearchButton;
- private View mUrlContainer;
- private View mNavButtons;
private View mGoButton;
private ImageView mStopButton;
private View mAllButton;
private View mClearButton;
private ImageView mVoiceSearch;
- private PageProgressView mProgressView;
private Drawable mFocusDrawable;
private Drawable mUnfocusDrawable;
- // Auto-login UI
- private View mAutoLogin;
- private Spinner mAutoLoginAccount;
- private Button mAutoLoginLogin;
- private ProgressBar mAutoLoginProgress;
- private TextView mAutoLoginError;
- private ImageButton mAutoLoginCancel;
- private DeviceAccountLogin mAutoLoginHandler;
- private ArrayAdapter<String> mAccountsAdapter;
-
- private boolean mInLoad;
- private boolean mUseQuickControls;
- private boolean mHideNavButtons;
+ private boolean mHasFocus = false;
+ private BrowserSettings mSettings;
public TitleBarXLarge(Activity activity, UiController controller,
- XLargeUi ui) {
- super(activity, controller, ui);
+ XLargeUi ui, FrameLayout parent) {
+ super(activity, controller, ui, parent);
mUi = ui;
Resources resources = activity.getResources();
mStopDrawable = resources.getDrawable(R.drawable.ic_stop_holo_dark);
@@ -108,17 +77,15 @@ public class TitleBarXLarge extends TitleBarBase
mUnfocusDrawable = resources.getDrawable(
R.drawable.textfield_default_holo_dark);
mInVoiceMode = false;
- initLayout(activity);
+ mSettings = BrowserSettings.getInstance();
+ initLayout(activity, R.layout.url_bar);
+ PreferenceManager.getDefaultSharedPreferences(activity)
+ .registerOnSharedPreferenceChangeListener(mSharedPrefsListener);
}
- private void initLayout(Context context) {
- Resources res = mContext.getResources();
- mHideNavButtons = res.getBoolean(R.bool.hide_nav_buttons);
- LayoutInflater factory = LayoutInflater.from(context);
- factory.inflate(R.layout.url_bar, this);
-
- mContainer = findViewById(R.id.taburlbar);
- mUrlInput = (UrlInputView) findViewById(R.id.url_focused);
+ @Override
+ protected void initLayout(Context context, int layoutId) {
+ super.initLayout(context, layoutId);
mAllButton = findViewById(R.id.all_btn);
// TODO: Change enabled states based on whether you can go
// back/forward. Probably should be done inside onPageStarted.
@@ -132,8 +99,6 @@ public class TitleBarXLarge extends TitleBarBase
mGoButton = findViewById(R.id.go);
mClearButton = findViewById(R.id.clear);
mVoiceSearch = (ImageView) findViewById(R.id.voicesearch);
- mProgressView = (PageProgressView) findViewById(R.id.progress);
- mNavButtons = findViewById(R.id.navbuttons);
mUrlContainer = findViewById(R.id.urlbar_focused);
mBackButton.setOnClickListener(this);
mForwardButton.setOnClickListener(this);
@@ -144,45 +109,11 @@ public class TitleBarXLarge extends TitleBarBase
mGoButton.setOnClickListener(this);
mClearButton.setOnClickListener(this);
mVoiceSearch.setOnClickListener(this);
- mUrlInput.setUrlInputListener(this);
+ mUrlIcon.setOnClickListener(this);
mUrlInput.setContainer(mUrlContainer);
- mUrlInput.setController(mUiController);
- mUrlInput.setOnFocusChangeListener(this);
- mUrlInput.setSelectAllOnFocus(true);
- mUrlInput.addQueryTextWatcher(this);
- mAutoLogin = findViewById(R.id.autologin);
- mAutoLoginAccount = (Spinner) findViewById(R.id.autologin_account);
- mAutoLoginLogin = (Button) findViewById(R.id.autologin_login);
- mAutoLoginLogin.setOnClickListener(this);
- mAutoLoginProgress =
- (ProgressBar) findViewById(R.id.autologin_progress);
- mAutoLoginError = (TextView) findViewById(R.id.autologin_error);
- mAutoLoginCancel =
- (ImageButton) mAutoLogin.findViewById(R.id.autologin_close);
- mAutoLoginCancel.setOnClickListener(this);
-
setFocusState(false);
}
- @Override
- public void onConfigurationChanged(Configuration config) {
- super.onConfigurationChanged(config);
- Resources res = mContext.getResources();
- mHideNavButtons = res.getBoolean(R.bool.hide_nav_buttons);
- if (mUrlInput.hasFocus()) {
- if (mHideNavButtons && (mNavButtons.getVisibility() == View.VISIBLE)) {
- int aw = mNavButtons.getMeasuredWidth();
- mNavButtons.setVisibility(View.GONE);
- mNavButtons.setAlpha(0f);
- mNavButtons.setTranslationX(-aw);
- } else if (!mHideNavButtons && (mNavButtons.getVisibility() == View.GONE)) {
- mNavButtons.setVisibility(View.VISIBLE);
- mNavButtons.setAlpha(1f);
- mNavButtons.setTranslationX(0);
- }
- }
- }
-
void updateNavigationState(Tab tab) {
WebView web = tab.getWebView();
if (web != null) {
@@ -193,100 +124,7 @@ public class TitleBarXLarge extends TitleBarBase
? R.drawable.ic_forward_holo_dark
: R.drawable.ic_forward_disabled_holo_dark);
}
- }
-
- void updateAutoLogin(Tab tab, boolean animate) {
- DeviceAccountLogin login = tab.getDeviceAccountLogin();
- if (login != null) {
- mAutoLoginHandler = login;
- mAutoLogin.setVisibility(View.VISIBLE);
- ContextThemeWrapper wrapper = new ContextThemeWrapper(mContext,
- android.R.style.Theme_Holo_Light);
- mAccountsAdapter = new ArrayAdapter<String>(wrapper,
- android.R.layout.simple_spinner_item, login.getAccountNames());
- mAccountsAdapter.setDropDownViewResource(
- android.R.layout.simple_spinner_dropdown_item);
- mAutoLoginAccount.setAdapter(mAccountsAdapter);
- mAutoLoginAccount.setSelection(0);
- mAutoLoginAccount.setEnabled(true);
- mAutoLoginLogin.setEnabled(true);
- mAutoLoginProgress.setVisibility(View.GONE);
- mAutoLoginError.setVisibility(View.GONE);
- switch (login.getState()) {
- case DeviceAccountLogin.PROCESSING:
- mAutoLoginAccount.setEnabled(false);
- mAutoLoginLogin.setEnabled(false);
- mAutoLoginProgress.setVisibility(View.VISIBLE);
- break;
- case DeviceAccountLogin.FAILED:
- mAutoLoginProgress.setVisibility(View.GONE);
- mAutoLoginError.setVisibility(View.VISIBLE);
- break;
- case DeviceAccountLogin.INITIAL:
- break;
- default:
- throw new IllegalStateException();
- }
- if (mUseQuickControls) {
- mUi.showTitleBar();
- } else {
- if (animate) {
- mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
- getContext(), R.anim.autologin_enter));
- }
- }
- } else {
- mAutoLoginHandler = null;
- if (mUseQuickControls) {
- mUi.hideTitleBar();
- mAutoLogin.setVisibility(View.GONE);
- mUi.refreshWebView();
- } else {
- if (animate) {
- hideAutoLogin();
- } else if (mAutoLogin.getAnimation() == null) {
- mAutoLogin.setVisibility(View.GONE);
- mUi.refreshWebView();
- }
- }
- }
- }
-
- boolean inAutoLogin() {
- return mAutoLoginHandler != null;
- }
-
- private ViewGroup.LayoutParams makeLayoutParams() {
- if (mUseQuickControls) {
- return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT);
- } else {
- return new AbsoluteLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
- 0, 0);
- }
- }
-
- @Override
- public int getEmbeddedHeight() {
- int height = mContainer.getHeight();
- if (mAutoLogin.getVisibility() == View.VISIBLE) {
- height += mAutoLogin.getHeight();
- }
- return height;
- }
-
- void setUseQuickControls(boolean useQuickControls) {
- mUseQuickControls = useQuickControls;
- setLayoutParams(makeLayoutParams());
- }
-
- void setShowProgressOnly(boolean progress) {
- if (progress && !inAutoLogin()) {
- mContainer.setVisibility(View.GONE);
- } else {
- mContainer.setVisibility(View.VISIBLE);
- }
+ updateUrlIcon();
}
@Override
@@ -324,47 +162,6 @@ public class TitleBarXLarge extends TitleBarBase
mStar.setActivated(isBookmark);
}
- /**
- * called from the Ui when the user wants to edit
- * @param clearInput clear the input field
- */
- void startEditingUrl(boolean clearInput) {
- // editing takes preference of progress
- mContainer.setVisibility(View.VISIBLE);
- if (mUseQuickControls) {
- mProgressView.setVisibility(View.GONE);
- }
- if (!mUrlInput.hasFocus()) {
- mUrlInput.requestFocus();
- }
- if (clearInput) {
- mUrlInput.setText("");
- } else if (mInVoiceMode) {
- mUrlInput.showDropDown();
- }
- }
-
- boolean isEditingUrl() {
- return mUrlInput.hasFocus();
- }
-
- void stopEditingUrl() {
- mUrlInput.clearFocus();
- }
-
- private void hideAutoLogin() {
- Animation anim = AnimationUtils.loadAnimation(
- getContext(), R.anim.autologin_exit);
- anim.setAnimationListener(new AnimationListener() {
- @Override public void onAnimationEnd(Animation a) {
- mAutoLogin.setVisibility(View.GONE);
- mUi.refreshWebView();
- }
- @Override public void onAnimationStart(Animation a) {}
- @Override public void onAnimationRepeat(Animation a) {}
- });
- mAutoLogin.startAnimation(anim);
- }
@Override
public void onClick(View v) {
@@ -390,33 +187,19 @@ public class TitleBarXLarge extends TitleBarBase
clearOrClose();
} else if (mVoiceSearch == v) {
mUiController.startVoiceSearch();
- } else if (mAutoLoginCancel == v) {
- if (mAutoLoginHandler != null) {
- mAutoLoginHandler.cancel();
- mAutoLoginHandler = null;
- }
- hideAutoLogin();
- } else if (mAutoLoginLogin == v) {
- if (mAutoLoginHandler != null) {
- mAutoLoginAccount.setEnabled(false);
- mAutoLoginLogin.setEnabled(false);
- mAutoLoginProgress.setVisibility(View.VISIBLE);
- mAutoLoginError.setVisibility(View.GONE);
- mAutoLoginHandler.login(
- mAutoLoginAccount.getSelectedItemPosition(), this);
+ } else if (mUrlIcon == v) {
+ WebView web = mUiController.getCurrentWebView();
+ if (mSettings.enableUseragentSwitcher() && web != null) {
+ mSettings.toggleDesktopUseragent(web);
+ web.loadUrl(web.getOriginalUrl());
+ updateUrlIcon();
}
+ } else {
+ super.onClick(v);
}
}
@Override
- public void loginFailed() {
- mAutoLoginAccount.setEnabled(true);
- mAutoLoginLogin.setEnabled(true);
- mAutoLoginProgress.setVisibility(View.GONE);
- mAutoLoginError.setVisibility(View.VISIBLE);
- }
-
- @Override
void setFavicon(Bitmap icon) { }
private void clearOrClose() {
@@ -429,22 +212,46 @@ public class TitleBarXLarge extends TitleBarBase
}
}
- private void setFocusState(boolean focus) {
- if (focus) {
- if (mHideNavButtons) {
- hideNavButtons();
+ void updateUrlIcon() {
+ if (mHasFocus) {
+ return;
+ }
+ if (!mInVoiceMode && mSettings.enableUseragentSwitcher()) {
+ WebView web = mUiController.getCurrentWebView();
+ if (mSettings.hasDesktopUseragent(web)) {
+ mUrlIcon.setImageResource(R.drawable.ic_ua_desktop);
+ } else {
+ mUrlIcon.setImageResource(R.drawable.ic_ua_android);
}
- mUrlInput.setDropDownWidth(mUrlContainer.getWidth());
- mUrlInput.setDropDownHorizontalOffset(-mUrlInput.getLeft());
+ } else {
+ mUrlIcon.setImageResource(mInVoiceMode ?
+ R.drawable.ic_search_holo_dark
+ : R.drawable.ic_web_holo_dark);
+ }
+ }
+
+ private OnSharedPreferenceChangeListener mSharedPrefsListener =
+ new OnSharedPreferenceChangeListener() {
+
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ updateUrlIcon();
+ }
+
+ };
+
+ @Override
+ protected void setFocusState(boolean focus) {
+ super.setFocusState(focus);
+ mHasFocus = focus;
+ if (focus) {
mSearchButton.setVisibility(View.GONE);
mStar.setVisibility(View.GONE);
mClearButton.setVisibility(View.VISIBLE);
mUrlIcon.setImageResource(R.drawable.ic_search_holo_dark);
updateSearchMode(false);
} else {
- if (mHideNavButtons) {
- showNavButtons();
- }
mGoButton.setVisibility(View.GONE);
mVoiceSearch.setVisibility(View.GONE);
mStar.setVisibility(View.VISIBLE);
@@ -454,9 +261,7 @@ public class TitleBarXLarge extends TitleBarBase
} else {
mSearchButton.setVisibility(View.VISIBLE);
}
- mUrlIcon.setImageResource(mInVoiceMode ?
- R.drawable.ic_search_holo_dark
- : R.drawable.ic_web_holo_dark);
+ updateUrlIcon();
}
}
@@ -468,41 +273,25 @@ public class TitleBarXLarge extends TitleBarBase
}
}
- /**
- * Update the progress, from 0 to 100.
- */
@Override
- void setProgress(int newProgress) {
- boolean blockvisuals = mUseQuickControls && isEditingUrl();
- if (newProgress >= PROGRESS_MAX) {
- if (!blockvisuals) {
- mProgressView.setProgress(PageProgressView.MAX_PROGRESS);
- mProgressView.setVisibility(View.GONE);
- mStopButton.setImageDrawable(mReloadDrawable);
- }
- mInLoad = false;
- } else {
- if (!mInLoad) {
- if (!blockvisuals) {
- mProgressView.setVisibility(View.VISIBLE);
- mStopButton.setImageDrawable(mStopDrawable);
- }
- mInLoad = true;
- }
- mProgressView.setProgress(newProgress * PageProgressView.MAX_PROGRESS
- / PROGRESS_MAX);
- }
+ protected void onProgressStarted() {
+ mStopButton.setImageDrawable(mStopDrawable);
+ }
+
+ @Override
+ protected void onProgressStopped() {
+ mStopButton.setImageDrawable(mReloadDrawable);
}
- private void updateSearchMode(boolean userEdited) {
+ @Override
+ protected void updateSearchMode(boolean userEdited) {
setSearchMode(!userEdited || TextUtils.isEmpty(mUrlInput.getUserText()));
}
- private void setSearchMode(boolean voiceSearchEnabled) {
- SearchEngine searchEngine = BrowserSettings.getInstance()
- .getSearchEngine();
+ @Override
+ protected void setSearchMode(boolean voiceSearchEnabled) {
boolean showvoicebutton = voiceSearchEnabled &&
- (searchEngine != null && searchEngine.supportsVoiceSearch());
+ mUiController.supportsVoiceSearch();
mVoiceSearch.setVisibility(showvoicebutton ? View.VISIBLE :
View.GONE);
mGoButton.setVisibility(voiceSearchEnabled ? View.GONE :
@@ -510,45 +299,14 @@ public class TitleBarXLarge extends TitleBarBase
}
@Override
- /* package */ void setDisplayTitle(String title) {
- if (!isEditingUrl()) {
- mUrlInput.setText(title, false);
- }
- }
-
- // UrlInput text watcher
-
- @Override
- public void onTextChanged(String newText) {
- if (mUrlInput.hasFocus()) {
- // check if input field is empty and adjust voice search state
- updateSearchMode(true);
- // clear voice mode when user types
- setInVoiceMode(false, null);
- }
- }
-
- // voicesearch
-
- @Override
- public void setInVoiceMode(boolean voicemode) {
- setInVoiceMode(voicemode, null);
- }
-
public void setInVoiceMode(boolean voicemode, List<String> voiceResults) {
- mInVoiceMode = voicemode;
- mUrlInput.setVoiceResults(voiceResults);
+ super.setInVoiceMode(voicemode, voiceResults);
if (voicemode) {
mUrlIcon.setImageDrawable(mSearchButton.getDrawable());
}
}
@Override
- void setIncognitoMode(boolean incognito) {
- mUrlInput.setIncognitoMode(incognito);
- }
-
- @Override
public View focusSearch(View focused, int dir) {
if (FOCUS_DOWN == dir && hasFocus()) {
return getCurrentWebView();
@@ -556,74 +314,4 @@ public class TitleBarXLarge extends TitleBarBase
return super.focusSearch(focused, dir);
}
- void clearCompletions() {
- mUrlInput.setSuggestedText(null);
- }
-
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent evt) {
- if (evt.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- // catch back key in order to do slightly more cleanup than usual
- mUrlInput.clearFocus();
- return true;
- }
- return super.dispatchKeyEventPreIme(evt);
- }
-
- private WebView getCurrentWebView() {
- Tab t = mUi.getActiveTab();
- if (t != null) {
- return t.getWebView();
- } else {
- return null;
- }
- }
-
- void registerDropdownChangeListener(DropdownChangeListener d) {
- mUrlInput.registerDropdownChangeListener(d);
- }
-
- private void hideNavButtons() {
- int awidth = mNavButtons.getMeasuredWidth();
- Animator anim1 = ObjectAnimator.ofFloat(mNavButtons, "translationX", 0, - awidth);
- Animator anim2 = ObjectAnimator.ofInt(mUrlContainer, "left", mUrlContainer.getLeft(),
- mUrlContainer.getPaddingLeft());
- Animator anim3 = ObjectAnimator.ofFloat(mNavButtons, "alpha", 1f, 0f);
- AnimatorSet combo = new AnimatorSet();
- combo.playTogether(anim1, anim2, anim3);
- combo.addListener(new AnimatorListener() {
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mNavButtons.setVisibility(View.GONE);
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- }
- });
- combo.setDuration(150);
- combo.start();
- }
-
- private void showNavButtons() {
- int awidth = mNavButtons.getMeasuredWidth();
- Animator anim1 = ObjectAnimator.ofFloat(mNavButtons, "translationX", -awidth, 0);
- Animator anim2 = ObjectAnimator.ofInt(mUrlContainer, "left", 0, awidth);
- Animator anim3 = ObjectAnimator.ofFloat(mNavButtons, "alpha", 0f, 1f);
- AnimatorSet combo = new AnimatorSet();
- combo.playTogether(anim1, anim2, anim3);
- mNavButtons.setVisibility(View.VISIBLE);
- combo.setDuration(150);
- combo.start();
- }
-
}
diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java
index 368c829..bb34ada 100644
--- a/src/com/android/browser/UI.java
+++ b/src/com/android/browser/UI.java
@@ -85,7 +85,7 @@ public interface UI {
public boolean isCustomViewShowing();
- public void showVoiceTitleBar(String title);
+ public void showVoiceTitleBar(String title, List<String> results);
public void revertVoiceTitleBar(Tab tab);
@@ -132,4 +132,6 @@ public interface UI {
void showAutoLogin(Tab tab);
void hideAutoLogin(Tab tab);
+
+ void setFullscreen(boolean enabled);
}
diff --git a/src/com/android/browser/UiController.java b/src/com/android/browser/UiController.java
index 65fa5f8..4fc37af 100644
--- a/src/com/android/browser/UiController.java
+++ b/src/com/android/browser/UiController.java
@@ -44,7 +44,12 @@ public interface UiController extends BookmarksHistoryCallbacks {
Tab openIncognitoTab();
- boolean switchToTab(int tabIndex);
+ Tab openTab(String url, boolean incognito, boolean setActive,
+ boolean useCurrent);
+
+ void setActiveTab(Tab tab);
+
+ boolean switchToTab(Tab tab);
void closeCurrentTab();
@@ -56,10 +61,10 @@ public interface UiController extends BookmarksHistoryCallbacks {
void bookmarksOrHistoryPicker(boolean openHistory);
- void startSearch(String url);
-
void startVoiceSearch();
+ boolean supportsVoiceSearch();
+
void showVoiceSearchResults(String title);
void editUrl();
diff --git a/src/com/android/browser/UrlHandler.java b/src/com/android/browser/UrlHandler.java
index b23dc7d..02a080f 100644
--- a/src/com/android/browser/UrlHandler.java
+++ b/src/com/android/browser/UrlHandler.java
@@ -22,7 +22,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import android.util.Log;
import android.webkit.WebView;
@@ -35,6 +37,9 @@ import java.util.regex.Matcher;
*/
public class UrlHandler {
+ static final String RLZ_PROVIDER = "com.google.android.partnersetup.rlzappprovider";
+ static final Uri RLZ_PROVIDER_URI = Uri.parse("content://" + RLZ_PROVIDER + "/");
+
// Use in overrideUrlLoading
/* package */ final static String SCHEME_WTAI = "wtai://wp/";
/* package */ final static String SCHEME_WTAI_MC = "wtai://wp/mc;";
@@ -44,6 +49,9 @@ public class UrlHandler {
Controller mController;
Activity mActivity;
+ private Boolean mIsProviderPresent = null;
+ private Uri mRlzUri = null;
+
public UrlHandler(Controller controller) {
mController = controller;
mActivity = mController.getActivity();
@@ -92,6 +100,20 @@ public class UrlHandler {
return false;
}
+ // If this is a Google search, attempt to add an RLZ string
+ // (if one isn't already present).
+ if (rlzProviderPresent()) {
+ Uri siteUri = Uri.parse(url);
+ if (needsRlzString(siteUri)) {
+ // Need to look up the RLZ info from a database, so do it in an
+ // AsyncTask. Although we are not overriding the URL load synchronously,
+ // we guarantee that we will handle this URL load after the task executes,
+ // so it's safe to just return true to WebCore now to stop its own loading.
+ new RLZTask(tab, siteUri, view).execute();
+ return true;
+ }
+ }
+
if (startActivityForUrl(url)) {
return true;
}
@@ -192,11 +214,120 @@ public class UrlHandler {
// depressed by opening in a new tab
boolean handleMenuClick(Tab tab, String url) {
if (mController.isMenuDown()) {
- mController.openTab(tab, url, false);
+ mController.openTab(url,
+ (tab != null) && tab.isPrivateBrowsingEnabled(),
+ !BrowserSettings.getInstance().openInBackground(), true);
mActivity.closeOptionsMenu();
return true;
}
return false;
}
+
+ // TODO: Move this class into Tab, where it can be properly stopped upon
+ // closure of the tab
+ private class RLZTask extends AsyncTask<Void, Void, String> {
+ private Tab mTab;
+ private Uri mSiteUri;
+ private WebView mWebView;
+
+ public RLZTask(Tab tab, Uri uri, WebView webView) {
+ mTab = tab;
+ mSiteUri = uri;
+ mWebView = webView;
+ }
+
+ protected String doInBackground(Void... unused) {
+ String result = mSiteUri.toString();
+ Cursor cur = null;
+ try {
+ cur = mActivity.getContentResolver()
+ .query(getRlzUri(), null, null, null, null);
+ if (cur != null && cur.moveToFirst() && !cur.isNull(0)) {
+ result = mSiteUri.buildUpon()
+ .appendQueryParameter("rlz", cur.getString(0))
+ .build().toString();
+ }
+ } finally {
+ if (cur != null) {
+ cur.close();
+ }
+ }
+ return result;
+ }
+
+ protected void onPostExecute(String result) {
+ // Make sure the Tab was not closed while handling the task
+ if (mController.getTabControl().getTabPosition(mTab) != -1) {
+ // If the Activity Manager is not invoked, load the URL directly
+ if (!startActivityForUrl(result)) {
+ if (!handleMenuClick(mTab, result)) {
+ mController.loadUrl(mWebView, result);
+ }
+ }
+ }
+ }
+ }
+
+ // Determine whether the RLZ provider is present on the system.
+ private boolean rlzProviderPresent() {
+ if (mIsProviderPresent == null) {
+ PackageManager pm = mActivity.getPackageManager();
+ mIsProviderPresent = pm.resolveContentProvider(RLZ_PROVIDER, 0) != null;
+ }
+ return mIsProviderPresent;
+ }
+
+ // Retrieve the RLZ access point string and cache the URI used to
+ // retrieve RLZ values.
+ private Uri getRlzUri() {
+ if (mRlzUri == null) {
+ String ap = mActivity.getResources()
+ .getString(R.string.rlz_access_point);
+ mRlzUri = Uri.withAppendedPath(RLZ_PROVIDER_URI, ap);
+ }
+ return mRlzUri;
+ }
+
+ // Determine if this URI appears to be for a Google search
+ // and does not have an RLZ parameter.
+ // Taken largely from Chrome source, src/chrome/browser/google_url_tracker.cc
+ private static boolean needsRlzString(Uri uri) {
+ String scheme = uri.getScheme();
+ if (("http".equals(scheme) || "https".equals(scheme)) &&
+ (uri.getQueryParameter("q") != null) &&
+ (uri.getQueryParameter("rlz") == null)) {
+ String host = uri.getHost();
+ if (host == null) {
+ return false;
+ }
+ String[] hostComponents = host.split("\\.");
+
+ if (hostComponents.length < 2) {
+ return false;
+ }
+ int googleComponent = hostComponents.length - 2;
+ String component = hostComponents[googleComponent];
+ if (!"google".equals(component)) {
+ if (hostComponents.length < 3 ||
+ (!"co".equals(component) && !"com".equals(component))) {
+ return false;
+ }
+ googleComponent = hostComponents.length - 3;
+ if (!"google".equals(hostComponents[googleComponent])) {
+ return false;
+ }
+ }
+
+ // Google corp network handling.
+ if (googleComponent > 0 && "corp".equals(
+ hostComponents[googleComponent - 1])) {
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+ }
+
}
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
index 9c5d338..7545e6a 100644
--- a/src/com/android/browser/UrlInputView.java
+++ b/src/com/android/browser/UrlInputView.java
@@ -175,7 +175,7 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (BrowserSettings.getInstance().useInstant() &&
+ if (BrowserSettings.getInstance().useInstantSearch() &&
(actionId == EditorInfo.IME_ACTION_NEXT)) {
// When instant is turned on AND the user chooses to complete
// using the tab key, then use the completion rather than the
@@ -298,11 +298,11 @@ public class UrlInputView extends SuggestiveAutoCompleteTextView
}
/*
- * no-op to prevent scrolling of webview when embedded titlebar is edited
+ * no-op to prevent scrolling of webview when embedded titlebar
+ * gets edited
*/
@Override
public boolean requestRectangleOnScreen(Rect rect, boolean immediate) {
return false;
}
-
}
diff --git a/src/com/android/browser/UrlUtils.java b/src/com/android/browser/UrlUtils.java
index 8c789db..ccf9710 100644
--- a/src/com/android/browser/UrlUtils.java
+++ b/src/com/android/browser/UrlUtils.java
@@ -16,8 +16,6 @@
package com.android.browser;
-import com.android.browser.homepages.HomeProvider;
-
import android.net.Uri;
import android.util.Patterns;
import android.webkit.URLUtil;
@@ -59,7 +57,7 @@ public class UrlUtils {
* @return a stripped url like "www.google.com", or the original string if it could
* not be stripped
*/
- /* package */ static String stripUrl(String url) {
+ public static String stripUrl(String url) {
if (url == null) return null;
Matcher m = STRIP_URL_PATTERN.matcher(url);
if (m.matches() && m.groupCount() == 3) {
@@ -159,34 +157,4 @@ public class UrlUtils {
return inUrl;
}
- // Determine if this URI appears to be a Google property
- /* package */ static boolean isGoogleUri(Uri uri) {
- String scheme = uri.getScheme();
- if (!"http".equals(scheme) && !"https".equals(scheme)) {
- return false;
- }
-
- String host = uri.getHost();
- if (host == null) {
- return false;
- }
- String[] hostComponents = host.split("\\.");
- if (hostComponents.length < 2) {
- return false;
- }
-
- int googleComponent = hostComponents.length - 2;
- String component = hostComponents[googleComponent];
- if (!"google".equals(component)) {
- if (hostComponents.length < 3 ||
- (!"co".equals(component) && !"com".equals(component))) {
- return false;
- }
- googleComponent = hostComponents.length - 3;
- if (!"google".equals(hostComponents[googleComponent])) {
- return false;
- }
- }
- return true;
- }
}
diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java
index 6b44207..bf3bdba 100644
--- a/src/com/android/browser/WebViewController.java
+++ b/src/com/android/browser/WebViewController.java
@@ -16,8 +16,6 @@
package com.android.browser;
-import com.android.browser.IntentHandler.UrlData;
-
import android.app.Activity;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -31,6 +29,8 @@ import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
+import java.util.List;
+
/**
* WebView aspect of the controller
*/
@@ -85,7 +85,7 @@ public interface WebViewController {
void onUserCanceledSsl(Tab tab);
- void activateVoiceSearchMode(String title);
+ void activateVoiceSearchMode(String title, List<String> results);
void revertVoiceSearchMode(Tab tab);
@@ -101,10 +101,10 @@ public interface WebViewController {
void dismissSubWindow(Tab tab);
- Tab openTabAndShow(Tab parent, UrlData urlData, boolean closeOnExit,
- String appId);
+ Tab openTab(String url, boolean incognito, boolean setActive,
+ boolean useCurrent);
- boolean switchToTab(int tabindex);
+ boolean switchToTab(Tab tab);
void closeTab(Tab tab);
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index 8c34fc9..4bfd3cf 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -16,26 +16,19 @@
package com.android.browser;
-import com.android.browser.ScrollWebView.ScrollListener;
+import com.android.browser.BrowserWebView.ScrollListener;
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.app.Activity;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.Menu;
import android.view.View;
import android.webkit.WebChromeClient.CustomViewCallback;
import android.webkit.WebView;
-import android.widget.FrameLayout;
import java.util.List;
@@ -50,8 +43,6 @@ public class XLargeUi extends BaseUi implements ScrollListener {
private TabBar mTabBar;
private TitleBarXLarge mTitleBar;
- private Animator mTitleBarAnimator;
- private boolean mSkipTitleBarAnimations;
private boolean mUseQuickControls;
private PieControl mPieControl;
@@ -64,7 +55,8 @@ public class XLargeUi extends BaseUi implements ScrollListener {
public XLargeUi(Activity browser, UiController controller) {
super(browser, controller);
mHandler = new Handler();
- mTitleBar = new TitleBarXLarge(mActivity, mUiController, this);
+ mTitleBar = new TitleBarXLarge(mActivity, mUiController, this,
+ mContentView);
mTitleBar.setProgress(100);
mTabBar = new TabBar(mActivity, mUiController, this);
mActionBar = mActivity.getActionBar();
@@ -103,16 +95,16 @@ public class XLargeUi extends BaseUi implements ScrollListener {
checkTabCount();
mPieControl = new PieControl(mActivity, mUiController, this);
mPieControl.attachToContainer(mContentView);
- Tab tab = getActiveTab();
- if ((tab != null) && (tab.getWebView() != null)) {
- tab.getWebView().setEmbeddedTitleBar(null);
+ WebView web = getWebView();
+ if (web != null) {
+ web.setEmbeddedTitleBar(null);
}
} else {
mActivity.getActionBar().show();
if (mPieControl != null) {
mPieControl.removeFromContainer(mContentView);
}
- WebView web = mTabControl.getCurrentWebView();
+ WebView web = getWebView();
if (web != null) {
web.setEmbeddedTitleBar(mTitleBar);
}
@@ -134,7 +126,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
public void onResume() {
super.onResume();
- if (!BrowserSettings.getInstance().useInstant()) {
+ if (!BrowserSettings.getInstance().useInstantSearch()) {
mTitleBar.clearCompletions();
}
}
@@ -149,23 +141,14 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
public WebView createWebView(boolean privateBrowsing) {
// Create a new WebView
- ScrollWebView w = new ScrollWebView(mActivity, null,
- android.R.attr.webViewStyle, privateBrowsing);
- initWebViewSettings(w);
+ BrowserWebView w = (BrowserWebView) super.createWebView(privateBrowsing);
w.setScrollListener(this);
- boolean supportsMultiTouch = mActivity.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH);
- w.getSettings().setDisplayZoomControls(!supportsMultiTouch);
- w.setExpandedTileBounds(true); // smoother scrolling
return w;
}
@Override
public WebView createSubWebView(boolean privateBrowsing) {
- ScrollWebView web = (ScrollWebView) createWebView(privateBrowsing);
- // no scroll listener for subview
- web.setScrollListener(null);
- return web;
+ return super.createWebView(privateBrowsing);
}
@Override
@@ -174,7 +157,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
}
void stopWebViewScrolling() {
- ScrollWebView web = (ScrollWebView) mUiController.getCurrentWebView();
+ BrowserWebView web = (BrowserWebView) mUiController.getCurrentWebView();
if (web != null) {
web.stopScroll();
}
@@ -188,31 +171,10 @@ public class XLargeUi extends BaseUi implements ScrollListener {
mTabBar.onProgress(tab, progress);
if (tab.inForeground()) {
mTitleBar.setProgress(progress);
- if (progress == 100) {
- if (!mTitleBar.isEditingUrl() && !mTitleBar.inAutoLogin()) {
- hideTitleBar();
- if (mUseQuickControls) {
- mTitleBar.setShowProgressOnly(false);
- }
- }
- } else {
- if (!isTitleBarShowing()) {
- if (mUseQuickControls && !mTitleBar.isEditingUrl()) {
- mTitleBar.setShowProgressOnly(true);
- setTitleGravity(Gravity.TOP);
- }
- showTitleBar();
- }
- }
}
}
@Override
- public boolean needsRestoreAllTabs() {
- return true;
- }
-
- @Override
public void addTab(Tab tab) {
mTabBar.onNewTab(tab);
}
@@ -223,9 +185,8 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
public void setActiveTab(final Tab tab) {
- cancelTitleBarAnimation(true);
- mSkipTitleBarAnimations = true;
- stopEditingUrl();
+ mTitleBar.cancelTitleBarAnimation(true);
+ mTitleBar.setSkipTitleBarAnimations(true);
if (mUseQuickControls) {
if (mActiveTab != null) {
captureTab(mActiveTab);
@@ -233,12 +194,12 @@ public class XLargeUi extends BaseUi implements ScrollListener {
}
super.setActiveTab(tab, true);
setActiveTab(tab, true);
- mSkipTitleBarAnimations = false;
+ mTitleBar.setSkipTitleBarAnimations(false);
}
@Override
void setActiveTab(Tab tab, boolean needsAttaching) {
- ScrollWebView view = (ScrollWebView) tab.getWebView();
+ BrowserWebView view = (BrowserWebView) tab.getWebView();
// TabControl.setCurrentTab has been called before this,
// so the tab is guaranteed to have a webview
if (view == null) {
@@ -259,7 +220,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
}
mTabBar.onSetActiveTab(tab);
if (tab.isInVoiceSearchMode()) {
- showVoiceTitleBar(tab.getVoiceDisplayTitle());
+ showVoiceTitleBar(tab.getVoiceDisplayTitle(), tab.getVoiceSearchResults());
} else {
revertVoiceTitleBar(tab);
}
@@ -267,15 +228,6 @@ public class XLargeUi extends BaseUi implements ScrollListener {
tab.getTopWindow().requestFocus();
}
- public void captureTab(final Tab tab) {
- Bitmap sshot = Controller.createScreenshot(tab,
- (int) mActivity.getResources()
- .getDimension(R.dimen.qc_thumb_width),
- (int) mActivity.getResources()
- .getDimension(R.dimen.qc_thumb_height));
- tab.setScreenshot(sshot);
- }
-
@Override
public void updateTabs(List<Tab> tabs) {
mTabBar.updateTabs(tabs);
@@ -284,11 +236,11 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
public void removeTab(Tab tab) {
- cancelTitleBarAnimation(true);
- mSkipTitleBarAnimations = true;
+ mTitleBar.cancelTitleBarAnimation(true);
+ mTitleBar.setSkipTitleBarAnimations(true);
super.removeTab(tab);
mTabBar.onRemoveTab(tab);
- mSkipTitleBarAnimations = false;
+ mTitleBar.setSkipTitleBarAnimations(false);
}
protected void onRemoveTabCompleted(Tab tab) {
@@ -304,17 +256,10 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
public void editUrl(boolean clearInput) {
- if (mUiController.isInCustomActionMode()) {
- mUiController.endActionMode();
+ if (mUseQuickControls) {
+ getTitleBar().setShowProgressOnly(false);
}
- showTitleBar();
- mTitleBar.startEditingUrl(clearInput);
- }
-
- void showTitleBarAndEdit() {
- mTitleBar.setShowProgressOnly(false);
- showTitleBar();
- mTitleBar.startEditingUrl(false);
+ super.editUrl(clearInput);
}
void stopEditingUrl() {
@@ -324,24 +269,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
protected void showTitleBar() {
if (canShowTitleBar()) {
- if (mUseQuickControls) {
- mContentView.addView(mTitleBar);
- } else {
- if (!mSkipTitleBarAnimations) {
- cancelTitleBarAnimation(false);
- int visibleHeight = getVisibleTitleHeight();
- float startPos = (-mTitleBar.getEmbeddedHeight() + visibleHeight);
- if (mTitleBar.getTranslationY() != 0) {
- startPos = Math.max(startPos, mTitleBar.getTranslationY());
- }
- mTitleBarAnimator = ObjectAnimator.ofFloat(mTitleBar,
- "translationY",
- startPos, 0);
- mTitleBarAnimator.start();
- }
- setTitleGravity(Gravity.TOP);
- }
- super.showTitleBar();
+ mTitleBar.show();
mTabBar.onShowTitleBar();
}
}
@@ -350,66 +278,10 @@ public class XLargeUi extends BaseUi implements ScrollListener {
protected void hideTitleBar() {
if (isTitleBarShowing()) {
mTabBar.onHideTitleBar();
- if (mUseQuickControls) {
- mContentView.removeView(mTitleBar);
- } else {
- if (!mSkipTitleBarAnimations) {
- cancelTitleBarAnimation(false);
- int visibleHeight = getVisibleTitleHeight();
- mTitleBarAnimator = ObjectAnimator.ofFloat(mTitleBar,
- "translationY", mTitleBar.getTranslationY(),
- (-mTitleBar.getEmbeddedHeight() + visibleHeight));
- mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
- mTitleBarAnimator.start();
- } else {
- setTitleGravity(Gravity.NO_GRAVITY);
- }
- }
- super.hideTitleBar();
+ mTitleBar.hide();
}
}
- private void cancelTitleBarAnimation(boolean reset) {
- if (mTitleBarAnimator != null) {
- mTitleBarAnimator.cancel();
- mTitleBarAnimator = null;
- }
- if (reset) {
- mTitleBar.setTranslationY(0);
- }
- }
-
- private int getVisibleTitleHeight() {
- WebView webview = mActiveTab != null ? mActiveTab.getWebView() : null;
- return webview != null ? webview.getVisibleTitleHeight() : 0;
- }
-
- private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
-
- boolean mWasCanceled;
- @Override
- public void onAnimationStart(Animator animation) {
- mWasCanceled = false;
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mWasCanceled) {
- mTitleBar.setTranslationY(0);
- }
- setTitleGravity(Gravity.NO_GRAVITY);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCanceled = true;
- }
- };
-
public boolean isEditingUrl() {
return mTitleBar.isEditingUrl();
}
@@ -421,12 +293,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
@Override
protected void setTitleGravity(int gravity) {
- if (mUseQuickControls) {
- FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mTitleBar.getLayoutParams();
- lp.gravity = gravity;
- mTitleBar.setLayoutParams(lp);
- } else {
+ if (!mUseQuickControls) {
super.setTitleGravity(gravity);
}
}
@@ -460,18 +327,6 @@ public class XLargeUi extends BaseUi implements ScrollListener {
}
@Override
- protected void updateAutoLogin(Tab tab, boolean animate) {
- mTitleBar.updateAutoLogin(tab, animate);
- }
-
- protected void refreshWebView() {
- Tab tab = getActiveTab();
- if ((tab != null) && (tab.getWebView() != null)) {
- tab.getWebView().invalidate();
- }
- }
-
- @Override
public void setUrlTitle(Tab tab) {
super.setUrlTitle(tab);
mTabBar.onUrlAndTitle(tab, tab.getUrl(), tab.getTitle());
@@ -485,11 +340,7 @@ public class XLargeUi extends BaseUi implements ScrollListener {
}
@Override
- public void showVoiceTitleBar(String title) {
- List<String> vsresults = null;
- if (getActiveTab() != null) {
- vsresults = getActiveTab().getVoiceSearchResults();
- }
+ public void showVoiceTitleBar(String title, List<String> vsresults) {
mTitleBar.setInVoiceMode(true, vsresults);
mTitleBar.setDisplayTitle(title);
}
@@ -549,19 +400,4 @@ public class XLargeUi extends BaseUi implements ScrollListener {
return mTabBar;
}
- @Override
- public void registerDropdownChangeListener(DropdownChangeListener d) {
- mTitleBar.registerDropdownChangeListener(d);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (mUseQuickControls) {
- mPieControl.onMenuOpened(menu);
- return false;
- } else {
- return true;
- }
- }
-
}
diff --git a/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java b/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
index 261aa62..67563c0 100644
--- a/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
+++ b/src/com/android/browser/addbookmark/FolderSpinnerAdapter.java
@@ -19,33 +19,37 @@ package com.android.browser.addbookmark;
import com.android.browser.R;
import android.content.Context;
-import android.content.res.Resources;
-import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Adapter;
-import android.widget.SpinnerAdapter;
+import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* SpinnerAdapter used in the AddBookmarkPage to select where to save a
* bookmark/folder.
*/
-public class FolderSpinnerAdapter implements SpinnerAdapter {
- private boolean mIncludeHomeScreen;
- private boolean mIncludesRecentFolder;
- private long mRecentFolderId;
- private String mRecentFolderName;
+public class FolderSpinnerAdapter extends BaseAdapter {
public static final int HOME_SCREEN = 0;
public static final int ROOT_FOLDER = 1;
public static final int OTHER_FOLDER = 2;
public static final int RECENT_FOLDER = 3;
- public FolderSpinnerAdapter(boolean includeHomeScreen) {
+ private boolean mIncludeHomeScreen;
+ private boolean mIncludesRecentFolder;
+ private long mRecentFolderId;
+ private String mRecentFolderName;
+ private LayoutInflater mInflater;
+ private Context mContext;
+ private String mOtherFolderDisplayText;
+
+ public FolderSpinnerAdapter(Context context, boolean includeHomeScreen) {
mIncludeHomeScreen = includeHomeScreen;
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
}
public void addRecentFolder(long folderId, String folderName) {
@@ -56,8 +60,7 @@ public class FolderSpinnerAdapter implements SpinnerAdapter {
public long recentFolderId() { return mRecentFolderId; }
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ private void bindView(int position, View view, boolean isDropDown) {
int labelResource;
int drawableResource;
if (!mIncludeHomeScreen) {
@@ -84,26 +87,39 @@ public class FolderSpinnerAdapter implements SpinnerAdapter {
// assert
break;
}
- Context context = parent.getContext();
- LayoutInflater factory = LayoutInflater.from(context);
- TextView textView = (TextView) factory.inflate(R.layout.add_to_option, null);
+ TextView textView = (TextView) view;
if (position == RECENT_FOLDER) {
textView.setText(mRecentFolderName);
+ } else if (position == OTHER_FOLDER && !isDropDown
+ && mOtherFolderDisplayText != null) {
+ textView.setText(mOtherFolderDisplayText);
} else {
textView.setText(labelResource);
}
- Drawable drawable = context.getResources().getDrawable(drawableResource);
+ textView.setGravity(Gravity.CENTER_VERTICAL);
+ Drawable drawable = mContext.getResources().getDrawable(drawableResource);
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null,
null, null);
- return textView;
}
@Override
- public void registerDataSetObserver(DataSetObserver observer) {
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(
+ android.R.layout.simple_spinner_dropdown_item, parent, false);
+ }
+ bindView(position, convertView, true);
+ return convertView;
}
@Override
- public void unregisterDataSetObserver(DataSetObserver observer) {
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(android.R.layout.simple_spinner_item,
+ parent, false);
+ }
+ bindView(position, convertView, false);
+ return convertView;
}
@Override
@@ -133,24 +149,9 @@ public class FolderSpinnerAdapter implements SpinnerAdapter {
return true;
}
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return getDropDownView(position, convertView, parent);
- }
-
- @Override
- public int getItemViewType(int position) {
- // Never want to recycle views
- return Adapter.IGNORE_ITEM_VIEW_TYPE;
- }
-
- @Override
- public int getViewTypeCount() {
- return 1;
+ public void setOtherFolderDisplayText(String parentTitle) {
+ mOtherFolderDisplayText = parentTitle;
+ notifyDataSetChanged();
}
- @Override
- public boolean isEmpty() {
- return false;
- }
}
diff --git a/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java b/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java
index e51a629..50ba758 100644
--- a/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java
+++ b/src/com/android/browser/autocomplete/SuggestiveAutoCompleteTextView.java
@@ -752,7 +752,7 @@ public class SuggestiveAutoCompleteTextView extends EditText implements Filter.F
}
private void updateText(SuggestionsAdapter adapter) {
- if (!BrowserSettings.getInstance().useInstant()) {
+ if (!BrowserSettings.getInstance().useInstantSearch()) {
return;
}
diff --git a/src/com/android/browser/preferences/AccessibilityPreferencesFragment.java b/src/com/android/browser/preferences/AccessibilityPreferencesFragment.java
new file mode 100644
index 0000000..99bd687
--- /dev/null
+++ b/src/com/android/browser/preferences/AccessibilityPreferencesFragment.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 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.preferences;
+
+import com.android.browser.PreferenceKeys;
+import com.android.browser.R;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.view.View;
+
+public class AccessibilityPreferencesFragment extends PreferenceFragment
+ implements Preference.OnPreferenceChangeListener {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.accessibility_preferences);
+
+ Preference e = findPreference(PreferenceKeys.PREF_TEXT_SIZE);
+ e.setOnPreferenceChangeListener(this);
+ e.setSummary(getVisualTextSizeName(
+ getPreferenceScreen().getSharedPreferences()
+ .getString(PreferenceKeys.PREF_TEXT_SIZE, null)) );
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setItemsCanFocus(true);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference pref, Object objValue) {
+ if (getActivity() == null) {
+ // We aren't attached, so don't accept preferences changes from the
+ // invisible UI.
+ return false;
+ }
+
+ if (pref.getKey().equals(PreferenceKeys.PREF_TEXT_SIZE)) {
+ pref.setSummary(getVisualTextSizeName((String) objValue));
+ return true;
+ }
+ return false;
+ }
+
+ private CharSequence getVisualTextSizeName(String enumName) {
+ Resources res = getActivity().getResources();
+ CharSequence[] visualNames = res.getTextArray(R.array.pref_text_size_choices);
+ CharSequence[] enumNames = res.getTextArray(R.array.pref_text_size_values);
+
+ // Sanity check
+ if (visualNames.length != enumNames.length) {
+ return "";
+ }
+
+ int length = enumNames.length;
+ for (int i = 0; i < length; i++) {
+ if (enumNames[i].equals(enumName)) {
+ return visualNames[i];
+ }
+ }
+
+ return "";
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/browser/preferences/AdvancedPreferencesFragment.java b/src/com/android/browser/preferences/AdvancedPreferencesFragment.java
index e2e45f5..2cc504e 100644
--- a/src/com/android/browser/preferences/AdvancedPreferencesFragment.java
+++ b/src/com/android/browser/preferences/AdvancedPreferencesFragment.java
@@ -17,7 +17,7 @@
package com.android.browser.preferences;
import com.android.browser.BrowserActivity;
-import com.android.browser.BrowserSettings;
+import com.android.browser.PreferenceKeys;
import com.android.browser.R;
import android.content.Intent;
@@ -46,28 +46,22 @@ public class AdvancedPreferencesFragment extends PreferenceFragment
addPreferencesFromResource(R.xml.advanced_preferences);
PreferenceScreen websiteSettings = (PreferenceScreen) findPreference(
- BrowserSettings.PREF_WEBSITE_SETTINGS);
+ PreferenceKeys.PREF_WEBSITE_SETTINGS);
websiteSettings.setFragment(WebsiteSettingsFragment.class.getName());
- Preference e = findPreference(BrowserSettings.PREF_TEXT_SIZE);
- e.setOnPreferenceChangeListener(this);
- e.setSummary(getVisualTextSizeName(
- getPreferenceScreen().getSharedPreferences()
- .getString(BrowserSettings.PREF_TEXT_SIZE, null)) );
-
- e = findPreference(BrowserSettings.PREF_DEFAULT_ZOOM);
+ Preference e = findPreference(PreferenceKeys.PREF_DEFAULT_ZOOM);
e.setOnPreferenceChangeListener(this);
e.setSummary(getVisualDefaultZoomName(
getPreferenceScreen().getSharedPreferences()
- .getString(BrowserSettings.PREF_DEFAULT_ZOOM, null)) );
+ .getString(PreferenceKeys.PREF_DEFAULT_ZOOM, null)) );
- e = findPreference(BrowserSettings.PREF_DEFAULT_TEXT_ENCODING);
+ e = findPreference(PreferenceKeys.PREF_DEFAULT_TEXT_ENCODING);
e.setOnPreferenceChangeListener(this);
- e = findPreference(BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS);
+ e = findPreference(PreferenceKeys.PREF_RESET_DEFAULT_PREFERENCES);
e.setOnPreferenceChangeListener(this);
- e = findPreference(BrowserSettings.PREF_PLUGIN_STATE);
+ e = findPreference(PreferenceKeys.PREF_PLUGIN_STATE);
e.setOnPreferenceChangeListener(this);
updatePluginSummary((ListPreference) e);
}
@@ -85,7 +79,7 @@ public class AdvancedPreferencesFragment extends PreferenceFragment
public void onResume() {
super.onResume();
final PreferenceScreen websiteSettings = (PreferenceScreen) findPreference(
- BrowserSettings.PREF_WEBSITE_SETTINGS);
+ PreferenceKeys.PREF_WEBSITE_SETTINGS);
websiteSettings.setEnabled(false);
WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
@Override
@@ -114,23 +108,20 @@ public class AdvancedPreferencesFragment extends PreferenceFragment
return false;
}
- if (pref.getKey().equals(BrowserSettings.PREF_TEXT_SIZE)) {
- pref.setSummary(getVisualTextSizeName((String) objValue));
- return true;
- } else if (pref.getKey().equals(BrowserSettings.PREF_DEFAULT_ZOOM)) {
+ if (pref.getKey().equals(PreferenceKeys.PREF_DEFAULT_ZOOM)) {
pref.setSummary(getVisualDefaultZoomName((String) objValue));
return true;
- } else if (pref.getKey().equals(BrowserSettings.PREF_DEFAULT_TEXT_ENCODING)) {
+ } else if (pref.getKey().equals(PreferenceKeys.PREF_DEFAULT_TEXT_ENCODING)) {
pref.setSummary((String) objValue);
return true;
- } else if (pref.getKey().equals(BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS)) {
+ } else if (pref.getKey().equals(PreferenceKeys.PREF_RESET_DEFAULT_PREFERENCES)) {
Boolean value = (Boolean) objValue;
if (value.booleanValue() == true) {
startActivity(new Intent(BrowserActivity.ACTION_RESTART, null,
getActivity(), BrowserActivity.class));
return true;
}
- } else if (pref.getKey().equals(BrowserSettings.PREF_PLUGIN_STATE)) {
+ } else if (pref.getKey().equals(PreferenceKeys.PREF_PLUGIN_STATE)) {
ListPreference lp = (ListPreference) pref;
lp.setValue((String) objValue);
updatePluginSummary(lp);
@@ -139,26 +130,6 @@ public class AdvancedPreferencesFragment extends PreferenceFragment
return false;
}
- private CharSequence getVisualTextSizeName(String enumName) {
- Resources res = getActivity().getResources();
- CharSequence[] visualNames = res.getTextArray(R.array.pref_text_size_choices);
- CharSequence[] enumNames = res.getTextArray(R.array.pref_text_size_values);
-
- // Sanity check
- if (visualNames.length != enumNames.length) {
- return "";
- }
-
- int length = enumNames.length;
- for (int i = 0; i < length; i++) {
- if (enumNames[i].equals(enumName)) {
- return visualNames[i];
- }
- }
-
- return "";
- }
-
private CharSequence getVisualDefaultZoomName(String enumName) {
Resources res = getActivity().getResources();
CharSequence[] visualNames = res.getTextArray(R.array.pref_default_zoom_choices);
diff --git a/src/com/android/browser/preferences/DebugPreferencesFragment.java b/src/com/android/browser/preferences/DebugPreferencesFragment.java
index 0a82371..984c12a 100644
--- a/src/com/android/browser/preferences/DebugPreferencesFragment.java
+++ b/src/com/android/browser/preferences/DebugPreferencesFragment.java
@@ -18,21 +18,14 @@ package com.android.browser.preferences;
import com.android.browser.BrowserActivity;
import com.android.browser.BrowserSettings;
-import com.android.browser.Controller;
+import com.android.browser.PreferenceKeys;
import com.android.browser.R;
-import android.content.Context;
import android.content.Intent;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceActivity.Header;
import android.preference.PreferenceFragment;
-import android.preference.PreferenceManager.OnActivityResultListener;
-
-import java.io.IOException;
-import java.io.Serializable;
public class DebugPreferencesFragment extends PreferenceFragment
implements OnPreferenceChangeListener {
@@ -43,11 +36,7 @@ public class DebugPreferencesFragment extends PreferenceFragment
// Load the XML preferences file
addPreferencesFromResource(R.xml.debug_preferences);
- if (BrowserSettings.getInstance().showDebugSettings()) {
- addPreferencesFromResource(R.xml.hidden_debug_preferences);
- }
-
- Preference e = findPreference(BrowserSettings.PREF_HARDWARE_ACCEL);
+ Preference e = findPreference(PreferenceKeys.PREF_ENABLE_HARDWARE_ACCEL);
e.setOnPreferenceChangeListener(this);
}
diff --git a/src/com/android/browser/preferences/GeneralPreferencesFragment.java b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
index 0c63ab5..879b95d 100644
--- a/src/com/android/browser/preferences/GeneralPreferencesFragment.java
+++ b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
@@ -19,7 +19,7 @@ package com.android.browser.preferences;
import com.android.browser.BrowserBookmarksPage;
import com.android.browser.BrowserHomepagePreference;
import com.android.browser.BrowserPreferencesPage;
-import com.android.browser.BrowserSettings;
+import com.android.browser.PreferenceKeys;
import com.android.browser.R;
import com.android.browser.widget.BookmarkThumbnailWidgetProvider;
@@ -62,10 +62,10 @@ public class GeneralPreferencesFragment extends PreferenceFragment
// Load the XML preferences file
addPreferencesFromResource(R.xml.general_preferences);
- Preference e = findPreference(BrowserSettings.PREF_HOMEPAGE);
+ Preference e = findPreference(PreferenceKeys.PREF_HOMEPAGE);
e.setOnPreferenceChangeListener(this);
e.setSummary(getPreferenceScreen().getSharedPreferences()
- .getString(BrowserSettings.PREF_HOMEPAGE, null));
+ .getString(PreferenceKeys.PREF_HOMEPAGE, null));
((BrowserHomepagePreference) e).setCurrentPage(
getActivity().getIntent().getStringExtra(BrowserPreferencesPage.CURRENT_PAGE));
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
@@ -81,7 +81,7 @@ public class GeneralPreferencesFragment extends PreferenceFragment
return false;
}
- if (pref.getKey().equals(BrowserSettings.PREF_HOMEPAGE)) {
+ if (pref.getKey().equals(PreferenceKeys.PREF_HOMEPAGE)) {
pref.setSummary((String) objValue);
return true;
}
@@ -202,8 +202,8 @@ public class GeneralPreferencesFragment extends PreferenceFragment
new GetAccountsTask(getActivity()).execute();
PreferenceScreen autoFillSettings =
- (PreferenceScreen)findPreference(BrowserSettings.PREF_AUTOFILL_PROFILE);
- autoFillSettings.setDependency(BrowserSettings.PREF_AUTOFILL_ENABLED);
+ (PreferenceScreen)findPreference(PreferenceKeys.PREF_AUTOFILL_PROFILE);
+ autoFillSettings.setDependency(PreferenceKeys.PREF_AUTOFILL_ENABLED);
}
@Override
diff --git a/src/com/android/browser/preferences/LabPreferencesFragment.java b/src/com/android/browser/preferences/LabPreferencesFragment.java
index a06dc3e..f99b96d 100644
--- a/src/com/android/browser/preferences/LabPreferencesFragment.java
+++ b/src/com/android/browser/preferences/LabPreferencesFragment.java
@@ -18,6 +18,7 @@ package com.android.browser.preferences;
import com.android.browser.BrowserActivity;
import com.android.browser.BrowserSettings;
+import com.android.browser.PreferenceKeys;
import com.android.browser.R;
import com.android.browser.search.SearchEngine;
@@ -41,22 +42,26 @@ public class LabPreferencesFragment extends PreferenceFragment
// Load the XML preferences file
addPreferencesFromResource(R.xml.lab_preferences);
- Preference e = findPreference(BrowserSettings.PREF_QUICK_CONTROLS);
- e.setOnPreferenceChangeListener(this);
- useInstantPref = findPreference(BrowserSettings.PREF_USE_INSTANT);
+ Preference e = findPreference(PreferenceKeys.PREF_ENABLE_QUICK_CONTROLS);
+ if (e != null) {
+ e.setOnPreferenceChangeListener(this);
+ }
+ useInstantPref = findPreference(PreferenceKeys.PREF_USE_INSTANT_SEARCH);
}
@Override
public void onResume() {
super.onResume();
- useInstantPref.setEnabled(false);
+ if (useInstantPref != null) {
+ useInstantPref.setEnabled(false);
- // Enable the "use instant" preference only if the selected
- // search engine is google.
- if (mBrowserSettings.getSearchEngine() != null) {
- final String currentName = mBrowserSettings.getSearchEngine().getName();
- if (SearchEngine.GOOGLE.equals(currentName)) {
- useInstantPref.setEnabled(true);
+ // Enable the "use instant" preference only if the selected
+ // search engine is google.
+ if (mBrowserSettings.getSearchEngine() != null) {
+ final String currentName = mBrowserSettings.getSearchEngine().getName();
+ if (SearchEngine.GOOGLE.equals(currentName)) {
+ useInstantPref.setEnabled(true);
+ }
}
}
}
diff --git a/src/com/android/browser/preferences/MinFontSizePreference.java b/src/com/android/browser/preferences/MinFontSizePreference.java
new file mode 100644
index 0000000..22092b0
--- /dev/null
+++ b/src/com/android/browser/preferences/MinFontSizePreference.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 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.preferences;
+
+import com.android.browser.R;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+public class MinFontSizePreference extends Preference implements OnSeekBarChangeListener {
+
+ // range from 1:6..24
+ static final int MIN = 5;
+ static final int MAX = 23;
+ private int mProgress;
+ View mRoot;
+
+ public MinFontSizePreference(
+ Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public MinFontSizePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MinFontSizePreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ if (mRoot == null) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mRoot = inflater.inflate(R.layout.min_font_size, parent, false);
+ SeekBar seek = (SeekBar) mRoot.findViewById(R.id.seekbar);
+ seek.setMax((MAX - MIN));
+ seek.setProgress(mProgress);
+ seek.setOnSeekBarChangeListener(this);
+ }
+ return mRoot;
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ mProgress = restoreValue ? getPersistedInt(mProgress)
+ : (Integer) defaultValue;
+ mProgress -= 1;
+ }
+
+ @Override
+ public void onProgressChanged(
+ SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser) {
+ if (progress == 0) {
+ persistInt(1);
+ } else {
+ persistInt(progress + MIN + 1);
+ }
+ }
+ mRoot.invalidate();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ /*
+ * Suppose a client uses this preference type without persisting. We
+ * must save the instance state so it is able to, for example, survive
+ * orientation changes.
+ */
+
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ // Save the instance state
+ final SavedState myState = new SavedState(superState);
+ myState.progress = mProgress;
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (!state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ // Restore the instance state
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ mProgress = myState.progress;
+ notifyChanged();
+ }
+
+ /**
+ * SavedState, a subclass of {@link BaseSavedState}, will store the state
+ * of MyPreference, a subclass of Preference.
+ * <p>
+ * It is important to always call through to super methods.
+ */
+ private static class SavedState extends BaseSavedState {
+ int progress;
+
+ public SavedState(Parcel source) {
+ super(source);
+
+ // Restore the click counter
+ progress = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+
+ // Save the click counter
+ dest.writeInt(progress);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+}
diff --git a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
index 2266608..35e6e43 100644
--- a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
+++ b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
@@ -16,7 +16,7 @@
package com.android.browser.preferences;
-import com.android.browser.BrowserSettings;
+import com.android.browser.PreferenceKeys;
import com.android.browser.R;
import android.app.Activity;
@@ -28,18 +28,14 @@ import android.preference.PreferenceFragment;
public class PrivacySecurityPreferencesFragment extends PreferenceFragment
implements Preference.OnPreferenceChangeListener {
- private BrowserSettings mSettings;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mSettings = BrowserSettings.getInstance();
-
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.privacy_security_preferences);
- Preference e = findPreference(BrowserSettings.PREF_CLEAR_HISTORY);
+ Preference e = findPreference(PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY);
e.setOnPreferenceChangeListener(this);
}
@@ -50,7 +46,7 @@ public class PrivacySecurityPreferencesFragment extends PreferenceFragment
@Override
public boolean onPreferenceChange(Preference pref, Object objValue) {
- if (pref.getKey().equals(BrowserSettings.PREF_CLEAR_HISTORY)
+ if (pref.getKey().equals(PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY)
&& ((Boolean) objValue).booleanValue() == true) {
// Need to tell the browser to remove the parent/child relationship
// between tabs
diff --git a/src/com/android/browser/preferences/WebViewPreview.java b/src/com/android/browser/preferences/WebViewPreview.java
new file mode 100644
index 0000000..a269dbd
--- /dev/null
+++ b/src/com/android/browser/preferences/WebViewPreview.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 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.preferences;
+
+import com.android.browser.BrowserSettings;
+import com.android.browser.R;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+import android.preference.Preference;
+import android.preference.PreferenceManager;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+
+public class WebViewPreview extends Preference implements OnSharedPreferenceChangeListener {
+
+ // 80 char line width limit? Rules are made to be broken.
+ static final String HTML_FORMAT = "<html><head><style type=\"text/css\">p { margin: 2px auto;}</style><body><p style=\"font-size: .4em\">%s</p><p style=\"font-size: .7em\">%s</p><p style=\"font-size: 1em\">%s</p><p style=\"font-size: 1.3em\">%s</p><p style=\"font-size: 1.6em\">%s</p></body></html>";
+
+ String HTML;
+ private View mRoot;
+ private WebView mWebView;
+
+ public WebViewPreview(
+ Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ public WebViewPreview(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public WebViewPreview(Context context) {
+ super(context);
+ init(context);
+ }
+
+ void init(Context context) {
+ Resources res = context.getResources();
+ Object[] visualNames = res.getStringArray(R.array.pref_text_size_choices);
+ HTML = String.format(HTML_FORMAT, visualNames);
+ }
+
+ void updatePreview() {
+ if (mWebView == null) return;
+
+ WebSettings ws = mWebView.getSettings();
+ BrowserSettings bs = BrowserSettings.getInstance();
+ ws.setMinimumFontSize(bs.getMinimumFontSize());
+ ws.setTextSize(bs.getTextSize());
+ mWebView.loadData(HTML, "text/html", "utf-8");
+ }
+
+ @Override
+ public View getView(View convertView, ViewGroup parent) {
+ if (mWebView == null) {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mRoot = inflater.inflate(R.layout.webview_preview, parent, false);
+ mWebView = (WebView) mRoot.findViewById(R.id.webview);
+ mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+ updatePreview();
+ return mRoot;
+ }
+
+ @Override
+ protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
+ super.onAttachedToHierarchy(preferenceManager);
+ getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void onPrepareForRemoval() {
+ getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ super.onPrepareForRemoval();
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ updatePreview();
+ }
+
+}
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/provider/BrowserProvider.java
index f69665c..b55b84a 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/provider/BrowserProvider.java
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-package com.android.browser;
+package com.android.browser.provider;
+import com.android.browser.BrowserSettings;
+import com.android.browser.R;
import com.android.browser.search.SearchEngine;
import android.app.SearchManager;
@@ -40,7 +42,6 @@ import android.os.Process;
import android.preference.PreferenceManager;
import android.provider.Browser;
import android.provider.Browser.BookmarkColumns;
-import android.provider.Settings;
import android.speech.RecognizerResultsIntent;
import android.text.TextUtils;
import android.util.Log;
@@ -58,14 +59,14 @@ public class BrowserProvider extends ContentProvider {
private SQLiteOpenHelper mOpenHelper;
private BackupManager mBackupManager;
- private static final String sDatabaseName = "browser.db";
+ static final String sDatabaseName = "browser.db";
private static final String TAG = "BrowserProvider";
private static final String ORDER_BY = "visits DESC, date DESC";
private static final String PICASA_URL = "http://picasaweb.google.com/m/" +
"viewer?source=androidclient";
- private static final String[] TABLE_NAMES = new String[] {
+ static final String[] TABLE_NAMES = new String[] {
"bookmarks", "searches"
};
private static final String[] SUGGEST_PROJECTION = new String[] {
@@ -113,7 +114,7 @@ public class BrowserProvider extends ContentProvider {
// make sure that these match the index of TABLE_NAMES
- private static final int URI_MATCH_BOOKMARKS = 0;
+ static final int URI_MATCH_BOOKMARKS = 0;
private static final int URI_MATCH_SEARCHES = 1;
// (id % 10) should match the table name index
private static final int URI_MATCH_BOOKMARKS_ID = 10;
@@ -179,7 +180,7 @@ public class BrowserProvider extends ContentProvider {
// XXX: This is a major hack to remove our dependency on gsf constants and
// its content provider. http://b/issue?id=2425179
- static String getClientId(ContentResolver cr) {
+ public static String getClientId(ContentResolver cr) {
String ret = "android-google";
Cursor legacyClientIdCursor = null;
Cursor searchClientIdCursor = null;
@@ -245,7 +246,7 @@ public class BrowserProvider extends ContentProvider {
return sb;
}
- private static class DatabaseHelper extends SQLiteOpenHelper {
+ static class DatabaseHelper extends SQLiteOpenHelper {
private Context mContext;
public DatabaseHelper(Context context) {
@@ -839,7 +840,7 @@ public class BrowserProvider extends ContentProvider {
* by the SearchDialog when the BrowserActivity is in voice search mode.
* @param results Strings to display in the dropdown from the SearchDialog
*/
- /* package */ void setQueryResults(ArrayList<String> results) {
+ public /* package */ void setQueryResults(ArrayList<String> results) {
synchronized (mResultsCursorLock) {
if (results == null) {
mResultsCursor = null;
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index d154f20..a8739ca 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.android.browser.BookmarkUtils;
import com.android.browser.BrowserBookmarksPage;
import com.android.browser.R;
+import com.android.browser.UrlUtils;
import com.android.browser.widget.BookmarkThumbnailWidgetProvider;
import com.android.common.content.SyncStateContentProviderHelper;
@@ -63,6 +64,7 @@ import android.provider.SyncStateContract;
import android.text.TextUtils;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@@ -86,6 +88,8 @@ public class BrowserProvider2 extends SQLiteContentProvider {
static final String TABLE_HISTORY_JOIN_IMAGES = "history LEFT OUTER JOIN images " +
"ON history.url = images." + Images.URL;
+ static final String VIEW_ACCOUNTS = "v_accounts";
+
static final String FORMAT_COMBINED_JOIN_SUBQUERY_JOIN_IMAGES =
"history LEFT OUTER JOIN (%s) bookmarks " +
"ON history.url = bookmarks.url LEFT OUTER JOIN images " +
@@ -203,6 +207,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
map = ACCOUNTS_PROJECTION_MAP;
map.put(Accounts.ACCOUNT_TYPE, Accounts.ACCOUNT_TYPE);
map.put(Accounts.ACCOUNT_NAME, Accounts.ACCOUNT_NAME);
+ map.put(Accounts.ROOT_ID, Accounts.ROOT_ID);
// Bookmarks
map = BOOKMARKS_PROJECTION_MAP;
@@ -328,7 +333,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
final class DatabaseHelper extends SQLiteOpenHelper {
static final String DATABASE_NAME = "browser2.db";
- static final int DATABASE_VERSION = 26;
+ static final int DATABASE_VERSION = 27;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -390,15 +395,109 @@ public class BrowserProvider2 extends SQLiteContentProvider {
Settings.VALUE + " TEXT NOT NULL" +
");");
+ createAccountsView(db);
+
mSyncHelper.createDatabase(db);
- createDefaultBookmarks(db);
+ if (!importFromBrowserProvider(db)) {
+ createDefaultBookmarks(db);
+ }
+ }
+
+ boolean importFromBrowserProvider(SQLiteDatabase db) {
+ Context context = getContext();
+ File oldDbFile = context.getDatabasePath(BrowserProvider.sDatabaseName);
+ if (oldDbFile.exists()) {
+ BrowserProvider.DatabaseHelper helper =
+ new BrowserProvider.DatabaseHelper(context);
+ SQLiteDatabase oldDb = helper.getWritableDatabase();
+ Cursor c = null;
+ try {
+ String table = BrowserProvider.TABLE_NAMES[BrowserProvider.URI_MATCH_BOOKMARKS];
+ // Import bookmarks
+ c = oldDb.query(table,
+ new String[] {
+ BookmarkColumns.URL, // 0
+ BookmarkColumns.TITLE, // 1
+ BookmarkColumns.FAVICON, // 2
+ BookmarkColumns.TOUCH_ICON, // 3
+ }, BookmarkColumns.BOOKMARK + "!=0", null,
+ null, null, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(Bookmarks.URL, c.getString(0));
+ values.put(Bookmarks.TITLE, c.getString(1));
+ values.put(Bookmarks.POSITION, 0);
+ values.put(Bookmarks.PARENT, FIXED_ID_ROOT);
+ ContentValues imageValues = new ContentValues();
+ imageValues.put(Images.URL, c.getString(0));
+ imageValues.put(Images.FAVICON, c.getBlob(2));
+ imageValues.put(Images.TOUCH_ICON, c.getBlob(3));
+ db.insertOrThrow(TABLE_IMAGES, Images.THUMBNAIL, imageValues);
+ db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.DIRTY, values);
+ }
+ c.close();
+ }
+ // Import history
+ c = oldDb.query(table,
+ new String[] {
+ BookmarkColumns.URL, // 0
+ BookmarkColumns.TITLE, // 1
+ BookmarkColumns.VISITS, // 2
+ BookmarkColumns.DATE, // 3
+ BookmarkColumns.CREATED, // 4
+ }, null, null, null, null, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(History.URL, c.getString(0));
+ values.put(History.TITLE, c.getString(1));
+ values.put(History.VISITS, c.getInt(2));
+ values.put(History.DATE_LAST_VISITED, c.getLong(3));
+ values.put(History.DATE_CREATED, c.getLong(4));
+ db.insertOrThrow(TABLE_HISTORY, History.FAVICON, values);
+ }
+ c.close();
+ }
+ // Wipe the old DB, in case the delete fails.
+ oldDb.delete(table, null, null);
+ } finally {
+ if (c != null) c.close();
+ oldDb.close();
+ helper.close();
+ }
+ if (!oldDbFile.delete()) {
+ oldDbFile.deleteOnExit();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void createAccountsView(SQLiteDatabase db) {
+ db.execSQL("CREATE VIEW IF NOT EXISTS v_accounts AS "
+ + "SELECT NULL AS " + Accounts.ACCOUNT_NAME
+ + ", NULL AS " + Accounts.ACCOUNT_TYPE
+ + ", " + FIXED_ID_ROOT + " AS " + Accounts.ROOT_ID
+ + " UNION ALL SELECT " + Accounts.ACCOUNT_NAME
+ + ", " + Accounts.ACCOUNT_TYPE + ", "
+ + Bookmarks._ID + " AS " + Accounts.ROOT_ID
+ + " FROM " + TABLE_BOOKMARKS + " WHERE "
+ + ChromeSyncColumns.SERVER_UNIQUE + " = \""
+ + ChromeSyncColumns.FOLDER_NAME_BOOKMARKS_BAR + "\" AND "
+ + Bookmarks.IS_DELETED + " = 0");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO write upgrade logic
- db.execSQL("DROP VIEW IF EXISTS combined");
+ if (oldVersion < 27) {
+ createAccountsView(db);
+ }
+ if (oldVersion < 26) {
+ db.execSQL("DROP VIEW IF EXISTS combined");
+ }
if (oldVersion < 25) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_HISTORY);
@@ -650,10 +749,8 @@ public class BrowserProvider2 extends SQLiteContentProvider {
String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
switch (match) {
case ACCOUNTS: {
- qb.setTables(TABLE_BOOKMARKS);
+ qb.setTables(VIEW_ACCOUNTS);
qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
- qb.setDistinct(true);
- qb.appendWhere(Bookmarks.ACCOUNT_NAME + " IS NOT NULL");
break;
}
@@ -1523,9 +1620,35 @@ public class BrowserProvider2 extends SQLiteContentProvider {
String[] selectionArgs, boolean callerIsSyncAdapter) {
int count = 0;
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- Cursor cursor = db.query(TABLE_BOOKMARKS,
- new String[] { Bookmarks._ID, Bookmarks.VERSION, Bookmarks.URL },
+ final String[] bookmarksProjection = new String[] {
+ Bookmarks._ID, // 0
+ Bookmarks.VERSION, // 1
+ Bookmarks.URL, // 2
+ Bookmarks.TITLE, // 3
+ Bookmarks.IS_FOLDER, // 4
+ Bookmarks.ACCOUNT_NAME, // 5
+ Bookmarks.ACCOUNT_TYPE, // 6
+ };
+ Cursor cursor = db.query(TABLE_BOOKMARKS, bookmarksProjection,
selection, selectionArgs, null, null, null);
+ boolean updatingParent = values.containsKey(Bookmarks.PARENT);
+ String parentAccountName = null;
+ String parentAccountType = null;
+ if (updatingParent) {
+ long parent = values.getAsLong(Bookmarks.PARENT);
+ Cursor c = db.query(TABLE_BOOKMARKS, new String[] {
+ Bookmarks.ACCOUNT_NAME, Bookmarks.ACCOUNT_TYPE},
+ "_id = ?", new String[] { Long.toString(parent) },
+ null, null, null);
+ if (c.moveToFirst()) {
+ parentAccountName = c.getString(0);
+ parentAccountType = c.getString(1);
+ c.close();
+ }
+ } else if (values.containsKey(Bookmarks.ACCOUNT_NAME)
+ || values.containsKey(Bookmarks.ACCOUNT_TYPE)) {
+ // TODO: Implement if needed (no one needs this yet)
+ }
try {
String[] args = new String[1];
// Mark the bookmark dirty if the caller isn't a sync adapter
@@ -1542,12 +1665,47 @@ public class BrowserProvider2 extends SQLiteContentProvider {
ContentValues imageValues = extractImageValues(values, url);
while (cursor.moveToNext()) {
- args[0] = cursor.getString(0);
- if (!callerIsSyncAdapter) {
- // increase the local version for non-sync changes
- values.put(Bookmarks.VERSION, cursor.getLong(1) + 1);
+ long id = cursor.getLong(0);
+ args[0] = Long.toString(id);
+ String accountName = cursor.getString(5);
+ String accountType = cursor.getString(6);
+ // If we are updating the parent and either the account name or
+ // type do not match that of the new parent
+ if (updatingParent
+ && (!TextUtils.equals(accountName, parentAccountName)
+ || !TextUtils.equals(accountType, parentAccountType))) {
+ // Parent is a different account
+ // First, insert a new bookmark/folder with the new account
+ // Then, if this is a folder, reparent all it's children
+ // Finally, delete the old bookmark/folder
+ ContentValues newValues = valuesFromCursor(cursor);
+ newValues.putAll(values);
+ newValues.remove(Bookmarks._ID);
+ newValues.remove(Bookmarks.VERSION);
+ newValues.put(Bookmarks.ACCOUNT_NAME, parentAccountName);
+ newValues.put(Bookmarks.ACCOUNT_TYPE, parentAccountType);
+ Uri insertUri = insertInTransaction(Bookmarks.CONTENT_URI,
+ newValues, callerIsSyncAdapter);
+ long newId = ContentUris.parseId(insertUri);
+ if (cursor.getInt(4) != 0) {
+ // This is a folder, reparent
+ ContentValues updateChildren = new ContentValues(1);
+ updateChildren.put(Bookmarks.PARENT, newId);
+ count += updateBookmarksInTransaction(updateChildren,
+ Bookmarks.PARENT + "=?", new String[] {
+ Long.toString(id)}, callerIsSyncAdapter);
+ }
+ // Now, delete the old one
+ Uri uri = ContentUris.withAppendedId(Bookmarks.CONTENT_URI, id);
+ deleteInTransaction(uri, null, null, callerIsSyncAdapter);
+ count += 1;
+ } else {
+ if (!callerIsSyncAdapter) {
+ // increase the local version for non-sync changes
+ values.put(Bookmarks.VERSION, cursor.getLong(1) + 1);
+ }
+ count += db.update(TABLE_BOOKMARKS, values, "_id=?", args);
}
- count += db.update(TABLE_BOOKMARKS, values, "_id=?", args);
// Update the images over in their table
if (imageValues != null) {
@@ -1570,6 +1728,29 @@ public class BrowserProvider2 extends SQLiteContentProvider {
return count;
}
+ ContentValues valuesFromCursor(Cursor c) {
+ int count = c.getColumnCount();
+ ContentValues values = new ContentValues(count);
+ String[] colNames = c.getColumnNames();
+ for (int i = 0; i < count; i++) {
+ switch (c.getType(i)) {
+ case Cursor.FIELD_TYPE_BLOB:
+ values.put(colNames[i], c.getBlob(i));
+ break;
+ case Cursor.FIELD_TYPE_FLOAT:
+ values.put(colNames[i], c.getFloat(i));
+ break;
+ case Cursor.FIELD_TYPE_INTEGER:
+ values.put(colNames[i], c.getLong(i));
+ break;
+ case Cursor.FIELD_TYPE_STRING:
+ values.put(colNames[i], c.getString(i));
+ break;
+ }
+ }
+ return values;
+ }
+
/**
* Does a query to find the matching bookmarks and updates each one with the provided values.
*/
@@ -1724,7 +1905,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
case SUGGEST_COLUMN_INTENT_DATA_ID:
case SUGGEST_COLUMN_TEXT_2_TEXT_ID:
case SUGGEST_COLUMN_TEXT_2_URL_ID:
- return mSource.getString(URL_INDEX);
+ return UrlUtils.stripUrl(mSource.getString(URL_INDEX));
case SUGGEST_COLUMN_TEXT_1_ID:
return mSource.getString(TITLE_INDEX);
case SUGGEST_COLUMN_ICON_1_ID:
diff --git a/src/com/android/browser/search/SearchEngines.java b/src/com/android/browser/search/SearchEngines.java
index a159f17..fd967f9 100644
--- a/src/com/android/browser/search/SearchEngines.java
+++ b/src/com/android/browser/search/SearchEngines.java
@@ -32,7 +32,7 @@ public class SearchEngines {
private static final String TAG = "SearchEngines";
public static SearchEngine getDefaultSearchEngine(Context context) {
- if (BrowserSettings.getInstance().useInstant()) {
+ if (BrowserSettings.getInstance().useInstantSearch()) {
return new InstantSearchEngine(context, DefaultSearchEngine.create(context));
}
diff --git a/src/com/android/browser/view/BookmarkContainer.java b/src/com/android/browser/view/BookmarkContainer.java
new file mode 100644
index 0000000..260b05e
--- /dev/null
+++ b/src/com/android/browser/view/BookmarkContainer.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 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.view;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewConfiguration;
+import android.widget.RelativeLayout;
+
+public class BookmarkContainer extends RelativeLayout implements OnClickListener {
+
+ private OnClickListener mClickListener;
+
+ public BookmarkContainer(Context context) {
+ super(context);
+ init();
+ }
+
+ public BookmarkContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public BookmarkContainer(
+ Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ void init() {
+ setFocusable(true);
+ super.setOnClickListener(this);
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable d) {
+ super.setBackgroundDrawable(d);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener l) {
+ mClickListener = l;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+ updateTransitionDrawable(isPressed());
+ }
+
+ void updateTransitionDrawable(boolean pressed) {
+ final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
+ Drawable selector = getBackground();
+ if (selector != null && selector instanceof StateListDrawable) {
+ Drawable d = ((StateListDrawable)selector).getCurrent();
+ if (d != null && d instanceof TransitionDrawable) {
+ if (pressed && isLongClickable()) {
+ ((TransitionDrawable) d).startTransition(longPressTimeout);
+ } else {
+ ((TransitionDrawable) d).resetTransition();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ updateTransitionDrawable(false);
+ if (mClickListener != null) {
+ mClickListener.onClick(view);
+ }
+ }
+}
diff --git a/src/com/android/browser/view/BookmarkExpandableGridView.java b/src/com/android/browser/view/BookmarkExpandableGridView.java
new file mode 100644
index 0000000..2cf4a65
--- /dev/null
+++ b/src/com/android/browser/view/BookmarkExpandableGridView.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2011 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.view;
+
+import com.android.browser.BookmarkDragHandler;
+import com.android.browser.BreadCrumbView;
+import com.android.browser.BrowserBookmarksAdapter;
+import com.android.browser.R;
+import com.android.browser.BookmarkDragHandler.BookmarkDragAdapter;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.provider.BrowserContract;
+import android.util.AttributeSet;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class BookmarkExpandableGridView extends ExpandableListView
+ implements BreadCrumbView.Controller {
+
+ private BookmarkAccountAdapter mAdapter;
+ private int mColumnWidth;
+ private Context mContext;
+ private OnChildClickListener mOnChildClickListener;
+ private ContextMenuInfo mContextMenuInfo = null;
+ private OnCreateContextMenuListener mOnCreateContextMenuListener;
+ private boolean mLongClickable;
+ private BreadCrumbView.Controller mBreadcrumbController;
+ private BookmarkDragHandler mDragHandler;
+
+ public BookmarkExpandableGridView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public BookmarkExpandableGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public BookmarkExpandableGridView(
+ Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(context);
+ }
+
+ void init(Context context) {
+ mContext = context;
+ setItemsCanFocus(true);
+ setLongClickable(false);
+ mAdapter = new BookmarkAccountAdapter(mContext);
+ super.setAdapter(mAdapter);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mAdapter.measureChildren();
+ }
+
+ @Override
+ public void setAdapter(ExpandableListAdapter adapter) {
+ throw new RuntimeException("Not supported");
+ }
+
+ public void setColumnWidthFromLayout(int layout) {
+ LayoutInflater infalter = LayoutInflater.from(mContext);
+ View v = infalter.inflate(layout, this, false);
+ v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mColumnWidth = v.getMeasuredWidth();
+ }
+
+ public void setHorizontalSpacing(int horizontalSpacing) {
+ // TODO Auto-generated method stub
+ }
+
+ public void clearAccounts() {
+ mAdapter.clear();
+ }
+
+ public void addAccount(String accountName, BrowserBookmarksAdapter adapter) {
+ // First, check if it already exists
+ int indexOf = mAdapter.mGroups.indexOf(accountName);
+ if (indexOf >= 0) {
+ BrowserBookmarksAdapter existing = mAdapter.mChildren.get(indexOf);
+ if (existing != adapter) {
+ existing.unregisterDataSetObserver(mAdapter.mObserver);
+ // Replace the existing one
+ mAdapter.mChildren.remove(indexOf);
+ mAdapter.mChildren.add(indexOf, adapter);
+ adapter.registerDataSetObserver(mAdapter.mObserver);
+ }
+ } else {
+ mAdapter.mGroups.add(accountName);
+ mAdapter.mChildren.add(adapter);
+ adapter.registerDataSetObserver(mAdapter.mObserver);
+ }
+ mAdapter.notifyDataSetChanged();
+ expandGroup(mAdapter.getGroupCount() - 1);
+ }
+
+ @Override
+ public void setOnChildClickListener(OnChildClickListener onChildClickListener) {
+ mOnChildClickListener = onChildClickListener;
+ }
+
+ @Override
+ public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
+ mOnCreateContextMenuListener = l;
+ if (!mLongClickable) {
+ mLongClickable = true;
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ public void createContextMenu(ContextMenu menu) {
+ // The below is copied from View - we want to bypass the override
+ // in AbsListView
+
+ ContextMenuInfo menuInfo = getContextMenuInfo();
+
+ // Sets the current menu info so all items added to menu will have
+ // my extra info set.
+ ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo);
+
+ onCreateContextMenu(menu);
+ if (mOnCreateContextMenuListener != null) {
+ mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
+ }
+
+ // Clear the extra information so subsequent items that aren't mine don't
+ // have my extra info.
+ ((MenuBuilder)menu).setCurrentMenuInfo(null);
+
+ if (mParent != null) {
+ mParent.createContextMenu(menu);
+ }
+ }
+
+ @Override
+ public boolean showContextMenuForChild(View originalView) {
+ int groupPosition = (Integer) originalView.getTag(R.id.group_position);
+ int childPosition = (Integer) originalView.getTag(R.id.child_position);
+
+ mContextMenuInfo = new BookmarkContextMenuInfo(childPosition,
+ groupPosition);
+ if (getParent() != null) {
+ getParent().showContextMenuForChild(this);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onTop(BreadCrumbView view, int level, Object data) {
+ if (mBreadcrumbController != null) {
+ mBreadcrumbController.onTop(view, level, data);
+ }
+ }
+
+ public void setBreadcrumbController(BreadCrumbView.Controller controller) {
+ mBreadcrumbController = controller;
+ }
+
+ @Override
+ protected ContextMenuInfo getContextMenuInfo() {
+ return mContextMenuInfo;
+ }
+
+ public BrowserBookmarksAdapter getChildAdapter(int groupPosition) {
+ return mAdapter.mChildren.get(groupPosition);
+ }
+
+ public BookmarkDragAdapter getDragAdapter() {
+ return mDragAdapter;
+ }
+
+ private BookmarkDragAdapter mDragAdapter = new BookmarkDragAdapter() {
+
+ @Override
+ public void setBookmarkDragHandler(BookmarkDragHandler handler) {
+ mDragHandler = handler;
+ }
+
+ @Override
+ public Cursor getItemForView(View v) {
+ int groupPosition = (Integer) v.getTag(R.id.group_position);
+ int childPosition = (Integer) v.getTag(R.id.child_position);
+ return getChildAdapter(groupPosition).getItem(childPosition);
+ }
+ };
+
+ private OnClickListener mChildClickListener = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ int groupPosition = (Integer) v.getTag(R.id.group_position);
+ int childPosition = (Integer) v.getTag(R.id.child_position);
+ long id = (Long) v.getTag(R.id.child_id);
+ if (mOnChildClickListener != null) {
+ mOnChildClickListener.onChildClick(BookmarkExpandableGridView.this,
+ v, groupPosition, childPosition, id);
+ }
+ }
+ };
+
+ private OnClickListener mGroupOnClickListener = new OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ int groupPosition = (Integer) v.getTag(R.id.group_position);
+ if (isGroupExpanded(groupPosition)) {
+ collapseGroup(groupPosition);
+ } else {
+ expandGroup(groupPosition, true);
+ }
+ }
+ };
+
+ private OnLongClickListener mChildOnLongClickListener = new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ int groupPosition = (Integer) v.getTag(R.id.group_position);
+ int childPosition = (Integer) v.getTag(R.id.child_position);
+ long id = (Long) v.getTag(R.id.child_id);
+ Cursor c = getChildAdapter(groupPosition).getItem(childPosition);
+ return mDragHandler.startDrag(v, c, id);
+ }
+ };
+
+ public BreadCrumbView getBreadCrumbs(int groupPosition) {
+ return mAdapter.getBreadCrumbView(groupPosition);
+ }
+
+ class BookmarkAccountAdapter extends BaseExpandableListAdapter {
+ ArrayList<BrowserBookmarksAdapter> mChildren;
+ ArrayList<String> mGroups;
+ HashMap<Integer, BreadCrumbView> mBreadcrumbs =
+ new HashMap<Integer, BreadCrumbView>();
+ LayoutInflater mInflater;
+ int mRowCount = 1; // assume at least 1 child fits in a row
+ int mLastViewWidth = -1;
+ int mRowPadding = -1;
+ DataSetObserver mObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ notifyDataSetChanged();
+ }
+ };
+
+ public BookmarkAccountAdapter(Context context) {
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
+ mChildren = new ArrayList<BrowserBookmarksAdapter>();
+ mGroups = new ArrayList<String>();
+ }
+
+ public void clear() {
+ mGroups.clear();
+ mChildren.clear();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public Object getChild(int groupPosition, int childPosition) {
+ return mChildren.get(groupPosition).getItem(childPosition);
+ }
+
+ @Override
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ @Override
+ public View getChildView(int groupPosition, int childPosition,
+ boolean isLastChild, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.bookmark_grid_row, parent, false);
+ }
+ LinearLayout row = (LinearLayout) convertView;
+ row.setPadding(
+ mRowPadding,
+ row.getPaddingTop(),
+ mRowPadding,
+ row.getPaddingBottom());
+ if (row.getChildCount() > mRowCount) {
+ row.removeViews(mRowCount, row.getChildCount() - mRowCount);
+ }
+ for (int i = 0; i < mRowCount; i++) {
+ View cv = null;
+ if (row.getChildCount() > i) {
+ cv = row.getChildAt(i);
+ }
+ int realChildPosition = (childPosition * mRowCount) + i;
+ BrowserBookmarksAdapter childAdapter = mChildren.get(groupPosition);
+ if (realChildPosition < childAdapter.getCount()) {
+ View v = childAdapter.getView(realChildPosition, cv, row);
+ v.setTag(R.id.group_position, groupPosition);
+ v.setTag(R.id.child_position, realChildPosition);
+ v.setTag(R.id.child_id, childAdapter.getItemId(realChildPosition));
+ v.setOnClickListener(mChildClickListener);
+ v.setLongClickable(mLongClickable);
+ if (mDragHandler != null) {
+ v.setOnLongClickListener(mChildOnLongClickListener);
+ mDragHandler.registerBookmarkDragHandler(v);
+ }
+ if (cv == null) {
+ row.addView(v);
+ } else if (cv != v) {
+ row.removeViewAt(i);
+ row.addView(v, i);
+ } else {
+ cv.setVisibility(View.VISIBLE);
+ }
+ } else if (cv != null) {
+ cv.setVisibility(View.GONE);
+ }
+ }
+ return row;
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ return (int) Math.ceil(
+ mChildren.get(groupPosition).getCount() / (float)mRowCount);
+ }
+
+ @Override
+ public Object getGroup(int groupPosition) {
+ return mChildren.get(groupPosition);
+ }
+
+ @Override
+ public int getGroupCount() {
+ return mGroups.size();
+ }
+
+ public void measureChildren() {
+ int viewWidth = getMeasuredWidth();
+ if (mLastViewWidth == viewWidth) return;
+
+ ViewGroup parent = (ViewGroup) mInflater.inflate(R.layout.bookmark_grid_row, null);
+ viewWidth -= parent.getPaddingLeft() + parent.getPaddingRight();
+ int rowCount = viewWidth / mColumnWidth;
+ int rowPadding = (viewWidth - (rowCount * mColumnWidth)) / 2;
+ boolean notify = rowCount != mRowCount || rowPadding != mRowPadding;
+ mRowCount = rowCount;
+ mRowPadding = rowPadding;
+ mLastViewWidth = viewWidth;
+ if (notify) {
+ notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded,
+ View view, ViewGroup parent) {
+ if (view == null) {
+ view = mInflater.inflate(R.layout.bookmark_group_view, parent, false);
+ view.setOnClickListener(mGroupOnClickListener);
+ }
+ view.setTag(R.id.group_position, groupPosition);
+ FrameLayout crumbHolder = (FrameLayout) view.findViewById(R.id.crumb_holder);
+ crumbHolder.removeAllViews();
+ BreadCrumbView crumbs = getBreadCrumbView(groupPosition);
+ if (crumbs.getParent() != null) {
+ ((ViewGroup)crumbs.getParent()).removeView(crumbs);
+ }
+ crumbHolder.addView(crumbs);
+ TextView name = (TextView) view.findViewById(R.id.group_name);
+ String groupName = mGroups.get(groupPosition);
+ if (groupName == null) {
+ groupName = mContext.getString(R.string.local_bookmarks);
+ }
+ name.setText(groupName);
+ return view;
+ }
+
+ public BreadCrumbView getBreadCrumbView(int groupPosition) {
+ BreadCrumbView crumbs = mBreadcrumbs.get(groupPosition);
+ if (crumbs == null) {
+ crumbs = (BreadCrumbView)
+ mInflater.inflate(R.layout.bookmarks_header, null);
+ crumbs.setController(BookmarkExpandableGridView.this);
+ crumbs.setUseBackButton(true);
+ crumbs.setMaxVisible(2);
+ String bookmarks = mContext.getString(R.string.bookmarks);
+ crumbs.pushView(bookmarks, false,
+ BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER);
+ crumbs.setTag(R.id.group_position, groupPosition);
+ mBreadcrumbs.put(groupPosition, crumbs);
+ }
+ return crumbs;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+ }
+
+ public static class BookmarkContextMenuInfo implements ContextMenuInfo {
+
+ private BookmarkContextMenuInfo(int childPosition, int groupPosition) {
+ this.childPosition = childPosition;
+ this.groupPosition = groupPosition;
+ }
+
+ public int childPosition;
+ public int groupPosition;
+ }
+
+}
diff --git a/src/com/android/browser/view/StopProgressView.java b/src/com/android/browser/view/StopProgressView.java
new file mode 100644
index 0000000..64fa5d0
--- /dev/null
+++ b/src/com/android/browser/view/StopProgressView.java
@@ -0,0 +1,98 @@
+
+package com.android.browser.view;
+
+import com.android.browser.R;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.ProgressBar;
+
+
+public class StopProgressView extends ProgressBar {
+
+ Drawable mOverlayDrawable;
+ Drawable mProgressDrawable;
+ int mWidth;
+ int mHeight;
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ * @param styleRes
+ */
+ public StopProgressView(Context context, AttributeSet attrs, int defStyle, int styleRes) {
+ super(context, attrs, defStyle, styleRes);
+ init(attrs);
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public StopProgressView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(attrs);
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public StopProgressView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs);
+ }
+
+ /**
+ * @param context
+ */
+ public StopProgressView(Context context) {
+ super(context);
+ init(null);
+ }
+
+ private void init(AttributeSet attrs) {
+ mProgressDrawable = getIndeterminateDrawable();
+ setImageDrawable(mContext.getResources()
+ .getDrawable(R.drawable.ic_stop_holo_dark));
+ }
+
+ public void hideProgress() {
+ setIndeterminateDrawable(null);
+ }
+
+ public void showProgress() {
+ setIndeterminateDrawable(mProgressDrawable);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mWidth = (right - left) * 2 / 3;
+ mHeight = (bottom - top) * 2 / 3;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mOverlayDrawable != null) {
+ int l = (getWidth() - mWidth) / 2;
+ int t = (getHeight() - mHeight) / 2;
+ mOverlayDrawable.setBounds(l, t, l + mWidth, t + mHeight);
+ mOverlayDrawable.draw(canvas);
+ }
+ }
+
+ public Drawable getDrawable() {
+ return mOverlayDrawable;
+ }
+
+ public void setImageDrawable(Drawable d) {
+ mOverlayDrawable = d;
+ }
+
+}
diff --git a/src/com/android/browser/RlzReceiver.java b/src/com/android/browser/view/TabHolderView.java
index 1dfb11a..c5a2b32 100644
--- a/src/com/android/browser/RlzReceiver.java
+++ b/src/com/android/browser/view/TabHolderView.java
@@ -14,25 +14,39 @@
* limitations under the License.
*/
-package com.android.browser;
+package com.android.browser.view;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
-/**
- * This {@link BroadcastReceiver} handles RLZ broadcast notifications.
- */
-public class RlzReceiver extends BroadcastReceiver {
- public static final String RLZ_VALUES_UPDATED_ACTION =
- "android.intent.action.RLZ_VALUES_UPDATED";
+public class TabHolderView extends LinearLayout {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (RLZ_VALUES_UPDATED_ACTION.equals(action)) {
- BrowserSettings settings = BrowserSettings.getInstance();
- settings.updateRlzValues(context);
- }
+ /**
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public TabHolderView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
}
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public TabHolderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * @param context
+ */
+ public TabHolderView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setPressed(boolean p) {}
+
}