diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:49 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:49 -0800 |
commit | 8611831e36b71c844a14788998728f3cd625b833 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /src/com/android/browser | |
parent | 1658a9bc00a3bd692908dcd5b9eb550a49f8f5ec (diff) | |
download | packages_apps_browser-8611831e36b71c844a14788998728f3cd625b833.zip packages_apps_browser-8611831e36b71c844a14788998728f3cd625b833.tar.gz packages_apps_browser-8611831e36b71c844a14788998728f3cd625b833.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'src/com/android/browser')
35 files changed, 0 insertions, 13775 deletions
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java deleted file mode 100644 index cf3fe70..0000000 --- a/src/com/android/browser/AddBookmarkPage.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2006 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.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Intent; -import android.content.res.Resources; -import android.database.Cursor; -import android.net.ParseException; -import android.net.WebAddress; -import android.os.Bundle; -import android.provider.Browser; -import android.view.View; -import android.view.Window; -import android.webkit.WebIconDatabase; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.Date; - -public class AddBookmarkPage extends Activity { - - private final String LOGTAG = "Bookmarks"; - - private EditText mTitle; - private EditText mAddress; - private TextView mButton; - private View mCancelButton; - private boolean mEditingExisting; - private Bundle mMap; - - private static final String[] mProjection = - { "_id", "url", "bookmark", "created", "title", "visits" }; - private static final String WHERE_CLAUSE = "url = ?"; - private final String[] SELECTION_ARGS = new String[1]; - - private View.OnClickListener mSaveBookmark = new View.OnClickListener() { - public void onClick(View v) { - if (save()) { - finish(); - Toast.makeText(AddBookmarkPage.this, R.string.bookmark_saved, - Toast.LENGTH_LONG).show(); - } - } - }; - - private View.OnClickListener mCancel = new View.OnClickListener() { - public void onClick(View v) { - finish(); - } - }; - - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - requestWindowFeature(Window.FEATURE_LEFT_ICON); - setContentView(R.layout.browser_add_bookmark); - setTitle(R.string.save_to_bookmarks); - getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_dialog_bookmark); - - String title = null; - String url = null; - mMap = getIntent().getExtras(); - if (mMap != null) { - Bundle b = mMap.getBundle("bookmark"); - if (b != null) { - mMap = b; - mEditingExisting = true; - setTitle(R.string.edit_bookmark); - } - title = mMap.getString("title"); - url = mMap.getString("url"); - } - - mTitle = (EditText) findViewById(R.id.title); - mTitle.setText(title); - mAddress = (EditText) findViewById(R.id.address); - mAddress.setText(url); - - - View.OnClickListener accept = mSaveBookmark; - mButton = (TextView) findViewById(R.id.OK); - mButton.setOnClickListener(accept); - - mCancelButton = findViewById(R.id.cancel); - mCancelButton.setOnClickListener(mCancel); - - if (!getWindow().getDecorView().isInTouchMode()) { - mButton.requestFocus(); - } - } - - /** - * Save the data to the database. - * Also, change the view to dialog stating - * that the webpage has been saved. - */ - boolean save() { - String title = mTitle.getText().toString().trim(); - String unfilteredUrl = - BrowserActivity.fixUrl(mAddress.getText().toString()); - boolean emptyTitle = title.length() == 0; - boolean emptyUrl = unfilteredUrl.trim().length() == 0; - Resources r = getResources(); - if (emptyTitle || emptyUrl) { - if (emptyTitle) { - mTitle.setError(r.getText(R.string.bookmark_needs_title)); - } - if (emptyUrl) { - mAddress.setError(r.getText(R.string.bookmark_needs_url)); - } - return false; - } - String url = unfilteredUrl; - if (!(url.startsWith("about:") || url.startsWith("data:") || url - .startsWith("file:"))) { - WebAddress address; - try { - address = new WebAddress(unfilteredUrl); - } catch (ParseException e) { - mAddress.setError(r.getText(R.string.bookmark_url_not_valid)); - return false; - } - if (address.mHost.length() == 0) { - mAddress.setError(r.getText(R.string.bookmark_url_not_valid)); - return false; - } - url = address.toString(); - } - try { - if (mEditingExisting) { - mMap.putString("title", title); - mMap.putString("url", url); - setResult(RESULT_OK, (new Intent()).setAction( - getIntent().toString()).putExtras(mMap)); - } else { - // Want to append to the beginning of the list - long creationTime = new Date().getTime(); - SELECTION_ARGS[0] = url; - ContentResolver cr = getContentResolver(); - Cursor c = cr.query(Browser.BOOKMARKS_URI, - mProjection, - WHERE_CLAUSE, - SELECTION_ARGS, - null); - ContentValues map = new ContentValues(); - if (c.moveToFirst() && c.getInt(c.getColumnIndexOrThrow( - Browser.BookmarkColumns.BOOKMARK)) == 0) { - // This means we have been to this site but not bookmarked - // it, so convert the history item to a bookmark - map.put(Browser.BookmarkColumns.CREATED, creationTime); - map.put(Browser.BookmarkColumns.TITLE, title); - map.put(Browser.BookmarkColumns.BOOKMARK, 1); - cr.update(Browser.BOOKMARKS_URI, map, - "_id = " + c.getInt(0), null); - } else { - int count = c.getCount(); - boolean matchedTitle = false; - for (int i = 0; i < count; i++) { - // One or more bookmarks already exist for this site. - // Check the names of each - c.moveToPosition(i); - if (c.getString(c.getColumnIndexOrThrow( - Browser.BookmarkColumns.TITLE)).equals(title)) { - // The old bookmark has the same name. - // Update its creation time. - map.put(Browser.BookmarkColumns.CREATED, - creationTime); - cr.update(Browser.BOOKMARKS_URI, map, - "_id = " + c.getInt(0), null); - matchedTitle = true; - } - } - if (!matchedTitle) { - // Adding a bookmark for a site the user has visited, - // or a new bookmark (with a different name) for a site - // the user has visited - map.put(Browser.BookmarkColumns.TITLE, title); - map.put(Browser.BookmarkColumns.URL, url); - map.put(Browser.BookmarkColumns.CREATED, creationTime); - map.put(Browser.BookmarkColumns.BOOKMARK, 1); - map.put(Browser.BookmarkColumns.DATE, 0); - int visits = 0; - if (count > 0) { - // The user has already bookmarked, and possibly - // visited this site. However, they are creating - // a new bookmark with the same url but a different - // name. The new bookmark should have the same - // number of visits as the already created bookmark. - visits = c.getInt(c.getColumnIndexOrThrow( - Browser.BookmarkColumns.VISITS)); - } - // Bookmark starts with 3 extra visits so that it will - // bubble up in the most visited and goto search box - map.put(Browser.BookmarkColumns.VISITS, visits + 3); - cr.insert(Browser.BOOKMARKS_URI, map); - } - } - WebIconDatabase.getInstance().retainIconForPageUrl(url); - c.deactivate(); - setResult(RESULT_OK); - } - } catch (IllegalStateException e) { - setTitle(r.getText(R.string.no_database)); - return false; - } - return true; - } -} diff --git a/src/com/android/browser/AddNewBookmark.java b/src/com/android/browser/AddNewBookmark.java deleted file mode 100644 index a75d002..0000000 --- a/src/com/android/browser/AddNewBookmark.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.Context; -import android.view.LayoutInflater; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -/** - * Custom layout for an item representing a bookmark in the browser. - */ - // FIXME: Remove BrowserBookmarkItem -class AddNewBookmark extends LinearLayout { - - private TextView mTextView; - private TextView mUrlText; - private ImageView mImageView; - - /** - * Instantiate a bookmark item, including a default favicon. - * - * @param context The application context for the item. - */ - AddNewBookmark(Context context) { - super(context); - - setWillNotDraw(false); - LayoutInflater factory = LayoutInflater.from(context); - factory.inflate(R.layout.add_new_bookmark, this); - mTextView = (TextView) findViewById(R.id.title); - mUrlText = (TextView) findViewById(R.id.url); - mImageView = (ImageView) findViewById(R.id.favicon); - } - - /** - * Copy this BookmarkItem to item. - * @param item BookmarkItem to receive the info from this BookmarkItem. - */ - /* package */ void copyTo(AddNewBookmark item) { - item.mTextView.setText(mTextView.getText()); - item.mUrlText.setText(mUrlText.getText()); - item.mImageView.setImageDrawable(mImageView.getDrawable()); - } - - /** - * Set the new url for the bookmark item. - * @param url The new url for the bookmark item. - */ - /* package */ void setUrl(String url) { - mUrlText.setText(url); - } -} diff --git a/src/com/android/browser/BookmarkItem.java b/src/com/android/browser/BookmarkItem.java deleted file mode 100644 index a70dd4f..0000000 --- a/src/com/android/browser/BookmarkItem.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.Context; -import android.graphics.Bitmap; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -/** - * Custom layout for an item representing a bookmark in the browser. - */ -class BookmarkItem extends LinearLayout { - - protected TextView mTextView; - protected TextView mUrlText; - protected ImageView mImageView; - protected String mUrl; - - /** - * Instantiate a bookmark item, including a default favicon. - * - * @param context The application context for the item. - */ - BookmarkItem(Context context) { - super(context); - - LayoutInflater factory = LayoutInflater.from(context); - factory.inflate(R.layout.history_item, this); - mTextView = (TextView) findViewById(R.id.title); - mUrlText = (TextView) findViewById(R.id.url); - mImageView = (ImageView) findViewById(R.id.favicon); - View star = findViewById(R.id.star); - star.setVisibility(View.GONE); - } - - /** - * Copy this BookmarkItem to item. - * @param item BookmarkItem to receive the info from this BookmarkItem. - */ - /* package */ void copyTo(BookmarkItem item) { - item.mTextView.setText(mTextView.getText()); - item.mUrlText.setText(mUrlText.getText()); - item.mImageView.setImageDrawable(mImageView.getDrawable()); - } - - /** - * Return the name assigned to this bookmark item. - */ - /* package */ String getName() { - return mTextView.getText().toString(); - } - - /** - * Return the TextView which holds the name of this bookmark item. - */ - /* package */ TextView getNameTextView() { - return mTextView; - } - - /* package */ String getUrl() { - return mUrl; - } - - /** - * Set the favicon for this item. - * - * @param b The new bitmap for this item. - * If it is null, will use the default. - */ - /* package */ void setFavicon(Bitmap b) { - if (b != null) { - mImageView.setImageBitmap(b); - } else { - mImageView.setImageResource(R.drawable.app_web_browser_sm); - } - } - - /** - * Set the new name for the bookmark item. - * - * @param name The new name for the bookmark item. - */ - /* package */ void setName(String name) { - mTextView.setText(name); - } - - /** - * Set the new url for the bookmark item. - * @param url The new url for the bookmark item. - */ - /* package */ void setUrl(String url) { - mUrlText.setText(url); - mUrl = url; - } -} diff --git a/src/com/android/browser/Browser.java b/src/com/android/browser/Browser.java deleted file mode 100644 index 32cee67..0000000 --- a/src/com/android/browser/Browser.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2006 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.util.Config; -import android.util.Log; - -import android.app.Application; -import android.content.Intent; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; - -import dalvik.system.VMRuntime; - -public class Browser extends Application { - - private final static String LOGTAG = "browser"; - - /** - * Specifies a heap utilization ratio that works better - * for the browser than the default ratio does. - */ - private final static float TARGET_HEAP_UTILIZATION = 0.75f; - - public Browser() { - } - - public void onCreate() { - if (Config.LOGV) - Log.v(LOGTAG, "Browser.onCreate: this=" + this); - // Fix heap utilization for better heap size characteristics. - VMRuntime.getRuntime().setTargetHeapUtilization( - TARGET_HEAP_UTILIZATION); - // create CookieSyncManager with current Context - CookieSyncManager.createInstance(this); - // remove all expired cookies - CookieManager.getInstance().removeExpiredCookie(); - } - - static Intent createBrowserViewIntent() { - Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); - return intent; - } -} - diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java deleted file mode 100644 index 0ca4248..0000000 --- a/src/com/android/browser/BrowserActivity.java +++ /dev/null @@ -1,4558 +0,0 @@ -/* - * Copyright (C) 2006 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.google.android.googleapps.IGoogleLoginService; -import com.google.android.googlelogin.GoogleLoginServiceConstants; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.app.SearchManager; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.DialogInterface.OnCancelListener; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.DrawFilter; -import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; -import android.graphics.Picture; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.PaintDrawable; -import android.hardware.SensorListener; -import android.hardware.SensorManager; -import android.net.ConnectivityManager; -import android.net.Uri; -import android.net.WebAddress; -import android.net.http.EventHandler; -import android.net.http.SslCertificate; -import android.net.http.SslError; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Debug; -import android.os.Environment; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.PowerManager; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.preference.PreferenceManager; -import android.provider.Browser; -import android.provider.Contacts; -import android.provider.Downloads; -import android.provider.MediaStore; -import android.provider.Contacts.Intents.Insert; -import android.text.IClipboard; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.text.util.Regex; -import android.util.Config; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.AnimationSet; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.ScaleAnimation; -import android.view.animation.TranslateAnimation; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; -import android.webkit.DownloadListener; -import android.webkit.HttpAuthHandler; -import android.webkit.SslErrorHandler; -import android.webkit.URLUtil; -import android.webkit.WebChromeClient; -import android.webkit.WebHistoryItem; -import android.webkit.WebIconDatabase; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.URLEncoder; -import java.text.ParseException; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class BrowserActivity extends Activity - implements KeyTracker.OnKeyTracker, - View.OnCreateContextMenuListener, - DownloadListener { - - private IGoogleLoginService mGls = null; - private ServiceConnection mGlsConnection = null; - - private SensorManager mSensorManager = null; - - /* Whitelisted webpages - private static HashSet<String> sWhiteList; - - static { - sWhiteList = new HashSet<String>(); - sWhiteList.add("cnn.com/"); - sWhiteList.add("espn.go.com/"); - sWhiteList.add("nytimes.com/"); - sWhiteList.add("engadget.com/"); - sWhiteList.add("yahoo.com/"); - sWhiteList.add("msn.com/"); - sWhiteList.add("amazon.com/"); - sWhiteList.add("consumerist.com/"); - sWhiteList.add("google.com/m/news"); - } - */ - - private void setupHomePage() { - final Runnable getAccount = new Runnable() { - public void run() { - // Lower priority - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - // get the default home page - String homepage = mSettings.getHomePage(); - - try { - if (mGls == null) return; - - String hostedUser = mGls.getAccount(GoogleLoginServiceConstants.PREFER_HOSTED); - String googleUser = mGls.getAccount(GoogleLoginServiceConstants.REQUIRE_GOOGLE); - - // three cases: - // - // hostedUser == googleUser - // The device has only a google account - // - // hostedUser != googleUser - // The device has a hosted account and a google account - // - // hostedUser != null, googleUser == null - // The device has only a hosted account (so far) - - // developers might have no accounts at all - if (hostedUser == null) return; - - if (googleUser == null || !hostedUser.equals(googleUser)) { - String domain = hostedUser.substring(hostedUser.lastIndexOf('@')+1); - homepage = "http://www.google.com/m/a/" + domain + "?client=ms-" + - SystemProperties.get("persist.sys.com.google.clientid", "unknown"); - } - } catch (RemoteException ignore) { - // Login service died; carry on - } catch (RuntimeException ignore) { - // Login service died; carry on - } finally { - finish(homepage); - } - } - - private void finish(final String homepage) { - mHandler.post(new Runnable() { - public void run() { - mSettings.setHomePage(BrowserActivity.this, homepage); - resumeAfterCredentials(); - - // as this is running in a separate thread, - // BrowserActivity's onDestroy() may have been called, - // which also calls unbindService(). - if (mGlsConnection != null) { - // we no longer need to keep GLS open - unbindService(mGlsConnection); - mGlsConnection = null; - } - } }); - } }; - - final boolean[] done = { false }; - - // Open a connection to the Google Login Service. The first - // time the connection is established, set up the homepage depending on - // the account in a background thread. - mGlsConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mGls = IGoogleLoginService.Stub.asInterface(service); - if (done[0] == false) { - done[0] = true; - Thread account = new Thread(getAccount); - account.setName("GLSAccount"); - account.start(); - } - } - public void onServiceDisconnected(ComponentName className) { - mGls = null; - } - }; - - bindService(GoogleLoginServiceConstants.SERVICE_INTENT, - mGlsConnection, Context.BIND_AUTO_CREATE); - } - - /** - * This class is in charge of installing pre-packaged plugins - * from the Browser assets directory to the user's data partition. - * Plugins are loaded from the "plugins" directory in the assets; - * Anything that is in this directory will be copied over to the - * user data partition in app_plugins. - */ - private class CopyPlugins implements Runnable { - final static String TAG = "PluginsInstaller"; - final static String ZIP_FILTER = "assets/plugins/"; - final static String APK_PATH = "/system/app/Browser.apk"; - final static String PLUGIN_EXTENSION = ".so"; - final static String TEMPORARY_EXTENSION = "_temp"; - final static String BUILD_INFOS_FILE = "build.prop"; - final static String SYSTEM_BUILD_INFOS_FILE = "/system/" - + BUILD_INFOS_FILE; - final int BUFSIZE = 4096; - boolean mDoOverwrite = false; - String pluginsPath; - Context mContext; - File pluginsDir; - AssetManager manager; - - public CopyPlugins (boolean overwrite, Context context) { - mDoOverwrite = overwrite; - mContext = context; - } - - /** - * Returned a filtered list of ZipEntry. - * We list all the files contained in the zip and - * only returns the ones starting with the ZIP_FILTER - * path. - * - * @param zip the zip file used. - */ - public Vector<ZipEntry> pluginsFilesFromZip(ZipFile zip) { - Vector<ZipEntry> list = new Vector<ZipEntry>(); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = (ZipEntry) entries.nextElement(); - if (entry.getName().startsWith(ZIP_FILTER)) { - list.add(entry); - } - } - return list; - } - - /** - * Utility method to copy the content from an inputstream - * to a file output stream. - */ - public void copyStreams(InputStream is, FileOutputStream fos) { - BufferedOutputStream os = null; - try { - byte data[] = new byte[BUFSIZE]; - int count; - os = new BufferedOutputStream(fos, BUFSIZE); - while ((count = is.read(data, 0, BUFSIZE)) != -1) { - os.write(data, 0, count); - } - os.flush(); - } catch (IOException e) { - Log.e(TAG, "Exception while copying: " + e); - } finally { - try { - if (os != null) { - os.close(); - } - } catch (IOException e2) { - Log.e(TAG, "Exception while closing the stream: " + e2); - } - } - } - - /** - * Returns a string containing the contents of a file - * - * @param file the target file - */ - private String contentsOfFile(File file) { - String ret = null; - FileInputStream is = null; - try { - byte[] buffer = new byte[BUFSIZE]; - int count; - is = new FileInputStream(file); - StringBuffer out = new StringBuffer(); - - while ((count = is.read(buffer, 0, BUFSIZE)) != -1) { - out.append(new String(buffer, 0, count)); - } - ret = out.toString(); - } catch (IOException e) { - Log.e(TAG, "Exception getting contents of file " + e); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e2) { - Log.e(TAG, "Exception while closing the file: " + e2); - } - } - } - return ret; - } - - /** - * Utility method to initialize the user data plugins path. - */ - public void initPluginsPath() { - BrowserSettings s = BrowserSettings.getInstance(); - pluginsPath = s.getPluginsPath(); - if (pluginsPath == null) { - s.loadFromDb(mContext); - pluginsPath = s.getPluginsPath(); - } - if (Config.LOGV) { - Log.v(TAG, "Plugin path: " + pluginsPath); - } - } - - /** - * Utility method to delete a file or a directory - * - * @param file the File to delete - */ - public void deleteFile(File file) { - File[] files = file.listFiles(); - if ((files != null) && files.length > 0) { - for (int i=0; i< files.length; i++) { - deleteFile(files[i]); - } - } - if (!file.delete()) { - Log.e(TAG, file.getPath() + " could not get deleted"); - } - } - - /** - * Clean the content of the plugins directory. - * We delete the directory, then recreate it. - */ - public void cleanPluginsDirectory() { - if (Config.LOGV) { - Log.v(TAG, "delete plugins directory: " + pluginsPath); - } - File pluginsDirectory = new File(pluginsPath); - deleteFile(pluginsDirectory); - pluginsDirectory.mkdir(); - } - - - /** - * Copy the SYSTEM_BUILD_INFOS_FILE file containing the - * informations about the system build to the - * BUILD_INFOS_FILE in the plugins directory. - */ - public void copyBuildInfos() { - try { - if (Config.LOGV) { - Log.v(TAG, "Copy build infos to the plugins directory"); - } - File buildInfoFile = new File(SYSTEM_BUILD_INFOS_FILE); - File buildInfoPlugins = new File(pluginsPath, BUILD_INFOS_FILE); - copyStreams(new FileInputStream(buildInfoFile), - new FileOutputStream(buildInfoPlugins)); - } catch (IOException e) { - Log.e(TAG, "Exception while copying the build infos: " + e); - } - } - - /** - * Returns true if the current system is newer than the - * system that installed the plugins. - * We determinate this by checking the build number of the system. - * - * At the end of the plugins copy operation, we copy the - * SYSTEM_BUILD_INFOS_FILE to the BUILD_INFOS_FILE. - * We then just have to load both and compare them -- if they - * are different the current system is newer. - * - * Loading and comparing the strings should be faster than - * creating a hash, the files being rather small. Extracting the - * version number would require some parsing which may be more - * brittle. - */ - public boolean newSystemImage() { - try { - File buildInfoFile = new File(SYSTEM_BUILD_INFOS_FILE); - File buildInfoPlugins = new File(pluginsPath, BUILD_INFOS_FILE); - if (!buildInfoPlugins.exists()) { - if (Config.LOGV) { - Log.v(TAG, "build.prop in plugins directory " + pluginsPath - + " does not exist, therefore it's a new system image"); - } - return true; - } else { - String buildInfo = contentsOfFile(buildInfoFile); - String buildInfoPlugin = contentsOfFile(buildInfoPlugins); - if (buildInfo == null || buildInfoPlugin == null - || buildInfo.compareTo(buildInfoPlugin) != 0) { - if (Config.LOGV) { - Log.v(TAG, "build.prop are different, " - + " therefore it's a new system image"); - } - return true; - } - } - } catch (Exception e) { - Log.e(TAG, "Exc in newSystemImage(): " + e); - } - return false; - } - - /** - * Check if the version of the plugins contained in the - * Browser assets is the same as the version of the plugins - * in the plugins directory. - * We simply iterate on every file in the assets/plugins - * and return false if a file listed in the assets does - * not exist in the plugins directory. - */ - private boolean checkIsDifferentVersions() { - try { - ZipFile zip = new ZipFile(APK_PATH); - Vector<ZipEntry> files = pluginsFilesFromZip(zip); - int zipFilterLength = ZIP_FILTER.length(); - - Enumeration entries = files.elements(); - while (entries.hasMoreElements()) { - ZipEntry entry = (ZipEntry) entries.nextElement(); - String path = entry.getName().substring(zipFilterLength); - File outputFile = new File(pluginsPath, path); - if (!outputFile.exists()) { - if (Config.LOGV) { - Log.v(TAG, "checkIsDifferentVersions(): extracted file " - + path + " does not exist, we have a different version"); - } - return true; - } - } - } catch (IOException e) { - Log.e(TAG, "Exception in checkDifferentVersions(): " + e); - } - return false; - } - - /** - * Copy every files from the assets/plugins directory - * to the app_plugins directory in the data partition. - * Once copied, we copy over the SYSTEM_BUILD_INFOS file - * in the plugins directory. - * - * NOTE: we directly access the content from the Browser - * package (it's a zip file) and do not use AssetManager - * as there is a limit of 1Mb (see Asset.h) - */ - public void run() { - // Lower the priority - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - try { - if (pluginsPath == null) { - Log.e(TAG, "No plugins path found!"); - return; - } - - ZipFile zip = new ZipFile(APK_PATH); - Vector<ZipEntry> files = pluginsFilesFromZip(zip); - Vector<File> plugins = new Vector<File>(); - int zipFilterLength = ZIP_FILTER.length(); - - Enumeration entries = files.elements(); - while (entries.hasMoreElements()) { - ZipEntry entry = (ZipEntry) entries.nextElement(); - String path = entry.getName().substring(zipFilterLength); - File outputFile = new File(pluginsPath, path); - outputFile.getParentFile().mkdirs(); - - if (outputFile.exists() && !mDoOverwrite) { - if (Config.LOGV) { - Log.v(TAG, path + " already extracted."); - } - } else { - if (path.endsWith(PLUGIN_EXTENSION)) { - // We rename plugins to be sure a half-copied - // plugin is not loaded by the browser. - plugins.add(outputFile); - outputFile = new File(pluginsPath, - path + TEMPORARY_EXTENSION); - } - FileOutputStream fos = new FileOutputStream(outputFile); - if (Config.LOGV) { - Log.v(TAG, "copy " + entry + " to " - + pluginsPath + "/" + path); - } - copyStreams(zip.getInputStream(entry), fos); - } - } - - // We now rename the .so we copied, once all their resources - // are safely copied over to the user data partition. - Enumeration elems = plugins.elements(); - while (elems.hasMoreElements()) { - File renamedFile = (File) elems.nextElement(); - File sourceFile = new File(renamedFile.getPath() - + TEMPORARY_EXTENSION); - if (Config.LOGV) { - Log.v(TAG, "rename " + sourceFile.getPath() - + " to " + renamedFile.getPath()); - } - sourceFile.renameTo(renamedFile); - } - - copyBuildInfos(); - - // Refresh the plugin list. - if (mTabControl.getCurrentWebView() != null) { - mTabControl.getCurrentWebView().refreshPlugins(false); - } - } catch (IOException e) { - Log.e(TAG, "IO Exception: " + e); - } - } - }; - - /** - * Copy the content of assets/plugins/ to the app_plugins directory - * in the data partition. - * - * This function is called every time the browser is started. - * We first check if the system image is newer than the one that - * copied the plugins (if there's plugins in the data partition). - * If this is the case, we then check if the versions are different. - * If they are different, we clean the plugins directory in the - * data partition, then start a thread to copy the plugins while - * the browser continue to load. - * - * @param overwrite if true overwrite the files even if they are - * already present (to let the user "reset" the plugins if needed). - */ - private void copyPlugins(boolean overwrite) { - CopyPlugins copyPluginsFromAssets = new CopyPlugins(overwrite, this); - copyPluginsFromAssets.initPluginsPath(); - if (copyPluginsFromAssets.newSystemImage()) { - if (copyPluginsFromAssets.checkIsDifferentVersions()) { - copyPluginsFromAssets.cleanPluginsDirectory(); - Thread copyplugins = new Thread(copyPluginsFromAssets); - copyplugins.setName("CopyPlugins"); - copyplugins.start(); - } - } - } - - private class ClearThumbnails extends AsyncTask<File, Void, Void> { - @Override - public Void doInBackground(File... files) { - if (files != null) { - for (File f : files) { - f.delete(); - } - } - return null; - } - } - - @Override public void onCreate(Bundle icicle) { - if (Config.LOGV) { - Log.v(LOGTAG, this + " onStart"); - } - super.onCreate(icicle); - this.requestWindowFeature(Window.FEATURE_LEFT_ICON); - this.requestWindowFeature(Window.FEATURE_RIGHT_ICON); - this.requestWindowFeature(Window.FEATURE_PROGRESS); - this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - // test the browser in OpenGL - // requestWindowFeature(Window.FEATURE_OPENGL); - - setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); - - mResolver = getContentResolver(); - - setBaseSearchUrl(PreferenceManager.getDefaultSharedPreferences(this) - .getString("search_url", "")); - - // - // start MASF proxy service - // - //Intent proxyServiceIntent = new Intent(); - //proxyServiceIntent.setComponent - // (new ComponentName( - // "com.android.masfproxyservice", - // "com.android.masfproxyservice.MasfProxyService")); - //startService(proxyServiceIntent, null); - - mSecLockIcon = Resources.getSystem().getDrawable( - android.R.drawable.ic_secure); - mMixLockIcon = Resources.getSystem().getDrawable( - android.R.drawable.ic_partial_secure); - mGenericFavicon = getResources().getDrawable( - R.drawable.app_web_browser_sm); - - mContentView = (FrameLayout) getWindow().getDecorView().findViewById( - com.android.internal.R.id.content); - - // Create the tab control and our initial tab - mTabControl = new TabControl(this); - - // Open the icon database and retain all the bookmark urls for favicons - retainIconsOnStartup(); - - // Keep a settings instance handy. - mSettings = BrowserSettings.getInstance(); - mSettings.setTabControl(mTabControl); - mSettings.loadFromDb(this); - - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser"); - - if (!mTabControl.restoreState(icicle)) { - // clear up the thumbnail directory if we can't restore the state as - // none of the files in the directory are referenced any more. - new ClearThumbnails().execute( - mTabControl.getThumbnailDir().listFiles()); - final Intent intent = getIntent(); - 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. - final TabControl.Tab t = mTabControl.createNewTab( - Intent.ACTION_VIEW.equals(intent.getAction()) && - intent.getData() != null); - mTabControl.setCurrentTab(t); - // This is one of the only places we call attachTabToContentView - // without animating from the tab picker. - attachTabToContentView(t); - WebView webView = t.getWebView(); - if (extra != null) { - int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0); - if (scale > 0 && scale <= 1000) { - webView.setInitialScale(scale); - } - } - // If we are not restoring from an icicle, then there is a high - // likely hood this is the first run. So, check to see if the - // homepage needs to be configured and copy any plugins from our - // asset directory to the data partition. - if ((extra == null || !extra.getBoolean("testing")) - && !mSettings.isLoginInitialized()) { - setupHomePage(); - } - copyPlugins(true); - - String url = getUrlFromIntent(intent); - if (url == null || url.length() == 0) { - if (mSettings.isLoginInitialized()) { - webView.loadUrl(mSettings.getHomePage()); - } else { - waitForCredentials(); - } - } else { - webView.loadUrl(url); - } - } else { - // TabControl.restoreState() will create a new tab even if - // restoring the state fails. Attach it to the view here since we - // are not animating from the tab picker. - attachTabToContentView(mTabControl.getCurrentTab()); - } - - /* enables registration for changes in network status from - http stack */ - mNetworkStateChangedFilter = new IntentFilter(); - mNetworkStateChangedFilter.addAction( - ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals( - ConnectivityManager.CONNECTIVITY_ACTION)) { - boolean down = intent.getBooleanExtra( - ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - onNetworkToggle(!down); - } - } - }; - } - - @Override - protected void onNewIntent(Intent intent) { - TabControl.Tab current = mTabControl.getCurrentTab(); - // When a tab is closed on exit, the current tab index is set to -1. - // Reset before proceed as Browser requires the current tab to be set. - if (current == null) { - // Try to reset the tab in case the index was incorrect. - current = mTabControl.getTab(0); - if (current == null) { - // No tabs at all so just ignore this intent. - return; - } - mTabControl.setCurrentTab(current); - attachTabToContentView(current); - resetTitleAndIcon(current.getWebView()); - } - final String action = intent.getAction(); - final int flags = intent.getFlags(); - if (Intent.ACTION_MAIN.equals(action) || - (flags & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) { - // just resume the browser - return; - } - if (Intent.ACTION_VIEW.equals(action) - || Intent.ACTION_SEARCH.equals(action) - || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action) - || Intent.ACTION_WEB_SEARCH.equals(action)) { - String url = getUrlFromIntent(intent); - if (url == null || url.length() == 0) { - url = mSettings.getHomePage(); - } - if (Intent.ACTION_VIEW.equals(action) && - (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { - // if FLAG_ACTIVITY_BROUGHT_TO_FRONT flag is on, the url will be - // opened in a new tab unless we have reached 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. - openTabAndShow(url, null, true); - } else { - if ("about:debug".equals(url)) { - mSettings.toggleDebugSettings(); - return; - } - // If the Window overview is up and we are not in the midst of - // an animation, animate away from the Window overview. - if (mTabOverview != null && mAnimationCount == 0) { - sendAnimateFromOverview(current, false, url, - TAB_OVERVIEW_DELAY, null); - } else { - // Get rid of the subwindow if it exists - dismissSubWindow(current); - current.getWebView().loadUrl(url); - } - } - } - } - - private String getUrlFromIntent(Intent intent) { - String url = null; - if (intent != null) { - final String action = intent.getAction(); - if (Intent.ACTION_VIEW.equals(action)) { - url = smartUrlFilter(intent.getData()); - if (url != null && url.startsWith("content:")) { - /* Append mimetype so webview knows how to display */ - String mimeType = intent.resolveType(getContentResolver()); - if (mimeType != null) { - url += "?" + mimeType; - } - } - } else if (Intent.ACTION_SEARCH.equals(action) - || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action) - || Intent.ACTION_WEB_SEARCH.equals(action)) { - url = intent.getStringExtra(SearchManager.QUERY); - if (url != null) { - mLastEnteredUrl = url; - // Don't add Urls, just search terms. - // Urls will get added when the page is loaded. - if (!Regex.WEB_URL_PATTERN.matcher(url).matches()) { - Browser.updateVisitedHistory(mResolver, url, false); - } - // In general, we shouldn't modify URL from Intent. - // But currently, we get the user-typed URL from search box as well. - url = fixUrl(url); - url = smartUrlFilter(url); - String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&"; - if (url.contains(searchSource)) { - String source = null; - final Bundle appData = intent.getBundleExtra(SearchManager.APP_DATA); - if (appData != null) { - source = appData.getString(SearchManager.SOURCE); - } - if (TextUtils.isEmpty(source)) { - source = GOOGLE_SEARCH_SOURCE_UNKNOWN; - } - url = url.replace(searchSource, "&source=android-"+source+"&"); - } - } - } - } - return url; - } - - /* package */ static String fixUrl(String inUrl) { - if (inUrl.startsWith("http://") || inUrl.startsWith("https://")) - return inUrl; - if (inUrl.startsWith("http:") || - inUrl.startsWith("https:")) { - if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) { - inUrl = inUrl.replaceFirst("/", "//"); - } else inUrl = inUrl.replaceFirst(":", "://"); - } - return inUrl; - } - - /** - * Looking for the pattern like this - * - * * - * * * - * *** * ******* - * * * - * * * - * * - */ - private final SensorListener mSensorListener = new SensorListener() { - private long mLastGestureTime; - private float[] mPrev = new float[3]; - private float[] mPrevDiff = new float[3]; - private float[] mDiff = new float[3]; - private float[] mRevertDiff = new float[3]; - - public void onSensorChanged(int sensor, float[] values) { - boolean show = false; - float[] diff = new float[3]; - - for (int i = 0; i < 3; i++) { - diff[i] = values[i] - mPrev[i]; - if (Math.abs(diff[i]) > 1) { - show = true; - } - if ((diff[i] > 1.0 && mDiff[i] < 0.2) - || (diff[i] < -1.0 && mDiff[i] > -0.2)) { - // start track when there is a big move, or revert - mRevertDiff[i] = mDiff[i]; - mDiff[i] = 0; - } else if (diff[i] > -0.2 && diff[i] < 0.2) { - // reset when it is flat - mDiff[i] = mRevertDiff[i] = 0; - } - mDiff[i] += diff[i]; - mPrevDiff[i] = diff[i]; - mPrev[i] = values[i]; - } - - if (false) { - // only shows if we think the delta is big enough, in an attempt - // to detect "serious" moves left/right or up/down - Log.d("BrowserSensorHack", "sensorChanged " + sensor + " (" - + values[0] + ", " + values[1] + ", " + values[2] + ")" - + " diff(" + diff[0] + " " + diff[1] + " " + diff[2] - + ")"); - Log.d("BrowserSensorHack", " mDiff(" + mDiff[0] + " " - + mDiff[1] + " " + mDiff[2] + ")" + " mRevertDiff(" - + mRevertDiff[0] + " " + mRevertDiff[1] + " " - + mRevertDiff[2] + ")"); - } - - long now = android.os.SystemClock.uptimeMillis(); - if (now - mLastGestureTime > 1000) { - mLastGestureTime = 0; - - float y = mDiff[1]; - float z = mDiff[2]; - float ay = Math.abs(y); - float az = Math.abs(z); - float ry = mRevertDiff[1]; - float rz = mRevertDiff[2]; - float ary = Math.abs(ry); - float arz = Math.abs(rz); - boolean gestY = ay > 2.5f && ary > 1.0f && ay > ary; - boolean gestZ = az > 3.5f && arz > 1.0f && az > arz; - - if ((gestY || gestZ) && !(gestY && gestZ)) { - WebView view = mTabControl.getCurrentWebView(); - - if (view != null) { - if (gestZ) { - if (z < 0) { - view.zoomOut(); - } else { - view.zoomIn(); - } - } else { - view.flingScroll(0, Math.round(y * 100)); - } - } - mLastGestureTime = now; - } - } - } - - public void onAccuracyChanged(int sensor, int accuracy) { - // TODO Auto-generated method stub - - } - }; - - @Override protected void onResume() { - super.onResume(); - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.onResume: this=" + this); - } - - if (!mActivityInPause) { - Log.e(LOGTAG, "BrowserActivity is already resumed."); - return; - } - - mActivityInPause = false; - resumeWebView(); - - if (mWakeLock.isHeld()) { - mHandler.removeMessages(RELEASE_WAKELOCK); - mWakeLock.release(); - } - - if (mCredsDlg != null) { - if (!mHandler.hasMessages(CANCEL_CREDS_REQUEST)) { - // In case credential request never comes back - mHandler.sendEmptyMessageDelayed(CANCEL_CREDS_REQUEST, 6000); - } - } - - registerReceiver(mNetworkStateIntentReceiver, - mNetworkStateChangedFilter); - WebView.enablePlatformNotifications(); - - if (mSettings.doFlick()) { - if (mSensorManager == null) { - mSensorManager = (SensorManager) getSystemService( - Context.SENSOR_SERVICE); - } - mSensorManager.registerListener(mSensorListener, - SensorManager.SENSOR_ACCELEROMETER, - SensorManager.SENSOR_DELAY_FASTEST); - } else { - mSensorManager = null; - } - } - - /** - * onSaveInstanceState(Bundle map) - * onSaveInstanceState is called right before onStop(). The map contains - * the saved state. - */ - @Override protected void onSaveInstanceState(Bundle outState) { - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.onSaveInstanceState: this=" + this); - } - // the default implementation requires each view to have an id. As the - // browser handles the state itself and it doesn't use id for the views, - // don't call the default implementation. Otherwise it will trigger the - // warning like this, "couldn't save which view has focus because the - // focused view XXX has no id". - - // Save all the tabs - mTabControl.saveState(outState); - } - - @Override protected void onPause() { - super.onPause(); - - if (mActivityInPause) { - Log.e(LOGTAG, "BrowserActivity is already paused."); - return; - } - - mActivityInPause = true; - if (mTabControl.getCurrentIndex() >= 0 && !pauseWebView()) { - mWakeLock.acquire(); - mHandler.sendMessageDelayed(mHandler - .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT); - } - - // Clear the credentials toast if it is up - if (mCredsDlg != null && mCredsDlg.isShowing()) { - mCredsDlg.dismiss(); - } - mCredsDlg = null; - - cancelStopToast(); - - // unregister network state listener - unregisterReceiver(mNetworkStateIntentReceiver); - WebView.disablePlatformNotifications(); - - if (mSensorManager != null) { - mSensorManager.unregisterListener(mSensorListener); - } - } - - @Override protected void onDestroy() { - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.onDestroy: this=" + this); - } - super.onDestroy(); - // Remove the current tab and sub window - TabControl.Tab t = mTabControl.getCurrentTab(); - dismissSubWindow(t); - removeTabFromContentView(t); - // Destroy all the tabs - mTabControl.destroy(); - WebIconDatabase.getInstance().close(); - if (mGlsConnection != null) { - unbindService(mGlsConnection); - mGlsConnection = null; - } - - // - // stop MASF proxy service - // - //Intent proxyServiceIntent = new Intent(); - //proxyServiceIntent.setComponent - // (new ComponentName( - // "com.android.masfproxyservice", - // "com.android.masfproxyservice.MasfProxyService")); - //stopService(proxyServiceIntent); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - if (mPageInfoDialog != null) { - mPageInfoDialog.dismiss(); - showPageInfo( - mPageInfoView, - mPageInfoFromShowSSLCertificateOnError.booleanValue()); - } - if (mSSLCertificateDialog != null) { - mSSLCertificateDialog.dismiss(); - showSSLCertificate( - mSSLCertificateView); - } - if (mSSLCertificateOnErrorDialog != null) { - mSSLCertificateOnErrorDialog.dismiss(); - showSSLCertificateOnError( - mSSLCertificateOnErrorView, - mSSLCertificateOnErrorHandler, - mSSLCertificateOnErrorError); - } - if (mHttpAuthenticationDialog != null) { - String title = ((TextView) mHttpAuthenticationDialog - .findViewById(com.android.internal.R.id.alertTitle)).getText() - .toString(); - String name = ((TextView) mHttpAuthenticationDialog - .findViewById(R.id.username_edit)).getText().toString(); - String password = ((TextView) mHttpAuthenticationDialog - .findViewById(R.id.password_edit)).getText().toString(); - int focusId = mHttpAuthenticationDialog.getCurrentFocus() - .getId(); - mHttpAuthenticationDialog.dismiss(); - showHttpAuthentication(mHttpAuthHandler, null, null, title, - name, password, focusId); - } - if (mFindDialog != null && mFindDialog.isShowing()) { - mFindDialog.onConfigurationChanged(newConfig); - } - } - - @Override public void onLowMemory() { - super.onLowMemory(); - mTabControl.freeMemory(); - } - - private boolean resumeWebView() { - if ((!mActivityInPause && !mPageStarted) || - (mActivityInPause && mPageStarted)) { - CookieSyncManager.getInstance().startSync(); - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - w.resumeTimers(); - } - return true; - } else { - return false; - } - } - - private boolean pauseWebView() { - if (mActivityInPause && !mPageStarted) { - CookieSyncManager.getInstance().stopSync(); - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - w.pauseTimers(); - } - return true; - } else { - return false; - } - } - - /* - * This function is called when we are launching for the first time. We - * are waiting for the login credentials before loading Google home - * pages. This way the user will be logged in straight away. - */ - private void waitForCredentials() { - // Show a toast - mCredsDlg = new ProgressDialog(this); - mCredsDlg.setIndeterminate(true); - mCredsDlg.setMessage(getText(R.string.retrieving_creds_dlg_msg)); - // If the user cancels the operation, then cancel the Google - // Credentials request. - mCredsDlg.setCancelMessage(mHandler.obtainMessage(CANCEL_CREDS_REQUEST)); - mCredsDlg.show(); - - // We set a timeout for the retrieval of credentials in onResume() - // as that is when we have freed up some CPU time to get - // the login credentials. - } - - /* - * If we have received the credentials or we have timed out and we are - * showing the credentials dialog, then it is time to move on. - */ - private void resumeAfterCredentials() { - if (mCredsDlg == null) { - return; - } - - // Clear the toast - if (mCredsDlg.isShowing()) { - mCredsDlg.dismiss(); - } - mCredsDlg = null; - - // Clear any pending timeout - mHandler.removeMessages(CANCEL_CREDS_REQUEST); - - // Load the page - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - w.loadUrl(mSettings.getHomePage()); - } - - // Update the settings, need to do this last as it can take a moment - // to persist the settings. In the mean time we could be loading - // content. - mSettings.setLoginInitialized(this); - } - - // Open the icon database and retain all the icons for visited sites. - private void retainIconsOnStartup() { - final WebIconDatabase db = WebIconDatabase.getInstance(); - db.open(getDir("icons", 0).getPath()); - try { - Cursor c = Browser.getAllBookmarks(mResolver); - if (!c.moveToFirst()) { - c.deactivate(); - return; - } - int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL); - do { - String url = c.getString(urlIndex); - db.retainIconForPageUrl(url); - } while (c.moveToNext()); - c.deactivate(); - } catch (IllegalStateException e) { - Log.e(LOGTAG, "retainIconsOnStartup", e); - } - } - - // Helper method for getting the top window. - WebView getTopWindow() { - return mTabControl.getCurrentTopWebView(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.browser, menu); - mMenu = menu; - updateInLoadMenuItems(); - return true; - } - - /** - * As the menu can be open when loading state changes - * we must manually update the state of the stop/reload menu - * item - */ - private void updateInLoadMenuItems() { - if (mMenu == null) { - return; - } - MenuItem src = mInLoad ? - mMenu.findItem(R.id.stop_menu_id): - mMenu.findItem(R.id.reload_menu_id); - MenuItem dest = mMenu.findItem(R.id.stop_reload_menu_id); - dest.setIcon(src.getIcon()); - dest.setTitle(src.getTitle()); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - // chording is not an issue with context menus, but we use the same - // options selector, so set mCanChord to true so we can access them. - mCanChord = true; - int id = item.getItemId(); - final WebView webView = getTopWindow(); - final HashMap hrefMap = new HashMap(); - hrefMap.put("webview", webView); - final Message msg = mHandler.obtainMessage( - FOCUS_NODE_HREF, id, 0, hrefMap); - switch (id) { - // -- Browser context menu - case R.id.open_context_menu_id: - case R.id.open_newtab_context_menu_id: - case R.id.bookmark_context_menu_id: - case R.id.save_link_context_menu_id: - case R.id.share_link_context_menu_id: - case R.id.copy_link_context_menu_id: - webView.requestFocusNodeHref(msg); - break; - - default: - // For other context menus - return onOptionsItemSelected(item); - } - mCanChord = false; - return true; - } - - private Bundle createGoogleSearchSourceBundle(String source) { - Bundle bundle = new Bundle(); - bundle.putString(SearchManager.SOURCE, source); - return bundle; - } - - /** - * Overriding this forces the search key to launch global search. The difference - * is the final "true" which requests global search. - */ - @Override - public boolean onSearchRequested() { - startSearch(null, false, - createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), true); - return true; - } - - @Override - public void startSearch(String initialQuery, boolean selectInitialQuery, - Bundle appSearchData, boolean globalSearch) { - if (appSearchData == null) { - appSearchData = createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_TYPE); - } - super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (!mCanChord) { - // The user has already fired a shortcut with this hold down of the - // menu key. - return false; - } - switch (item.getItemId()) { - // -- Main menu - case R.id.goto_menu_id: { - String url = getTopWindow().getUrl(); - startSearch(mSettings.getHomePage().equals(url) ? null : url, true, - createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_GOTO), false); - } - break; - - case R.id.bookmarks_menu_id: - bookmarksOrHistoryPicker(false); - break; - - case R.id.windows_menu_id: - if (mTabControl.getTabCount() == 1) { - openTabAndShow(mSettings.getHomePage(), null, false); - } else { - tabPicker(true, mTabControl.getCurrentIndex(), false); - } - break; - - case R.id.stop_reload_menu_id: - if (mInLoad) { - stopLoading(); - } else { - getTopWindow().reload(); - } - break; - - case R.id.back_menu_id: - getTopWindow().goBack(); - break; - - case R.id.forward_menu_id: - getTopWindow().goForward(); - break; - - case R.id.close_menu_id: - // Close the subwindow if it exists. - if (mTabControl.getCurrentSubWindow() != null) { - dismissSubWindow(mTabControl.getCurrentTab()); - break; - } - final int currentIndex = mTabControl.getCurrentIndex(); - final TabControl.Tab parent = - mTabControl.getCurrentTab().getParentTab(); - int indexToShow = -1; - if (parent != null) { - indexToShow = mTabControl.getTabIndex(parent); - } else { - // Get the last tab in the list. If it is the current tab, - // subtract 1 more. - indexToShow = mTabControl.getTabCount() - 1; - if (currentIndex == indexToShow) { - indexToShow--; - } - } - switchTabs(currentIndex, indexToShow, true); - break; - - case R.id.homepage_menu_id: - TabControl.Tab current = mTabControl.getCurrentTab(); - if (current != null) { - dismissSubWindow(current); - current.getWebView().loadUrl(mSettings.getHomePage()); - } - break; - - case R.id.preferences_menu_id: - Intent intent = new Intent(this, - BrowserPreferencesPage.class); - startActivityForResult(intent, PREFERENCES_PAGE); - break; - - case R.id.find_menu_id: - if (null == mFindDialog) { - mFindDialog = new FindDialog(this); - } - mFindDialog.setWebView(getTopWindow()); - mFindDialog.show(); - mMenuState = EMPTY_MENU; - break; - - case R.id.select_text_id: - getTopWindow().emulateShiftHeld(); - break; - case R.id.page_info_menu_id: - showPageInfo(mTabControl.getCurrentTab(), false); - break; - - case R.id.classic_history_menu_id: - bookmarksOrHistoryPicker(true); - break; - - case R.id.share_page_menu_id: - Browser.sendString(this, getTopWindow().getUrl()); - break; - - case R.id.dump_nav_menu_id: - getTopWindow().debugDump(); - break; - - case R.id.zoom_in_menu_id: - getTopWindow().zoomIn(); - break; - - case R.id.zoom_out_menu_id: - getTopWindow().zoomOut(); - break; - - case R.id.view_downloads_menu_id: - viewDownloads(null); - break; - - // -- Tab menu - case R.id.view_tab_menu_id: - if (mTabListener != null && mTabOverview != null) { - int pos = mTabOverview.getContextMenuPosition(item); - mTabOverview.setCurrentIndex(pos); - mTabListener.onClick(pos); - } - break; - - case R.id.remove_tab_menu_id: - if (mTabListener != null && mTabOverview != null) { - int pos = mTabOverview.getContextMenuPosition(item); - mTabListener.remove(pos); - } - break; - - case R.id.new_tab_menu_id: - // No need to check for mTabOverview here since we are not - // dependent on it for a position. - if (mTabListener != null) { - // If the overview happens to be non-null, make the "New - // Tab" cell visible. - if (mTabOverview != null) { - mTabOverview.setCurrentIndex(ImageGrid.NEW_TAB); - } - mTabListener.onClick(ImageGrid.NEW_TAB); - } - break; - - case R.id.bookmark_tab_menu_id: - if (mTabListener != null && mTabOverview != null) { - int pos = mTabOverview.getContextMenuPosition(item); - TabControl.Tab t = mTabControl.getTab(pos); - // Since we called populatePickerData for all of the - // tabs, getTitle and getUrl will return appropriate - // values. - Browser.saveBookmark(BrowserActivity.this, t.getTitle(), - t.getUrl()); - } - break; - - case R.id.history_tab_menu_id: - bookmarksOrHistoryPicker(true); - break; - - case R.id.bookmarks_tab_menu_id: - bookmarksOrHistoryPicker(false); - break; - - case R.id.properties_tab_menu_id: - if (mTabListener != null && mTabOverview != null) { - int pos = mTabOverview.getContextMenuPosition(item); - showPageInfo(mTabControl.getTab(pos), false); - } - break; - - case R.id.window_one_menu_id: - case R.id.window_two_menu_id: - case R.id.window_three_menu_id: - case R.id.window_four_menu_id: - case R.id.window_five_menu_id: - case R.id.window_six_menu_id: - case R.id.window_seven_menu_id: - case R.id.window_eight_menu_id: - { - int menuid = item.getItemId(); - for (int id = 0; id < WINDOW_SHORTCUT_ID_ARRAY.length; id++) { - if (WINDOW_SHORTCUT_ID_ARRAY[id] == menuid) { - TabControl.Tab desiredTab = mTabControl.getTab(id); - if (desiredTab != null && - desiredTab != mTabControl.getCurrentTab()) { - switchTabs(mTabControl.getCurrentIndex(), id, false); - } - break; - } - } - } - break; - - default: - if (!super.onOptionsItemSelected(item)) { - return false; - } - // Otherwise fall through. - } - mCanChord = false; - return true; - } - - public void closeFind() { - mMenuState = R.id.MAIN_MENU; - } - - @Override public boolean onPrepareOptionsMenu(Menu menu) - { - // This happens when the user begins to hold down the menu key, so - // allow them to chord to get a shortcut. - mCanChord = true; - // Note: setVisible will decide whether an item is visible; while - // setEnabled() will decide whether an item is enabled, which also means - // whether the matching shortcut key will function. - super.onPrepareOptionsMenu(menu); - switch (mMenuState) { - case R.id.TAB_MENU: - if (mCurrentMenuState != mMenuState) { - menu.setGroupVisible(R.id.MAIN_MENU, false); - menu.setGroupEnabled(R.id.MAIN_MENU, false); - menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false); - menu.setGroupVisible(R.id.TAB_MENU, true); - menu.setGroupEnabled(R.id.TAB_MENU, true); - } - boolean newT = mTabControl.getTabCount() < TabControl.MAX_TABS; - final MenuItem tab = menu.findItem(R.id.new_tab_menu_id); - tab.setVisible(newT); - tab.setEnabled(newT); - break; - case EMPTY_MENU: - if (mCurrentMenuState != mMenuState) { - menu.setGroupVisible(R.id.MAIN_MENU, false); - menu.setGroupEnabled(R.id.MAIN_MENU, false); - menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false); - menu.setGroupVisible(R.id.TAB_MENU, false); - menu.setGroupEnabled(R.id.TAB_MENU, false); - } - break; - default: - if (mCurrentMenuState != mMenuState) { - menu.setGroupVisible(R.id.MAIN_MENU, true); - menu.setGroupEnabled(R.id.MAIN_MENU, true); - menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, true); - menu.setGroupVisible(R.id.TAB_MENU, false); - menu.setGroupEnabled(R.id.TAB_MENU, false); - } - final WebView w = getTopWindow(); - boolean canGoBack = false; - boolean canGoForward = false; - boolean isHome = false; - if (w != null) { - canGoBack = w.canGoBack(); - canGoForward = w.canGoForward(); - isHome = mSettings.getHomePage().equals(w.getUrl()); - } - final MenuItem back = menu.findItem(R.id.back_menu_id); - back.setEnabled(canGoBack); - - final MenuItem home = menu.findItem(R.id.homepage_menu_id); - home.setEnabled(!isHome); - - menu.findItem(R.id.forward_menu_id) - .setEnabled(canGoForward); - - // decide whether to show the share link option - PackageManager pm = getPackageManager(); - Intent send = new Intent(Intent.ACTION_SEND); - send.setType("text/plain"); - ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY); - menu.findItem(R.id.share_page_menu_id).setVisible(ri != null); - - // If there is only 1 window, the text will be "New window" - final MenuItem windows = menu.findItem(R.id.windows_menu_id); - windows.setTitleCondensed(mTabControl.getTabCount() > 1 ? - getString(R.string.view_tabs_condensed) : - getString(R.string.tab_picker_new_tab)); - - boolean isNavDump = mSettings.isNavDump(); - final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id); - nav.setVisible(isNavDump); - nav.setEnabled(isNavDump); - break; - } - mCurrentMenuState = mMenuState; - return true; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - WebView webview = (WebView) v; - WebView.HitTestResult result = webview.getHitTestResult(); - if (result == null) { - return; - } - - int type = result.getType(); - if (type == WebView.HitTestResult.UNKNOWN_TYPE) { - Log.w(LOGTAG, - "We should not show context menu when nothing is touched"); - return; - } - if (type == WebView.HitTestResult.EDIT_TEXT_TYPE) { - // let TextView handles context menu - return; - } - - // Note, http://b/issue?id=1106666 is requesting that - // an inflated menu can be used again. This is not available - // yet, so inflate each time (yuk!) - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.browsercontext, menu); - - // Show the correct menu group - String extra = result.getExtra(); - menu.setGroupVisible(R.id.PHONE_MENU, - type == WebView.HitTestResult.PHONE_TYPE); - menu.setGroupVisible(R.id.EMAIL_MENU, - type == WebView.HitTestResult.EMAIL_TYPE); - menu.setGroupVisible(R.id.GEO_MENU, - type == WebView.HitTestResult.GEO_TYPE); - menu.setGroupVisible(R.id.IMAGE_MENU, - type == WebView.HitTestResult.IMAGE_TYPE - || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE); - menu.setGroupVisible(R.id.ANCHOR_MENU, - type == WebView.HitTestResult.SRC_ANCHOR_TYPE - || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE); - - // Setup custom handling depending on the type - switch (type) { - case WebView.HitTestResult.PHONE_TYPE: - menu.setHeaderTitle(Uri.decode(extra)); - menu.findItem(R.id.dial_context_menu_id).setIntent( - new Intent(Intent.ACTION_VIEW, Uri - .parse(WebView.SCHEME_TEL + extra))); - Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT); - addIntent.putExtra(Insert.PHONE, Uri.decode(extra)); - addIntent.setType(Contacts.People.CONTENT_ITEM_TYPE); - menu.findItem(R.id.add_contact_context_menu_id).setIntent( - addIntent); - menu.findItem(R.id.copy_phone_context_menu_id).setOnMenuItemClickListener( - new Copy(extra)); - break; - - case WebView.HitTestResult.EMAIL_TYPE: - menu.setHeaderTitle(extra); - menu.findItem(R.id.email_context_menu_id).setIntent( - new Intent(Intent.ACTION_VIEW, Uri - .parse(WebView.SCHEME_MAILTO + extra))); - menu.findItem(R.id.copy_mail_context_menu_id).setOnMenuItemClickListener( - new Copy(extra)); - break; - - case WebView.HitTestResult.GEO_TYPE: - menu.setHeaderTitle(extra); - menu.findItem(R.id.map_context_menu_id).setIntent( - new Intent(Intent.ACTION_VIEW, Uri - .parse(WebView.SCHEME_GEO - + URLEncoder.encode(extra)))); - menu.findItem(R.id.copy_geo_context_menu_id).setOnMenuItemClickListener( - new Copy(extra)); - break; - - case WebView.HitTestResult.SRC_ANCHOR_TYPE: - case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE: - TextView titleView = (TextView) LayoutInflater.from(this) - .inflate(android.R.layout.browser_link_context_header, - null); - titleView.setText(extra); - menu.setHeaderView(titleView); - // decide whether to show the open link in new tab option - menu.findItem(R.id.open_newtab_context_menu_id).setVisible( - mTabControl.getTabCount() < TabControl.MAX_TABS); - PackageManager pm = getPackageManager(); - Intent send = new Intent(Intent.ACTION_SEND); - send.setType("text/plain"); - ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY); - menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null); - if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) { - break; - } - // otherwise fall through to handle image part - case WebView.HitTestResult.IMAGE_TYPE: - if (type == WebView.HitTestResult.IMAGE_TYPE) { - menu.setHeaderTitle(extra); - } - menu.findItem(R.id.view_image_context_menu_id).setIntent( - new Intent(Intent.ACTION_VIEW, Uri.parse(extra))); - menu.findItem(R.id.download_context_menu_id). - setOnMenuItemClickListener(new Download(extra)); - break; - - default: - Log.w(LOGTAG, "We should not get here."); - break; - } - } - - // Used by attachTabToContentView for the WebView's ZoomControl widget. - private static final FrameLayout.LayoutParams ZOOM_PARAMS = - new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - Gravity.BOTTOM); - - // Attach the given tab to the content view. - private void attachTabToContentView(TabControl.Tab t) { - final WebView main = t.getWebView(); - // Attach the main WebView. - mContentView.addView(main, COVER_SCREEN_PARAMS); - // Attach the Zoom control widget and hide it. - final View zoom = main.getZoomControls(); - mContentView.addView(zoom, ZOOM_PARAMS); - zoom.setVisibility(View.GONE); - // Attach the sub window if necessary - attachSubWindow(t); - // Request focus on the top window. - t.getTopWindow().requestFocus(); - } - - // Attach a sub window to the main WebView of the given tab. - private void attachSubWindow(TabControl.Tab t) { - // If a sub window exists, attach it to the content view. - final WebView subView = t.getSubWebView(); - if (subView != null) { - final View container = t.getSubWebViewContainer(); - mContentView.addView(container, COVER_SCREEN_PARAMS); - subView.requestFocus(); - } - } - - // Remove the given tab from the content view. - private void removeTabFromContentView(TabControl.Tab t) { - // Remove the Zoom widget and the main WebView. - mContentView.removeView(t.getWebView().getZoomControls()); - mContentView.removeView(t.getWebView()); - // Remove the sub window if it exists. - if (t.getSubWebView() != null) { - mContentView.removeView(t.getSubWebViewContainer()); - } - } - - // Remove the sub window if it exists. Also called by TabControl when the - // user clicks the 'X' to dismiss a sub window. - /* package */ void dismissSubWindow(TabControl.Tab t) { - final WebView mainView = t.getWebView(); - if (t.getSubWebView() != null) { - // Remove the container view and request focus on the main WebView. - mContentView.removeView(t.getSubWebViewContainer()); - mainView.requestFocus(); - // Tell the TabControl to dismiss the subwindow. This will destroy - // the WebView. - mTabControl.dismissSubWindow(t); - } - } - - // Send the ANIMTE_FROM_OVERVIEW message after changing the current tab. - private void sendAnimateFromOverview(final TabControl.Tab tab, - final boolean newTab, final String url, final int delay, - final Message msg) { - // Set the current tab. - mTabControl.setCurrentTab(tab); - // Attach the WebView so it will layout. - attachTabToContentView(tab); - // Set the view to invisibile for now. - tab.getWebView().setVisibility(View.INVISIBLE); - // If there is a sub window, make it invisible too. - if (tab.getSubWebView() != null) { - tab.getSubWebViewContainer().setVisibility(View.INVISIBLE); - } - // Create our fake animating view. - final AnimatingView view = new AnimatingView(this, tab); - // Attach it to the view system and make in invisible so it will - // layout but not flash white on the screen. - mContentView.addView(view, COVER_SCREEN_PARAMS); - view.setVisibility(View.INVISIBLE); - // Send the animate message. - final HashMap map = new HashMap(); - map.put("view", view); - // Load the url after the AnimatingView has captured the picture. This - // prevents any bad layout or bad scale from being used during - // animation. - if (url != null) { - dismissSubWindow(tab); - tab.getWebView().loadUrl(url); - } - map.put("msg", msg); - mHandler.sendMessageDelayed(mHandler.obtainMessage( - ANIMATE_FROM_OVERVIEW, newTab ? 1 : 0, 0, map), delay); - // Increment the count to indicate that we are in an animation. - mAnimationCount++; - // Remove the listener so we don't get any more tab changes. - mTabOverview.setListener(null); - mTabListener = null; - // Make the menu empty until the animation completes. - mMenuState = EMPTY_MENU; - - } - - // 500ms animation with 800ms delay - private static final int TAB_ANIMATION_DURATION = 500; - private static final int TAB_OVERVIEW_DELAY = 800; - - // Called by TabControl when a tab is requesting focus - /* package */ void showTab(TabControl.Tab t) { - // Disallow focus change during a tab animation. - if (mAnimationCount > 0) { - return; - } - int delay = 0; - if (mTabOverview == null) { - // Add a delay so the tab overview can be shown before the second - // animation begins. - delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY; - tabPicker(false, mTabControl.getTabIndex(t), false); - } - sendAnimateFromOverview(t, false, null, delay, null); - } - - // 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. If the tab overview is not - // showing, it will animate to the tab overview, create a new tab and - // animate away from it. After the animation completes, it will dispatch - // the given Message. If the tab overview is already showing (i.e. this - // method is called from TabListener.onClick(), the method will animate - // away from the tab overview. - private void openTabAndShow(String url, final Message msg, - boolean closeOnExit) { - final boolean newTab = mTabControl.getTabCount() != TabControl.MAX_TABS; - final TabControl.Tab currentTab = mTabControl.getCurrentTab(); - if (newTab) { - int delay = 0; - // If the tab overview is up and there are animations, just load - // the url. - if (mTabOverview != null && mAnimationCount > 0) { - if (url != null) { - // We should not have a msg here since onCreateWindow - // checks the animation count and every other caller passes - // null. - assert msg == null; - // just dismiss the subwindow and load the given url. - dismissSubWindow(currentTab); - currentTab.getWebView().loadUrl(url); - } - } else { - // show mTabOverview if it is not there. - if (mTabOverview == null) { - // We have to delay the animation from the tab picker by the - // length of the tab animation. Add a delay so the tab - // overview can be shown before the second animation begins. - delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY; - tabPicker(false, ImageGrid.NEW_TAB, false); - } - // Animate from the Tab overview after any animations have - // finished. - sendAnimateFromOverview(mTabControl.createNewTab(closeOnExit), - true, url, delay, msg); - } - } else if (url != null) { - // We should not have a msg here. - assert msg == null; - if (mTabOverview != null && mAnimationCount == 0) { - sendAnimateFromOverview(currentTab, false, url, - TAB_OVERVIEW_DELAY, null); - } else { - // Get rid of the subwindow if it exists - dismissSubWindow(currentTab); - // Load the given url. - currentTab.getWebView().loadUrl(url); - } - } - } - - private Animation createTabAnimation(final AnimatingView view, - final View cell, boolean scaleDown) { - final AnimationSet set = new AnimationSet(true); - final float scaleX = (float) cell.getWidth() / view.getWidth(); - final float scaleY = (float) cell.getHeight() / view.getHeight(); - if (scaleDown) { - set.addAnimation(new ScaleAnimation(1.0f, scaleX, 1.0f, scaleY)); - set.addAnimation(new TranslateAnimation(0, cell.getLeft(), 0, - cell.getTop())); - } else { - set.addAnimation(new ScaleAnimation(scaleX, 1.0f, scaleY, 1.0f)); - set.addAnimation(new TranslateAnimation(cell.getLeft(), 0, - cell.getTop(), 0)); - } - set.setDuration(TAB_ANIMATION_DURATION); - set.setInterpolator(new DecelerateInterpolator()); - return set; - } - - // Animate to the tab overview. currentIndex tells us which position to - // animate to and newIndex is the position that should be selected after - // the animation completes. - // If remove is true, after the animation stops, a confirmation dialog will - // be displayed to the user. - private void animateToTabOverview(final int newIndex, final boolean remove, - final AnimatingView view) { - // Find the view in the ImageGrid allowing for the "New Tab" cell. - int position = mTabControl.getTabIndex(view.mTab); - if (!((ImageAdapter) mTabOverview.getAdapter()).maxedOut()) { - position++; - } - - // Offset the tab position with the first visible position to get a - // number between 0 and 3. - position -= mTabOverview.getFirstVisiblePosition(); - - // Grab the view that we are going to animate to. - final View v = mTabOverview.getChildAt(position); - - final Animation.AnimationListener l = - new Animation.AnimationListener() { - public void onAnimationStart(Animation a) { - mTabOverview.requestFocus(); - // Clear the listener so we don't trigger a tab - // selection. - mTabOverview.setListener(null); - } - public void onAnimationRepeat(Animation a) {} - public void onAnimationEnd(Animation a) { - // We are no longer animating so decrement the count. - mAnimationCount--; - // Make the view GONE so that it will not draw between - // now and when the Runnable is handled. - view.setVisibility(View.GONE); - // Post a runnable since we can't modify the view - // hierarchy during this callback. - mHandler.post(new Runnable() { - public void run() { - // Remove the AnimatingView. - mContentView.removeView(view); - // Make newIndex visible. - mTabOverview.setCurrentIndex(newIndex); - // Restore the listener. - mTabOverview.setListener(mTabListener); - // Change the menu to TAB_MENU if the - // ImageGrid is interactive. - if (mTabOverview.isLive()) { - mMenuState = R.id.TAB_MENU; - mTabOverview.requestFocus(); - } - // If a remove was requested, remove the tab. - if (remove) { - // During a remove, the current tab has - // already changed. Remember the current one - // here. - final TabControl.Tab currentTab = - mTabControl.getCurrentTab(); - // Remove the tab at newIndex from - // TabControl and the tab overview. - final TabControl.Tab tab = - mTabControl.getTab(newIndex); - mTabControl.removeTab(tab); - // Restore the current tab. - if (currentTab != tab) { - mTabControl.setCurrentTab(currentTab); - } - mTabOverview.remove(newIndex); - // Make the current tab visible. - mTabOverview.setCurrentIndex( - mTabControl.getCurrentIndex()); - } - } - }); - } - }; - - // Do an animation if there is a view to animate to. - if (v != null) { - // Create our animation - final Animation anim = createTabAnimation(view, v, true); - anim.setAnimationListener(l); - // Start animating - view.startAnimation(anim); - } else { - // If something goes wrong and we didn't find a view to animate to, - // just do everything here. - l.onAnimationStart(null); - l.onAnimationEnd(null); - } - } - - // Animate from the tab picker. The index supplied is the index to animate - // from. - private void animateFromTabOverview(final AnimatingView view, - final boolean newTab, final Message msg) { - // firstVisible is the first visible tab on the screen. This helps - // to know which corner of the screen the selected tab is. - int firstVisible = mTabOverview.getFirstVisiblePosition(); - // tabPosition is the 0-based index of of the tab being opened - int tabPosition = mTabControl.getTabIndex(view.mTab); - if (!((ImageAdapter) mTabOverview.getAdapter()).maxedOut()) { - // Add one to make room for the "New Tab" cell. - tabPosition++; - } - // If this is a new tab, animate from the "New Tab" cell. - if (newTab) { - tabPosition = 0; - } - // Location corresponds to the four corners of the screen. - // A new tab or 0 is upper left, 0 for an old tab is upper - // right, 1 is lower left, and 2 is lower right - int location = tabPosition - firstVisible; - - // Find the view at this location. - final View v = mTabOverview.getChildAt(location); - - // Wait until the animation completes to replace the AnimatingView. - final Animation.AnimationListener l = - new Animation.AnimationListener() { - public void onAnimationStart(Animation a) {} - public void onAnimationRepeat(Animation a) {} - public void onAnimationEnd(Animation a) { - mHandler.post(new Runnable() { - public void run() { - mContentView.removeView(view); - // Dismiss the tab overview. If the cell at the - // given location is null, set the fade - // parameter to true. - dismissTabOverview(v == null); - TabControl.Tab t = - mTabControl.getCurrentTab(); - mMenuState = R.id.MAIN_MENU; - // Resume regular updates. - t.getWebView().resumeTimers(); - // Dispatch the message after the animation - // completes. - if (msg != null) { - msg.sendToTarget(); - } - // The animation is done and the tab overview is - // gone so allow key events and other animations - // to begin. - mAnimationCount--; - // Reset all the title bar info. - resetTitle(); - } - }); - } - }; - - if (v != null) { - final Animation anim = createTabAnimation(view, v, false); - // Set the listener and start animating - anim.setAnimationListener(l); - view.startAnimation(anim); - // Make the view VISIBLE during the animation. - view.setVisibility(View.VISIBLE); - } else { - // Go ahead and do all the cleanup. - l.onAnimationEnd(null); - } - } - - // Dismiss the tab overview applying a fade if needed. - private void dismissTabOverview(final boolean fade) { - if (fade) { - AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f); - anim.setDuration(500); - anim.startNow(); - mTabOverview.startAnimation(anim); - } - // Just in case there was a problem with animating away from the tab - // overview - mTabControl.getCurrentWebView().setVisibility(View.VISIBLE); - // Make the sub window container visible. - if (mTabControl.getCurrentSubWindow() != null) { - mTabControl.getCurrentTab().getSubWebViewContainer() - .setVisibility(View.VISIBLE); - } - mContentView.removeView(mTabOverview); - mTabOverview.clear(); - mTabOverview = null; - mTabListener = null; - } - - private void openTab(String url) { - if (mSettings.openInBackground()) { - TabControl.Tab t = mTabControl.createNewTab(false); - if (t != null) { - t.getWebView().loadUrl(url); - } - } else { - openTabAndShow(url, null, false); - } - } - - private class Copy implements OnMenuItemClickListener { - private CharSequence mText; - - public boolean onMenuItemClick(MenuItem item) { - copy(mText); - return true; - } - - public Copy(CharSequence toCopy) { - mText = toCopy; - } - } - - private class Download implements OnMenuItemClickListener { - private String mText; - - public boolean onMenuItemClick(MenuItem item) { - onDownloadStartNoStream(mText, null, null, null, -1); - return true; - } - - public Download(String toDownload) { - mText = toDownload; - } - } - - private void copy(CharSequence text) { - try { - IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard")); - if (clip != null) { - clip.setClipboardText(text); - } - } catch (android.os.RemoteException e) { - Log.e(LOGTAG, "Copy failed", e); - } - } - - /** - * Resets the browser title-view to whatever it must be (for example, if we - * load a page from history). - */ - private void resetTitle() { - resetLockIcon(); - resetTitleIconAndProgress(); - } - - /** - * Resets the browser title-view to whatever it must be - * (for example, if we had a loading error) - * When we have a new page, we call resetTitle, when we - * have to reset the titlebar to whatever it used to be - * (for example, if the user chose to stop loading), we - * call resetTitleAndRevertLockIcon. - */ - /* package */ void resetTitleAndRevertLockIcon() { - revertLockIcon(); - resetTitleIconAndProgress(); - } - - /** - * Reset the title, favicon, and progress. - */ - private void resetTitleIconAndProgress() { - WebView current = mTabControl.getCurrentWebView(); - if (current == null) { - return; - } - resetTitleAndIcon(current); - int progress = current.getProgress(); - mInLoad = (progress != 100); - updateInLoadMenuItems(); - mWebChromeClient.onProgressChanged(current, progress); - } - - // Reset the title and the icon based on the given item. - private void resetTitleAndIcon(WebView view) { - WebHistoryItem item = view.copyBackForwardList().getCurrentItem(); - if (item != null) { - setUrlTitle(item.getUrl(), item.getTitle()); - setFavicon(item.getFavicon()); - } else { - setUrlTitle(null, null); - setFavicon(null); - } - } - - /** - * Sets a title composed of the URL and the title string. - * @param url The URL of the site being loaded. - * @param title The title of the site being loaded. - */ - private void setUrlTitle(String url, String title) { - mUrl = url; - mTitle = title; - - // While the tab overview is animating or being shown, block changes - // to the title. - if (mAnimationCount == 0 && mTabOverview == null) { - setTitle(buildUrlTitle(url, title)); - } - } - - /** - * Builds and returns the page title, which is some - * combination of the page URL and title. - * @param url The URL of the site being loaded. - * @param title The title of the site being loaded. - * @return The page title. - */ - private String buildUrlTitle(String url, String title) { - String urlTitle = ""; - - if (url != null) { - String titleUrl = buildTitleUrl(url); - - if (title != null && 0 < title.length()) { - if (titleUrl != null && 0 < titleUrl.length()) { - urlTitle = titleUrl + ": " + title; - } else { - urlTitle = title; - } - } else { - if (titleUrl != null) { - urlTitle = titleUrl; - } - } - } - - return urlTitle; - } - - /** - * @param url The URL to build a title version of the URL from. - * @return The title version of the URL or null if fails. - * The title version of the URL can be either the URL hostname, - * or the hostname with an "https://" prefix (for secure URLs), - * or an empty string if, for example, the URL in question is a - * file:// URL with no hostname. - */ - private static String buildTitleUrl(String url) { - String titleUrl = null; - - if (url != null) { - try { - // parse the url string - URL urlObj = new URL(url); - if (urlObj != null) { - titleUrl = ""; - - String protocol = urlObj.getProtocol(); - String host = urlObj.getHost(); - - if (host != null && 0 < host.length()) { - titleUrl = host; - if (protocol != null) { - // if a secure site, add an "https://" prefix! - if (protocol.equalsIgnoreCase("https")) { - titleUrl = protocol + "://" + host; - } - } - } - } - } catch (MalformedURLException e) {} - } - - return titleUrl; - } - - // Set the favicon in the title bar. - private void setFavicon(Bitmap icon) { - // While the tab overview is animating or being shown, block changes to - // the favicon. - if (mAnimationCount > 0 || mTabOverview != null) { - return; - } - Drawable[] array = new Drawable[2]; - PaintDrawable p = new PaintDrawable(Color.WHITE); - p.setCornerRadius(3f); - array[0] = p; - if (icon == null) { - array[1] = mGenericFavicon; - } else { - array[1] = new BitmapDrawable(icon); - } - LayerDrawable d = new LayerDrawable(array); - d.setLayerInset(1, 2, 2, 2, 2); - getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, d); - } - - /** - * Saves the current lock-icon state before resetting - * the lock icon. If we have an error, we may need to - * roll back to the previous state. - */ - private void saveLockIcon() { - mPrevLockType = mLockIconType; - } - - /** - * Reverts the lock-icon state to the last saved state, - * for example, if we had an error, and need to cancel - * the load. - */ - private void revertLockIcon() { - mLockIconType = mPrevLockType; - - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.revertLockIcon:" + - " revert lock icon to " + mLockIconType); - } - - updateLockIconImage(mLockIconType); - } - - private void switchTabs(int indexFrom, int indexToShow, boolean remove) { - int delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY; - // Animate to the tab picker, remove the current tab, then - // animate away from the tab picker to the parent WebView. - tabPicker(false, indexFrom, remove); - // Change to the parent tab - final TabControl.Tab tab = mTabControl.getTab(indexToShow); - if (tab != null) { - sendAnimateFromOverview(tab, false, null, delay, null); - } else { - // Increment this here so that no other animations can happen in - // between the end of the tab picker transition and the beginning - // of openTabAndShow. This has a matching decrement in the handler - // of OPEN_TAB_AND_SHOW. - mAnimationCount++; - // Send a message to open a new tab. - mHandler.sendMessageDelayed( - mHandler.obtainMessage(OPEN_TAB_AND_SHOW, - mSettings.getHomePage()), delay); - } - } - - private void goBackOnePageOrQuit() { - TabControl.Tab current = mTabControl.getCurrentTab(); - if (current == null) { - /* - * Instead of finishing the activity, simply push this to the back - * of the stack and let ActivityManager to choose the foreground - * activity. As BrowserActivity is singleTask, it will be always the - * root of the task. So we can use either true or false for - * moveTaskToBack(). - */ - moveTaskToBack(true); - } - WebView w = current.getWebView(); - if (w.canGoBack()) { - w.goBack(); - } else { - // Check to see if we are closing a window that was created by - // another window. If so, we switch back to that window. - TabControl.Tab parent = current.getParentTab(); - if (parent != null) { - switchTabs(mTabControl.getCurrentIndex(), - mTabControl.getTabIndex(parent), true); - } else { - if (current.closeOnExit()) { - if (mTabControl.getTabCount() == 1) { - finish(); - return; - } - // call pauseWebView() now, we won't be able to call it in - // onPause() as the WebView won't be valid. - pauseWebView(); - removeTabFromContentView(current); - mTabControl.removeTab(current); - } - /* - * Instead of finishing the activity, simply push this to the back - * of the stack and let ActivityManager to choose the foreground - * activity. As BrowserActivity is singleTask, it will be always the - * root of the task. So we can use either true or false for - * moveTaskToBack(). - */ - moveTaskToBack(true); - } - } - } - - public KeyTracker.State onKeyTracker(int keyCode, - KeyEvent event, - KeyTracker.Stage stage, - int duration) { - // if onKeyTracker() is called after activity onStop() - // because of accumulated key events, - // we should ignore it as browser is not active any more. - WebView topWindow = getTopWindow(); - if (topWindow == null) - return KeyTracker.State.NOT_TRACKING; - - if (keyCode == KeyEvent.KEYCODE_BACK) { - // During animations, block the back key so that other animations - // are not triggered and so that we don't end up destroying all the - // WebViews before finishing the animation. - if (mAnimationCount > 0) { - return KeyTracker.State.DONE_TRACKING; - } - if (stage == KeyTracker.Stage.LONG_REPEAT) { - bookmarksOrHistoryPicker(true); - return KeyTracker.State.DONE_TRACKING; - } else if (stage == KeyTracker.Stage.UP) { - // FIXME: Currently, we do not have a notion of the - // history picker for the subwindow, but maybe we - // should? - WebView subwindow = mTabControl.getCurrentSubWindow(); - if (subwindow != null) { - if (subwindow.canGoBack()) { - subwindow.goBack(); - } else { - dismissSubWindow(mTabControl.getCurrentTab()); - } - } else { - goBackOnePageOrQuit(); - } - return KeyTracker.State.DONE_TRACKING; - } - return KeyTracker.State.KEEP_TRACKING; - } - return KeyTracker.State.NOT_TRACKING; - } - - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - mMenuIsDown = true; - } - boolean handled = mKeyTracker.doKeyDown(keyCode, event); - if (!handled) { - switch (keyCode) { - case KeyEvent.KEYCODE_SPACE: - if (event.isShiftPressed()) { - getTopWindow().pageUp(false); - } else { - getTopWindow().pageDown(false); - } - handled = true; - break; - - default: - break; - } - } - return handled || super.onKeyDown(keyCode, event); - } - - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - mMenuIsDown = false; - } - return mKeyTracker.doKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); - } - - private void stopLoading() { - resetTitleAndRevertLockIcon(); - WebView w = getTopWindow(); - w.stopLoading(); - mWebViewClient.onPageFinished(w, w.getUrl()); - - cancelStopToast(); - mStopToast = Toast - .makeText(this, R.string.stopping, Toast.LENGTH_SHORT); - mStopToast.show(); - } - - private void cancelStopToast() { - if (mStopToast != null) { - mStopToast.cancel(); - mStopToast = null; - } - } - - // called by a non-UI thread to post the message - public void postMessage(int what, int arg1, int arg2, Object obj) { - mHandler.sendMessage(mHandler.obtainMessage(what, arg1, arg2, obj)); - } - - // public message ids - public final static int LOAD_URL = 1001; - public final static int STOP_LOAD = 1002; - - // Message Ids - private static final int FOCUS_NODE_HREF = 102; - private static final int CANCEL_CREDS_REQUEST = 103; - private static final int ANIMATE_FROM_OVERVIEW = 104; - private static final int ANIMATE_TO_OVERVIEW = 105; - private static final int OPEN_TAB_AND_SHOW = 106; - private static final int CHECK_MEMORY = 107; - private static final int RELEASE_WAKELOCK = 108; - - // Private handler for handling javascript and saving passwords - private Handler mHandler = new Handler() { - - public void handleMessage(Message msg) { - switch (msg.what) { - case ANIMATE_FROM_OVERVIEW: - final HashMap map = (HashMap) msg.obj; - animateFromTabOverview((AnimatingView) map.get("view"), - msg.arg1 == 1, (Message) map.get("msg")); - break; - - case ANIMATE_TO_OVERVIEW: - animateToTabOverview(msg.arg1, msg.arg2 == 1, - (AnimatingView) msg.obj); - break; - - case OPEN_TAB_AND_SHOW: - // Decrement mAnimationCount before openTabAndShow because - // the method relies on the value being 0 to start the next - // animation. - mAnimationCount--; - openTabAndShow((String) msg.obj, null, false); - break; - - case FOCUS_NODE_HREF: - String url = (String) msg.getData().get("url"); - if (url == null || url.length() == 0) { - break; - } - HashMap focusNodeMap = (HashMap) msg.obj; - WebView view = (WebView) focusNodeMap.get("webview"); - // Only apply the action if the top window did not change. - if (getTopWindow() != view) { - break; - } - switch (msg.arg1) { - case R.id.open_context_menu_id: - case R.id.view_image_context_menu_id: - loadURL(getTopWindow(), url); - break; - case R.id.open_newtab_context_menu_id: - openTab(url); - break; - case R.id.bookmark_context_menu_id: - Intent intent = new Intent(BrowserActivity.this, - AddBookmarkPage.class); - intent.putExtra("url", url); - startActivity(intent); - break; - case R.id.share_link_context_menu_id: - Browser.sendString(BrowserActivity.this, url); - break; - case R.id.copy_link_context_menu_id: - copy(url); - break; - case R.id.save_link_context_menu_id: - case R.id.download_context_menu_id: - onDownloadStartNoStream(url, null, null, null, -1); - break; - } - break; - - case LOAD_URL: - loadURL(getTopWindow(), (String) msg.obj); - break; - - case STOP_LOAD: - stopLoading(); - break; - - case CANCEL_CREDS_REQUEST: - resumeAfterCredentials(); - break; - - case CHECK_MEMORY: - // reschedule to check memory condition - mHandler.removeMessages(CHECK_MEMORY); - mHandler.sendMessageDelayed(mHandler.obtainMessage - (CHECK_MEMORY), CHECK_MEMORY_INTERVAL); - checkMemory(); - break; - - case RELEASE_WAKELOCK: - if (mWakeLock.isHeld()) { - mWakeLock.release(); - } - break; - } - } - }; - - // ------------------------------------------------------------------------- - // WebViewClient implementation. - //------------------------------------------------------------------------- - - // Use in overrideUrlLoading - /* package */ final static String SCHEME_WTAI = "wtai://wp/"; - /* package */ final static String SCHEME_WTAI_MC = "wtai://wp/mc;"; - /* package */ final static String SCHEME_WTAI_SD = "wtai://wp/sd;"; - /* package */ final static String SCHEME_WTAI_AP = "wtai://wp/ap;"; - - /* package */ WebViewClient getWebViewClient() { - return mWebViewClient; - } - - private void updateIcon(String url, Bitmap icon) { - if (icon != null) { - BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver, - url, icon); - } - setFavicon(icon); - } - - private final WebViewClient mWebViewClient = new WebViewClient() { - @Override - public void onPageStarted(WebView view, String url, Bitmap favicon) { - resetLockIcon(url); - setUrlTitle(url, null); - // Call updateIcon instead of setFavicon so the bookmark - // database can be updated. - updateIcon(url, favicon); - - if (mSettings.isTracing() == true) { - // FIXME: we should save the trace file somewhere other than data. - // I can't use "/tmp" as it competes for system memory. - File file = getDir("browserTrace", 0); - String baseDir = file.getPath(); - if (!baseDir.endsWith(File.separator)) baseDir += File.separator; - String host; - try { - WebAddress uri = new WebAddress(url); - host = uri.mHost; - } catch (android.net.ParseException ex) { - host = "unknown_host"; - } - host = host.replace('.', '_'); - baseDir = baseDir + host; - file = new File(baseDir+".data"); - if (file.exists() == true) { - file.delete(); - } - file = new File(baseDir+".key"); - if (file.exists() == true) { - file.delete(); - } - mInTrace = true; - Debug.startMethodTracing(baseDir, 8 * 1024 * 1024); - } - - // Performance probe - if (false) { - mStart = SystemClock.uptimeMillis(); - mProcessStart = Process.getElapsedCpuTime(); - long[] sysCpu = new long[7]; - if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, null, - sysCpu, null)) { - mUserStart = sysCpu[0] + sysCpu[1]; - mSystemStart = sysCpu[2]; - mIdleStart = sysCpu[3]; - mIrqStart = sysCpu[4] + sysCpu[5] + sysCpu[6]; - } - mUiStart = SystemClock.currentThreadTimeMillis(); - } - - if (!mPageStarted) { - mPageStarted = true; - // if onResume() has been called, resumeWebView() does nothing. - resumeWebView(); - } - - // reset sync timer to avoid sync starts during loading a page - CookieSyncManager.getInstance().resetSync(); - - mInLoad = true; - updateInLoadMenuItems(); - if (!mIsNetworkUp) { - if ( mAlertDialog == null) { - mAlertDialog = new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.loadSuspendedTitle) - .setMessage(R.string.loadSuspended) - .setPositiveButton(R.string.ok, null) - .show(); - } - if (view != null) { - view.setNetworkAvailable(false); - } - } - - // schedule to check memory condition - mHandler.sendMessageDelayed(mHandler.obtainMessage(CHECK_MEMORY), - CHECK_MEMORY_INTERVAL); - } - - @Override - public void onPageFinished(WebView view, String url) { - // Reset the title and icon in case we stopped a provisional - // load. - resetTitleAndIcon(view); - - // Update the lock icon image only once we are done loading - updateLockIconImage(mLockIconType); - - // Performance probe - if (false) { - long[] sysCpu = new long[7]; - if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, null, - sysCpu, null)) { - String uiInfo = "UI thread used " - + (SystemClock.currentThreadTimeMillis() - mUiStart) - + " ms"; - if (Config.LOGD) { - Log.d(LOGTAG, uiInfo); - } - //The string that gets written to the log - String performanceString = "It took total " - + (SystemClock.uptimeMillis() - mStart) - + " ms clock time to load the page." - + "\nbrowser process used " - + (Process.getElapsedCpuTime() - mProcessStart) - + " ms, user processes used " - + (sysCpu[0] + sysCpu[1] - mUserStart) * 10 - + " ms, kernel used " - + (sysCpu[2] - mSystemStart) * 10 - + " ms, idle took " + (sysCpu[3] - mIdleStart) * 10 - + " ms and irq took " - + (sysCpu[4] + sysCpu[5] + sysCpu[6] - mIrqStart) - * 10 + " ms, " + uiInfo; - if (Config.LOGD) { - Log.d(LOGTAG, performanceString + "\nWebpage: " + url); - } - if (url != null) { - // strip the url to maintain consistency - String newUrl = new String(url); - if (newUrl.startsWith("http://www.")) { - newUrl = newUrl.substring(11); - } else if (newUrl.startsWith("http://")) { - newUrl = newUrl.substring(7); - } else if (newUrl.startsWith("https://www.")) { - newUrl = newUrl.substring(12); - } else if (newUrl.startsWith("https://")) { - newUrl = newUrl.substring(8); - } - if (Config.LOGD) { - Log.d(LOGTAG, newUrl + " loaded"); - } - /* - if (sWhiteList.contains(newUrl)) { - // The string that gets pushed to the statistcs - // service - performanceString = performanceString - + "\nWebpage: " - + newUrl - + "\nCarrier: " - + android.os.SystemProperties - .get("gsm.sim.operator.alpha"); - if (mWebView != null - && mWebView.getContext() != null - && mWebView.getContext().getSystemService( - Context.CONNECTIVITY_SERVICE) != null) { - ConnectivityManager cManager = - (ConnectivityManager) mWebView - .getContext().getSystemService( - Context.CONNECTIVITY_SERVICE); - NetworkInfo nInfo = cManager - .getActiveNetworkInfo(); - if (nInfo != null) { - performanceString = performanceString - + "\nNetwork Type: " - + nInfo.getType().toString(); - } - } - Checkin.logEvent(mResolver, - Checkin.Events.Tag.WEBPAGE_LOAD, - performanceString); - Log.w(LOGTAG, "pushed to the statistics service"); - } - */ - } - } - } - - if (mInTrace) { - mInTrace = false; - Debug.stopMethodTracing(); - } - - if (mPageStarted) { - mPageStarted = false; - // pauseWebView() will do nothing and return false if onPause() - // is not called yet. - if (pauseWebView()) { - if (mWakeLock.isHeld()) { - mHandler.removeMessages(RELEASE_WAKELOCK); - mWakeLock.release(); - } - } - } - - if (mInLoad) { - mInLoad = false; - updateInLoadMenuItems(); - } - - mHandler.removeMessages(CHECK_MEMORY); - checkMemory(); - } - - // return true if want to hijack the url to let another app to handle it - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.startsWith(SCHEME_WTAI)) { - // wtai://wp/mc;number - // number=string(phone-number) - if (url.startsWith(SCHEME_WTAI_MC)) { - Intent intent = new Intent(Intent.ACTION_VIEW, - Uri.parse(WebView.SCHEME_TEL + - url.substring(SCHEME_WTAI_MC.length()))); - startActivity(intent); - return true; - } - // wtai://wp/sd;dtmf - // dtmf=string(dialstring) - if (url.startsWith(SCHEME_WTAI_SD)) { - // TODO - // only send when there is active voice connection - return false; - } - // wtai://wp/ap;number;name - // number=string(phone-number) - // name=string - if (url.startsWith(SCHEME_WTAI_AP)) { - // TODO - return false; - } - } - - Uri uri; - try { - uri = Uri.parse(url); - } catch (IllegalArgumentException ex) { - return false; - } - - // check whether other activities want to handle this url - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.addCategory(Intent.CATEGORY_BROWSABLE); - try { - if (startActivityIfNeeded(intent, -1)) { - return true; - } - } catch (ActivityNotFoundException ex) { - // ignore the error. If no application can handle the URL, - // eg about:blank, assume the browser can handle it. - } - - if (mMenuIsDown) { - openTab(url); - closeOptionsMenu(); - return true; - } - - return false; - } - - /** - * Updates the lock icon. This method is called when we discover another - * resource to be loaded for this page (for example, javascript). While - * we update the icon type, we do not update the lock icon itself until - * we are done loading, it is slightly more secure this way. - */ - @Override - public void onLoadResource(WebView view, String url) { - if (url != null && url.length() > 0) { - // It is only if the page claims to be secure - // that we may have to update the lock: - if (mLockIconType == LOCK_ICON_SECURE) { - // If NOT a 'safe' url, change the lock to mixed content! - if (!(URLUtil.isHttpsUrl(url) || URLUtil.isDataUrl(url) || URLUtil.isAboutUrl(url))) { - mLockIconType = LOCK_ICON_MIXED; - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.updateLockIcon:" + - " updated lock icon to " + mLockIconType + " due to " + url); - } - } - } - } - } - - /** - * Show the dialog, asking the user if they would like to continue after - * an excessive number of HTTP redirects. - */ - @Override - public void onTooManyRedirects(WebView view, final Message cancelMsg, - final Message continueMsg) { - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.browserFrameRedirect) - .setMessage(R.string.browserFrame307Post) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - continueMsg.sendToTarget(); - }}) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - cancelMsg.sendToTarget(); - }}) - .setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - cancelMsg.sendToTarget(); - }}) - .show(); - } - - /** - * Show a dialog informing the user of the network error reported by - * WebCore. - */ - @Override - public void onReceivedError(WebView view, int errorCode, - String description, String failingUrl) { - if (errorCode != EventHandler.ERROR_LOOKUP && - errorCode != EventHandler.ERROR_CONNECT && - errorCode != EventHandler.ERROR_BAD_URL && - errorCode != EventHandler.ERROR_UNSUPPORTED_SCHEME && - errorCode != EventHandler.FILE_ERROR) { - new AlertDialog.Builder(BrowserActivity.this) - .setTitle((errorCode == EventHandler.FILE_NOT_FOUND_ERROR) ? - R.string.browserFrameFileErrorLabel : - R.string.browserFrameNetworkErrorLabel) - .setMessage(description) - .setPositiveButton(R.string.ok, null) - .show(); - } - Log.e(LOGTAG, "onReceivedError code:"+errorCode+" "+description); - - // We need to reset the title after an error. - resetTitleAndRevertLockIcon(); - } - - /** - * Check with the user if it is ok to resend POST data as the page they - * are trying to navigate to is the result of a POST. - */ - @Override - public void onFormResubmission(WebView view, final Message dontResend, - final Message resend) { - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.browserFrameFormResubmitLabel) - .setMessage(R.string.browserFrameFormResubmitMessage) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - resend.sendToTarget(); - }}) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dontResend.sendToTarget(); - }}) - .setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - dontResend.sendToTarget(); - }}) - .show(); - } - - /** - * Insert the url into the visited history database. - * @param url The url to be inserted. - * @param isReload True if this url is being reloaded. - * FIXME: Not sure what to do when reloading the page. - */ - @Override - public void doUpdateVisitedHistory(WebView view, String url, - boolean isReload) { - if (url.regionMatches(true, 0, "about:", 0, 6)) { - return; - } - Browser.updateVisitedHistory(mResolver, url, true); - WebIconDatabase.getInstance().retainIconForPageUrl(url); - } - - /** - * Displays SSL error(s) dialog to the user. - */ - @Override - public void onReceivedSslError( - final WebView view, final SslErrorHandler handler, final SslError error) { - - if (mSettings.showSecurityWarnings()) { - final LayoutInflater factory = - LayoutInflater.from(BrowserActivity.this); - final View warningsView = - factory.inflate(R.layout.ssl_warnings, null); - final LinearLayout placeholder = - (LinearLayout)warningsView.findViewById(R.id.placeholder); - - if (error.hasError(SslError.SSL_UNTRUSTED)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, null); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_untrusted); - placeholder.addView(ll); - } - - if (error.hasError(SslError.SSL_IDMISMATCH)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, null); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_mismatch); - placeholder.addView(ll); - } - - if (error.hasError(SslError.SSL_EXPIRED)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, null); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_expired); - placeholder.addView(ll); - } - - if (error.hasError(SslError.SSL_NOTYETVALID)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, null); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_not_yet_valid); - placeholder.addView(ll); - } - - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.security_warning) - .setIcon(android.R.drawable.ic_dialog_alert) - .setView(warningsView) - .setPositiveButton(R.string.ssl_continue, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - handler.proceed(); - } - }) - .setNeutralButton(R.string.view_certificate, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - showSSLCertificateOnError(view, handler, error); - } - }) - .setNegativeButton(R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - handler.cancel(); - BrowserActivity.this.resetTitleAndRevertLockIcon(); - } - }) - .setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - handler.cancel(); - BrowserActivity.this.resetTitleAndRevertLockIcon(); - } - }) - .show(); - } else { - handler.proceed(); - } - } - - /** - * Handles an HTTP authentication request. - * - * @param handler The authentication handler - * @param host The host - * @param realm The realm - */ - @Override - public void onReceivedHttpAuthRequest(WebView view, - final HttpAuthHandler handler, final String host, final String realm) { - String username = null; - String password = null; - - boolean reuseHttpAuthUsernamePassword = - handler.useHttpAuthUsernamePassword(); - - if (reuseHttpAuthUsernamePassword && - (mTabControl.getCurrentWebView() != null)) { - String[] credentials = - mTabControl.getCurrentWebView() - .getHttpAuthUsernamePassword(host, realm); - if (credentials != null && credentials.length == 2) { - username = credentials[0]; - password = credentials[1]; - } - } - - if (username != null && password != null) { - handler.proceed(username, password); - } else { - showHttpAuthentication(handler, host, realm, null, null, null, 0); - } - } - - @Override - public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) { - if (mMenuIsDown) { - // only check shortcut key when MENU is held - return getWindow().isShortcutKey(event.getKeyCode(), event); - } else { - return false; - } - } - - @Override - public void onUnhandledKeyEvent(WebView view, KeyEvent event) { - if (view != mTabControl.getCurrentTopWebView()) { - return; - } - if (event.isDown()) { - BrowserActivity.this.onKeyDown(event.getKeyCode(), event); - } else { - BrowserActivity.this.onKeyUp(event.getKeyCode(), event); - } - } - }; - - //-------------------------------------------------------------------------- - // WebChromeClient implementation - //-------------------------------------------------------------------------- - - /* package */ WebChromeClient getWebChromeClient() { - return mWebChromeClient; - } - - private final WebChromeClient mWebChromeClient = new WebChromeClient() { - // Helper method to create a new tab or sub window. - private void createWindow(final boolean dialog, final Message msg) { - if (dialog) { - mTabControl.createSubWindow(); - final TabControl.Tab t = mTabControl.getCurrentTab(); - attachSubWindow(t); - WebView.WebViewTransport transport = - (WebView.WebViewTransport) msg.obj; - transport.setWebView(t.getSubWebView()); - msg.sendToTarget(); - } else { - final TabControl.Tab parent = mTabControl.getCurrentTab(); - // openTabAndShow will dispatch the message after creating the - // new WebView. This will prevent another request from coming - // in during the animation. - openTabAndShow(null, msg, false); - parent.addChildTab(mTabControl.getCurrentTab()); - WebView.WebViewTransport transport = - (WebView.WebViewTransport) msg.obj; - transport.setWebView(mTabControl.getCurrentWebView()); - } - } - - @Override - public boolean onCreateWindow(WebView view, final boolean dialog, - final boolean userGesture, final Message resultMsg) { - // Ignore these requests during tab animations or if the tab - // overview is showing. - if (mAnimationCount > 0 || mTabOverview != null) { - return false; - } - // Short-circuit if we can't create any more tabs or sub windows. - if (dialog && mTabControl.getCurrentSubWindow() != null) { - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.too_many_subwindows_dialog_title) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.too_many_subwindows_dialog_message) - .setPositiveButton(R.string.ok, null) - .show(); - return false; - } else if (mTabControl.getTabCount() >= TabControl.MAX_TABS) { - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.too_many_windows_dialog_title) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.too_many_windows_dialog_message) - .setPositiveButton(R.string.ok, null) - .show(); - return false; - } - - // Short-circuit if this was a user gesture. - if (userGesture) { - // createWindow will call openTabAndShow for new Windows and - // that will call tabPicker which will increment - // mAnimationCount. - createWindow(dialog, resultMsg); - return true; - } - - // Allow the popup and create the appropriate window. - final AlertDialog.OnClickListener allowListener = - new AlertDialog.OnClickListener() { - public void onClick(DialogInterface d, - int which) { - // Same comment as above for setting - // mAnimationCount. - createWindow(dialog, resultMsg); - // Since we incremented mAnimationCount while the - // dialog was up, we have to decrement it here. - mAnimationCount--; - } - }; - - // Block the popup by returning a null WebView. - final AlertDialog.OnClickListener blockListener = - new AlertDialog.OnClickListener() { - public void onClick(DialogInterface d, int which) { - resultMsg.sendToTarget(); - // We are not going to trigger an animation so - // unblock keys and animation requests. - mAnimationCount--; - } - }; - - // Build a confirmation dialog to display to the user. - final AlertDialog d = - new AlertDialog.Builder(BrowserActivity.this) - .setTitle(R.string.attention) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.popup_window_attempt) - .setPositiveButton(R.string.allow, allowListener) - .setNegativeButton(R.string.block, blockListener) - .setCancelable(false) - .create(); - - // Show the confirmation dialog. - d.show(); - // We want to increment mAnimationCount here to prevent a - // potential race condition. If the user allows a pop-up from a - // site and that pop-up then triggers another pop-up, it is - // possible to get the BACK key between here and when the dialog - // appears. - mAnimationCount++; - return true; - } - - @Override - public void onCloseWindow(WebView window) { - final int currentIndex = mTabControl.getCurrentIndex(); - final TabControl.Tab parent = - mTabControl.getCurrentTab().getParentTab(); - if (parent != null) { - // JavaScript can only close popup window. - switchTabs(currentIndex, mTabControl.getTabIndex(parent), true); - } - } - - @Override - public void onProgressChanged(WebView view, int newProgress) { - // Block progress updates to the title bar while the tab overview - // is animating or being displayed. - if (mAnimationCount == 0 && mTabOverview == null) { - getWindow().setFeatureInt(Window.FEATURE_PROGRESS, - newProgress * 100); - } - - if (newProgress == 100) { - // onProgressChanged() is called for sub-frame too while - // onPageFinished() is only called for the main frame. sync - // cookie and cache promptly here. - CookieSyncManager.getInstance().sync(); - } - } - - @Override - public void onReceivedTitle(WebView view, String title) { - String url = view.getOriginalUrl(); - - // here, if url is null, we want to reset the title - setUrlTitle(url, title); - - if (url == null || - url.length() >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) { - return; - } - if (url.startsWith("http://www.")) { - url = url.substring(11); - } else if (url.startsWith("http://")) { - url = url.substring(4); - } - try { - url = "%" + url; - String [] selArgs = new String[] { url }; - - String where = Browser.BookmarkColumns.URL + " LIKE ? AND " - + Browser.BookmarkColumns.BOOKMARK + " = 0"; - Cursor c = mResolver.query(Browser.BOOKMARKS_URI, - Browser.HISTORY_PROJECTION, where, selArgs, null); - if (c.moveToFirst()) { - if (Config.LOGV) { - Log.v(LOGTAG, "updating cursor"); - } - // Current implementation of database only has one entry per - // url. - int titleIndex = - c.getColumnIndex(Browser.BookmarkColumns.TITLE); - c.updateString(titleIndex, title); - c.commitUpdates(); - } - c.close(); - } catch (IllegalStateException e) { - Log.e(LOGTAG, "BrowserActivity onReceived title", e); - } catch (SQLiteException ex) { - Log.e(LOGTAG, "onReceivedTitle() caught SQLiteException: ", ex); - } - } - - @Override - public void onReceivedIcon(WebView view, Bitmap icon) { - updateIcon(view.getUrl(), icon); - } - }; - - /** - * Notify the host application a download should be done, or that - * the data should be streamed if a streaming viewer is available. - * @param url The full url to the content that should be downloaded - * @param contentDisposition Content-disposition http header, if - * present. - * @param mimetype The mimetype of the content reported by the server - * @param contentLength The file size reported by the server - */ - public void onDownloadStart(String url, String userAgent, - String contentDisposition, String mimetype, long contentLength) { - // if we're dealing wih A/V content that's not explicitly marked - // for download, check if it's streamable. - if (contentDisposition == null - || !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) { - // query the package manager to see if there's a registered handler - // that matches. - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.parse(url), mimetype); - if (getPackageManager().resolveActivity(intent, - PackageManager.MATCH_DEFAULT_ONLY) != null) { - // someone knows how to handle this mime type with this scheme, don't download. - try { - startActivity(intent); - return; - } catch (ActivityNotFoundException ex) { - if (Config.LOGD) { - Log.d(LOGTAG, "activity not found for " + mimetype - + " over " + Uri.parse(url).getScheme(), ex); - } - // Best behavior is to fall back to a download in this case - } - } - } - onDownloadStartNoStream(url, userAgent, contentDisposition, mimetype, contentLength); - } - - /** - * Notify the host application a download should be done, even if there - * is a streaming viewer available for thise type. - * @param url The full url to the content that should be downloaded - * @param contentDisposition Content-disposition http header, if - * present. - * @param mimetype The mimetype of the content reported by the server - * @param contentLength The file size reported by the server - */ - /*package */ void onDownloadStartNoStream(String url, String userAgent, - String contentDisposition, String mimetype, long contentLength) { - - String filename = URLUtil.guessFileName(url, - contentDisposition, mimetype); - - // Check to see if we have an SDCard - String status = Environment.getExternalStorageState(); - if (!status.equals(Environment.MEDIA_MOUNTED)) { - int title; - String msg; - - // Check to see if the SDCard is busy, same as the music app - if (status.equals(Environment.MEDIA_SHARED)) { - msg = getString(R.string.download_sdcard_busy_dlg_msg); - title = R.string.download_sdcard_busy_dlg_title; - } else { - msg = getString(R.string.download_no_sdcard_dlg_msg, filename); - title = R.string.download_no_sdcard_dlg_title; - } - - new AlertDialog.Builder(this) - .setTitle(title) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(msg) - .setPositiveButton(R.string.ok, null) - .show(); - return; - } - - // java.net.URI is a lot stricter than KURL so we have to undo - // KURL's percent-encoding and redo the encoding using java.net.URI. - URI uri = null; - try { - // Undo the percent-encoding that KURL may have done. - String newUrl = new String(URLUtil.decode(url.getBytes())); - // Parse the url into pieces - WebAddress w = new WebAddress(newUrl); - String frag = null; - String query = null; - String path = w.mPath; - // Break the path into path, query, and fragment - if (path.length() > 0) { - // Strip the fragment - int idx = path.lastIndexOf('#'); - if (idx != -1) { - frag = path.substring(idx + 1); - path = path.substring(0, idx); - } - idx = path.lastIndexOf('?'); - if (idx != -1) { - query = path.substring(idx + 1); - path = path.substring(0, idx); - } - } - uri = new URI(w.mScheme, w.mAuthInfo, w.mHost, w.mPort, path, - query, frag); - } catch (Exception e) { - Log.e(LOGTAG, "Could not parse url for download: " + url, e); - return; - } - - // XXX: Have to use the old url since the cookies were stored using the - // old percent-encoded url. - String cookies = CookieManager.getInstance().getCookie(url); - - ContentValues values = new ContentValues(); - values.put(Downloads.URI, uri.toString()); - values.put(Downloads.COOKIE_DATA, cookies); - values.put(Downloads.USER_AGENT, userAgent); - values.put(Downloads.NOTIFICATION_PACKAGE, - getPackageName()); - values.put(Downloads.NOTIFICATION_CLASS, - BrowserDownloadPage.class.getCanonicalName()); - values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - values.put(Downloads.MIMETYPE, mimetype); - values.put(Downloads.FILENAME_HINT, filename); - values.put(Downloads.DESCRIPTION, uri.getHost()); - if (contentLength > 0) { - values.put(Downloads.TOTAL_BYTES, contentLength); - } - if (mimetype == null) { - // We must have long pressed on a link or image to download it. We - // are not sure of the mimetype in this case, so do a head request - new FetchUrlMimeType(this).execute(values); - } else { - final Uri contentUri = - getContentResolver().insert(Downloads.CONTENT_URI, values); - viewDownloads(contentUri); - } - - } - - /** - * Resets the lock icon. This method is called when we start a new load and - * know the url to be loaded. - */ - private void resetLockIcon(String url) { - // Save the lock-icon state (we revert to it if the load gets cancelled) - saveLockIcon(); - - mLockIconType = LOCK_ICON_UNSECURE; - if (URLUtil.isHttpsUrl(url)) { - mLockIconType = LOCK_ICON_SECURE; - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.resetLockIcon:" + - " reset lock icon to " + mLockIconType); - } - } - - updateLockIconImage(LOCK_ICON_UNSECURE); - } - - /** - * Resets the lock icon. This method is called when the icon needs to be - * reset but we do not know whether we are loading a secure or not secure - * page. - */ - private void resetLockIcon() { - // Save the lock-icon state (we revert to it if the load gets cancelled) - saveLockIcon(); - - mLockIconType = LOCK_ICON_UNSECURE; - - if (Config.LOGV) { - Log.v(LOGTAG, "BrowserActivity.resetLockIcon:" + - " reset lock icon to " + mLockIconType); - } - - updateLockIconImage(LOCK_ICON_UNSECURE); - } - - /** - * Updates the lock-icon image in the title-bar. - */ - private void updateLockIconImage(int lockIconType) { - Drawable d = null; - if (lockIconType == LOCK_ICON_SECURE) { - d = mSecLockIcon; - } else if (lockIconType == LOCK_ICON_MIXED) { - d = mMixLockIcon; - } - // If the tab overview is animating or being shown, do not update the - // lock icon. - if (mAnimationCount == 0 && mTabOverview == null) { - getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d); - } - } - - /** - * Displays a page-info dialog. - * @param tab The tab to show info about - * @param fromShowSSLCertificateOnError The flag that indicates whether - * this dialog was opened from the SSL-certificate-on-error dialog or - * not. This is important, since we need to know whether to return to - * the parent dialog or simply dismiss. - */ - private void showPageInfo(final TabControl.Tab tab, - final boolean fromShowSSLCertificateOnError) { - final LayoutInflater factory = LayoutInflater - .from(this); - - final View pageInfoView = factory.inflate(R.layout.page_info, null); - - final WebView view = tab.getWebView(); - - String url = null; - String title = null; - - if (view == null) { - url = tab.getUrl(); - title = tab.getTitle(); - } else if (view == mTabControl.getCurrentWebView()) { - // Use the cached title and url if this is the current WebView - url = mUrl; - title = mTitle; - } else { - url = view.getUrl(); - title = view.getTitle(); - } - - if (url == null) { - url = ""; - } - if (title == null) { - title = ""; - } - - ((TextView) pageInfoView.findViewById(R.id.address)).setText(url); - ((TextView) pageInfoView.findViewById(R.id.title)).setText(title); - - mPageInfoView = tab; - mPageInfoFromShowSSLCertificateOnError = new Boolean(fromShowSSLCertificateOnError); - - AlertDialog.Builder alertDialogBuilder = - new AlertDialog.Builder(this) - .setTitle(R.string.page_info).setIcon(android.R.drawable.ic_dialog_info) - .setView(pageInfoView) - .setPositiveButton( - R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - mPageInfoDialog = null; - mPageInfoView = null; - mPageInfoFromShowSSLCertificateOnError = null; - - // if we came here from the SSL error dialog - if (fromShowSSLCertificateOnError) { - // go back to the SSL error dialog - showSSLCertificateOnError( - mSSLCertificateOnErrorView, - mSSLCertificateOnErrorHandler, - mSSLCertificateOnErrorError); - } - } - }) - .setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - mPageInfoDialog = null; - mPageInfoView = null; - mPageInfoFromShowSSLCertificateOnError = null; - - // if we came here from the SSL error dialog - if (fromShowSSLCertificateOnError) { - // go back to the SSL error dialog - showSSLCertificateOnError( - mSSLCertificateOnErrorView, - mSSLCertificateOnErrorHandler, - mSSLCertificateOnErrorError); - } - } - }); - - // if we have a main top-level page SSL certificate set or a certificate - // error - if (fromShowSSLCertificateOnError || - (view != null && view.getCertificate() != null)) { - // add a 'View Certificate' button - alertDialogBuilder.setNeutralButton( - R.string.view_certificate, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - mPageInfoDialog = null; - mPageInfoView = null; - mPageInfoFromShowSSLCertificateOnError = null; - - // if we came here from the SSL error dialog - if (fromShowSSLCertificateOnError) { - // go back to the SSL error dialog - showSSLCertificateOnError( - mSSLCertificateOnErrorView, - mSSLCertificateOnErrorHandler, - mSSLCertificateOnErrorError); - } else { - // otherwise, display the top-most certificate from - // the chain - if (view.getCertificate() != null) { - showSSLCertificate(tab); - } - } - } - }); - } - - mPageInfoDialog = alertDialogBuilder.show(); - } - - /** - * Displays the main top-level page SSL certificate dialog - * (accessible from the Page-Info dialog). - * @param tab The tab to show certificate for. - */ - private void showSSLCertificate(final TabControl.Tab tab) { - final View certificateView = - inflateCertificateView(tab.getWebView().getCertificate()); - if (certificateView == null) { - return; - } - - LayoutInflater factory = LayoutInflater.from(this); - - final LinearLayout placeholder = - (LinearLayout)certificateView.findViewById(R.id.placeholder); - - LinearLayout ll = (LinearLayout) factory.inflate( - R.layout.ssl_success, placeholder); - ((TextView)ll.findViewById(R.id.success)) - .setText(R.string.ssl_certificate_is_valid); - - mSSLCertificateView = tab; - mSSLCertificateDialog = - new AlertDialog.Builder(this) - .setTitle(R.string.ssl_certificate).setIcon( - R.drawable.ic_dialog_browser_certificate_secure) - .setView(certificateView) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - mSSLCertificateDialog = null; - mSSLCertificateView = null; - - showPageInfo(tab, false); - } - }) - .setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - mSSLCertificateDialog = null; - mSSLCertificateView = null; - - showPageInfo(tab, false); - } - }) - .show(); - } - - /** - * Displays the SSL error certificate dialog. - * @param view The target web-view. - * @param handler The SSL error handler responsible for cancelling the - * connection that resulted in an SSL error or proceeding per user request. - * @param error The SSL error object. - */ - private void showSSLCertificateOnError( - final WebView view, final SslErrorHandler handler, final SslError error) { - - final View certificateView = - inflateCertificateView(error.getCertificate()); - if (certificateView == null) { - return; - } - - LayoutInflater factory = LayoutInflater.from(this); - - final LinearLayout placeholder = - (LinearLayout)certificateView.findViewById(R.id.placeholder); - - if (error.hasError(SslError.SSL_UNTRUSTED)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, placeholder); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_untrusted); - } - - if (error.hasError(SslError.SSL_IDMISMATCH)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, placeholder); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_mismatch); - } - - if (error.hasError(SslError.SSL_EXPIRED)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, placeholder); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_expired); - } - - if (error.hasError(SslError.SSL_NOTYETVALID)) { - LinearLayout ll = (LinearLayout)factory - .inflate(R.layout.ssl_warning, placeholder); - ((TextView)ll.findViewById(R.id.warning)) - .setText(R.string.ssl_not_yet_valid); - } - - mSSLCertificateOnErrorHandler = handler; - mSSLCertificateOnErrorView = view; - mSSLCertificateOnErrorError = error; - mSSLCertificateOnErrorDialog = - new AlertDialog.Builder(this) - .setTitle(R.string.ssl_certificate).setIcon( - R.drawable.ic_dialog_browser_certificate_partially_secure) - .setView(certificateView) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - mSSLCertificateOnErrorDialog = null; - mSSLCertificateOnErrorView = null; - mSSLCertificateOnErrorHandler = null; - mSSLCertificateOnErrorError = null; - - mWebViewClient.onReceivedSslError( - view, handler, error); - } - }) - .setNeutralButton(R.string.page_info_view, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - mSSLCertificateOnErrorDialog = null; - - // do not clear the dialog state: we will - // need to show the dialog again once the - // user is done exploring the page-info details - - showPageInfo(mTabControl.getTabFromView(view), - true); - } - }) - .setOnCancelListener( - new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - mSSLCertificateOnErrorDialog = null; - mSSLCertificateOnErrorView = null; - mSSLCertificateOnErrorHandler = null; - mSSLCertificateOnErrorError = null; - - mWebViewClient.onReceivedSslError( - view, handler, error); - } - }) - .show(); - } - - /** - * Inflates the SSL certificate view (helper method). - * @param certificate The SSL certificate. - * @return The resultant certificate view with issued-to, issued-by, - * issued-on, expires-on, and possibly other fields set. - * If the input certificate is null, returns null. - */ - private View inflateCertificateView(SslCertificate certificate) { - if (certificate == null) { - return null; - } - - LayoutInflater factory = LayoutInflater.from(this); - - View certificateView = factory.inflate( - R.layout.ssl_certificate, null); - - // issued to: - SslCertificate.DName issuedTo = certificate.getIssuedTo(); - if (issuedTo != null) { - ((TextView) certificateView.findViewById(R.id.to_common)) - .setText(issuedTo.getCName()); - ((TextView) certificateView.findViewById(R.id.to_org)) - .setText(issuedTo.getOName()); - ((TextView) certificateView.findViewById(R.id.to_org_unit)) - .setText(issuedTo.getUName()); - } - - // issued by: - SslCertificate.DName issuedBy = certificate.getIssuedBy(); - if (issuedBy != null) { - ((TextView) certificateView.findViewById(R.id.by_common)) - .setText(issuedBy.getCName()); - ((TextView) certificateView.findViewById(R.id.by_org)) - .setText(issuedBy.getOName()); - ((TextView) certificateView.findViewById(R.id.by_org_unit)) - .setText(issuedBy.getUName()); - } - - // issued on: - String issuedOn = reformatCertificateDate( - certificate.getValidNotBefore()); - ((TextView) certificateView.findViewById(R.id.issued_on)) - .setText(issuedOn); - - // expires on: - String expiresOn = reformatCertificateDate( - certificate.getValidNotAfter()); - ((TextView) certificateView.findViewById(R.id.expires_on)) - .setText(expiresOn); - - return certificateView; - } - - /** - * Re-formats the certificate date (Date.toString()) string to - * a properly localized date string. - * @return Properly localized version of the certificate date string and - * the original certificate date string if fails to localize. - * If the original string is null, returns an empty string "". - */ - private String reformatCertificateDate(String certificateDate) { - String reformattedDate = null; - - if (certificateDate != null) { - Date date = null; - try { - date = java.text.DateFormat.getInstance().parse(certificateDate); - } catch (ParseException e) { - date = null; - } - - if (date != null) { - reformattedDate = - DateFormat.getDateFormat(this).format(date); - } - } - - return reformattedDate != null ? reformattedDate : - (certificateDate != null ? certificateDate : ""); - } - - /** - * Displays an http-authentication dialog. - */ - private void showHttpAuthentication(final HttpAuthHandler handler, - final String host, final String realm, final String title, - final String name, final String password, int focusId) { - LayoutInflater factory = LayoutInflater.from(this); - final View v = factory - .inflate(R.layout.http_authentication, null); - if (name != null) { - ((EditText) v.findViewById(R.id.username_edit)).setText(name); - } - if (password != null) { - ((EditText) v.findViewById(R.id.password_edit)).setText(password); - } - - String titleText = title; - if (titleText == null) { - titleText = getText(R.string.sign_in_to).toString().replace( - "%s1", host).replace("%s2", realm); - } - - mHttpAuthHandler = handler; - AlertDialog dialog = new AlertDialog.Builder(this) - .setTitle(titleText) - .setIcon(android.R.drawable.ic_dialog_alert) - .setView(v) - .setPositiveButton(R.string.action, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - String nm = ((EditText) v - .findViewById(R.id.username_edit)) - .getText().toString(); - String pw = ((EditText) v - .findViewById(R.id.password_edit)) - .getText().toString(); - BrowserActivity.this.setHttpAuthUsernamePassword - (host, realm, nm, pw); - handler.proceed(nm, pw); - mHttpAuthenticationDialog = null; - mHttpAuthHandler = null; - }}) - .setNegativeButton(R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - handler.cancel(); - BrowserActivity.this.resetTitleAndRevertLockIcon(); - mHttpAuthenticationDialog = null; - mHttpAuthHandler = null; - }}) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - handler.cancel(); - BrowserActivity.this.resetTitleAndRevertLockIcon(); - mHttpAuthenticationDialog = null; - mHttpAuthHandler = null; - }}) - .create(); - // Make the IME appear when the dialog is displayed if applicable. - dialog.getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - dialog.show(); - if (focusId != 0) { - dialog.findViewById(focusId).requestFocus(); - } else { - v.findViewById(R.id.username_edit).requestFocus(); - } - mHttpAuthenticationDialog = dialog; - } - - public int getProgress() { - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - return w.getProgress(); - } else { - return 100; - } - } - - /** - * Set HTTP authentication password. - * - * @param host The host for the password - * @param realm The realm for the password - * @param username The username for the password. If it is null, it means - * password can't be saved. - * @param password The password - */ - public void setHttpAuthUsernamePassword(String host, String realm, - String username, - String password) { - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - w.setHttpAuthUsernamePassword(host, realm, username, password); - } - } - - /** - * connectivity manager says net has come or gone... inform the user - * @param up true if net has come up, false if net has gone down - */ - public void onNetworkToggle(boolean up) { - if (up == mIsNetworkUp) { - return; - } else if (up) { - mIsNetworkUp = true; - if (mAlertDialog != null) { - mAlertDialog.cancel(); - mAlertDialog = null; - } - } else { - mIsNetworkUp = false; - if (mInLoad && mAlertDialog == null) { - mAlertDialog = new AlertDialog.Builder(this) - .setTitle(R.string.loadSuspendedTitle) - .setMessage(R.string.loadSuspended) - .setPositiveButton(R.string.ok, null) - .show(); - } - } - WebView w = mTabControl.getCurrentWebView(); - if (w != null) { - w.setNetworkAvailable(up); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent intent) { - switch (requestCode) { - case COMBO_PAGE: - if (resultCode == RESULT_OK && intent != null) { - String data = intent.getAction(); - Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean("new_window", false)) { - openTab(data); - } else { - final TabControl.Tab currentTab = - mTabControl.getCurrentTab(); - // If the Window overview is up and we are not in the - // middle of an animation, animate away from it to the - // current tab. - if (mTabOverview != null && mAnimationCount == 0) { - sendAnimateFromOverview(currentTab, false, data, - TAB_OVERVIEW_DELAY, null); - } else { - dismissSubWindow(currentTab); - if (data != null && data.length() != 0) { - getTopWindow().loadUrl(data); - } - } - } - } - break; - default: - break; - } - getTopWindow().requestFocus(); - } - - /* - * This method is called as a result of the user selecting the options - * menu to see the download window, or when a download changes state. It - * shows the download window ontop of the current window. - */ - /* package */ void viewDownloads(Uri downloadRecord) { - Intent intent = new Intent(this, - BrowserDownloadPage.class); - intent.setData(downloadRecord); - startActivityForResult(intent, this.DOWNLOAD_PAGE); - - } - - /** - * Handle results from Tab Switcher mTabOverview tool - */ - private class TabListener implements ImageGrid.Listener { - public void remove(int position) { - // Note: Remove is not enabled if we have only one tab. - if (Config.DEBUG && mTabControl.getTabCount() == 1) { - throw new AssertionError(); - } - - // Remember the current tab. - TabControl.Tab current = mTabControl.getCurrentTab(); - final TabControl.Tab remove = mTabControl.getTab(position); - mTabControl.removeTab(remove); - // If we removed the current tab, use the tab at position - 1 if - // possible. - if (current == remove) { - // If the user removes the last tab, act like the New Tab item - // was clicked on. - if (mTabControl.getTabCount() == 0) { - current = mTabControl.createNewTab(false); - sendAnimateFromOverview(current, true, - mSettings.getHomePage(), TAB_OVERVIEW_DELAY, null); - } else { - final int index = position > 0 ? (position - 1) : 0; - current = mTabControl.getTab(index); - } - } - - // The tab overview could have been dismissed before this method is - // called. - if (mTabOverview != null) { - // Remove the tab and change the index. - mTabOverview.remove(position); - mTabOverview.setCurrentIndex(mTabControl.getTabIndex(current)); - } - - // Only the current tab ensures its WebView is non-null. This - // implies that we are reloading the freed tab. - mTabControl.setCurrentTab(current); - } - public void onClick(int index) { - // Change the tab if necessary. - // Index equals ImageGrid.CANCEL when pressing back from the tab - // overview. - if (index == ImageGrid.CANCEL) { - index = mTabControl.getCurrentIndex(); - // The current index is -1 if the current tab was removed. - if (index == -1) { - // Take the last tab as a fallback. - index = mTabControl.getTabCount() - 1; - } - } - - // Clear all the data for tab picker so next time it will be - // recreated. - mTabControl.wipeAllPickerData(); - - // NEW_TAB means that the "New Tab" cell was clicked on. - if (index == ImageGrid.NEW_TAB) { - openTabAndShow(mSettings.getHomePage(), null, false); - } else { - sendAnimateFromOverview(mTabControl.getTab(index), - false, null, 0, null); - } - } - } - - // A fake View that draws the WebView's picture with a fast zoom filter. - // The View is used in case the tab is freed during the animation because - // of low memory. - private static class AnimatingView extends View { - private static final int ZOOM_BITS = Paint.FILTER_BITMAP_FLAG | - Paint.DITHER_FLAG | Paint.SUBPIXEL_TEXT_FLAG; - private static final DrawFilter sZoomFilter = - new PaintFlagsDrawFilter(ZOOM_BITS, Paint.LINEAR_TEXT_FLAG); - private final Picture mPicture; - private final float mScale; - private final int mScrollX; - private final int mScrollY; - final TabControl.Tab mTab; - - AnimatingView(Context ctxt, TabControl.Tab t) { - super(ctxt); - mTab = t; - // Use the top window in the animation since the tab overview will - // display the top window in each cell. - final WebView w = t.getTopWindow(); - mPicture = w.capturePicture(); - mScale = w.getScale() / w.getWidth(); - mScrollX = w.getScrollX(); - mScrollY = w.getScrollY(); - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.save(); - canvas.drawColor(Color.WHITE); - if (mPicture != null) { - canvas.setDrawFilter(sZoomFilter); - float scale = getWidth() * mScale; - canvas.scale(scale, scale); - canvas.translate(-mScrollX, -mScrollY); - canvas.drawPicture(mPicture); - } - canvas.restore(); - } - } - - /** - * Open the tab picker. This function will always use the current tab in - * its animation. - * @param stay boolean stating whether the tab picker is to remain open - * (in which case it needs a listener and its menu) or not. - * @param index The index of the tab to show as the selection in the tab - * overview. - * @param remove If true, the tab at index will be removed after the - * animation completes. - */ - private void tabPicker(final boolean stay, final int index, - final boolean remove) { - if (mTabOverview != null) { - return; - } - - int size = mTabControl.getTabCount(); - - TabListener l = null; - if (stay) { - l = mTabListener = new TabListener(); - } - mTabOverview = new ImageGrid(this, stay, l); - - for (int i = 0; i < size; i++) { - final TabControl.Tab t = mTabControl.getTab(i); - mTabControl.populatePickerData(t); - mTabOverview.add(t); - } - - // Tell the tab overview to show the current tab, the tab overview will - // handle the "New Tab" case. - int currentIndex = mTabControl.getCurrentIndex(); - mTabOverview.setCurrentIndex(currentIndex); - - // Attach the tab overview. - mContentView.addView(mTabOverview, COVER_SCREEN_PARAMS); - - // Create a fake AnimatingView to animate the WebView's picture. - final TabControl.Tab current = mTabControl.getCurrentTab(); - final AnimatingView v = new AnimatingView(this, current); - mContentView.addView(v, COVER_SCREEN_PARAMS); - removeTabFromContentView(current); - // Pause timers to get the animation smoother. - current.getWebView().pauseTimers(); - - // Send a message so the tab picker has a chance to layout and get - // positions for all the cells. - mHandler.sendMessage(mHandler.obtainMessage(ANIMATE_TO_OVERVIEW, - index, remove ? 1 : 0, v)); - // Setting this will indicate that we are animating to the overview. We - // set it here to prevent another request to animate from coming in - // between now and when ANIMATE_TO_OVERVIEW is handled. - mAnimationCount++; - // Always change the title bar to the window overview title while - // animating. - getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null); - getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null); - getWindow().setFeatureInt(Window.FEATURE_PROGRESS, - Window.PROGRESS_VISIBILITY_OFF); - setTitle(R.string.tab_picker_title); - // Make the menu empty until the animation completes. - mMenuState = EMPTY_MENU; - } - - private void bookmarksOrHistoryPicker(boolean startWithHistory) { - WebView current = mTabControl.getCurrentWebView(); - if (current == null) { - return; - } - Intent intent = new Intent(this, - CombinedBookmarkHistoryActivity.class); - String title = current.getTitle(); - String url = current.getUrl(); - // Just in case the user opens bookmarks before a page finishes loading - // so the current history item, and therefore the page, is null. - if (null == url) { - url = mLastEnteredUrl; - // This can happen. - if (null == url) { - url = mSettings.getHomePage(); - } - } - // In case the web page has not yet received its associated title. - if (title == null) { - title = url; - } - intent.putExtra("title", title); - intent.putExtra("url", url); - intent.putExtra("maxTabsOpen", - mTabControl.getTabCount() >= TabControl.MAX_TABS); - if (startWithHistory) { - intent.putExtra(CombinedBookmarkHistoryActivity.STARTING_TAB, - CombinedBookmarkHistoryActivity.HISTORY_TAB); - } - startActivityForResult(intent, COMBO_PAGE); - } - - // Called when loading from context menu or LOAD_URL message - private void loadURL(WebView view, String url) { - // In case the user enters nothing. - if (url != null && url.length() != 0 && view != null) { - url = smartUrlFilter(url); - if (!mWebViewClient.shouldOverrideUrlLoading(view, url)) { - view.loadUrl(url); - } - } - } - - private void checkMemory() { - ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); - ((ActivityManager) getSystemService(ACTIVITY_SERVICE)) - .getMemoryInfo(mi); - // FIXME: mi.lowMemory is too aggressive, use (mi.availMem < - // mi.threshold) for now - // if (mi.lowMemory) { - if (mi.availMem < mi.threshold) { - Log.w(LOGTAG, "Browser is freeing memory now because: available=" - + (mi.availMem / 1024) + "K threshold=" - + (mi.threshold / 1024) + "K"); - mTabControl.freeMemory(); - } - } - - private String smartUrlFilter(Uri inUri) { - if (inUri != null) { - return smartUrlFilter(inUri.toString()); - } - return null; - } - - - // get window count - - int getWindowCount(){ - if(mTabControl != null){ - return mTabControl.getTabCount(); - } - return 0; - } - - static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile( - "(?i)" + // switch on case insensitive matching - "(" + // begin group for schema - "(?:http|https|file):\\/\\/" + - "|(?:data|about|content|javascript):" + - ")" + - "(.*)" ); - - /** - * Attempts to determine whether user input is a URL or search - * terms. Anything with a space is passed to search. - * - * Converts to lowercase any mistakenly uppercased schema (i.e., - * "Http://" converts to "http://" - * - * @return Original or modified URL - * - */ - String smartUrlFilter(String url) { - - String inUrl = url.trim(); - boolean hasSpace = inUrl.indexOf(' ') != -1; - - Matcher matcher = ACCEPTED_URI_SCHEMA.matcher(inUrl); - if (matcher.matches()) { - if (hasSpace) { - inUrl = inUrl.replace(" ", "%20"); - } - // force scheme to lowercase - String scheme = matcher.group(1); - String lcScheme = scheme.toLowerCase(); - if (!lcScheme.equals(scheme)) { - return lcScheme + matcher.group(2); - } - return inUrl; - } - if (hasSpace) { - // FIXME: quick search, need to be customized by setting - if (inUrl.length() > 2 && inUrl.charAt(1) == ' ') { - // FIXME: Is this the correct place to add to searches? - // what if someone else calls this function? - char char0 = inUrl.charAt(0); - - if (char0 == 'g') { - Browser.addSearchUrl(mResolver, inUrl); - return composeSearchUrl(inUrl.substring(2)); - - } else if (char0 == 'w') { - Browser.addSearchUrl(mResolver, inUrl); - return URLUtil.composeSearchUrl(inUrl.substring(2), - QuickSearch_W, - QUERY_PLACE_HOLDER); - - } else if (char0 == 'd') { - Browser.addSearchUrl(mResolver, inUrl); - return URLUtil.composeSearchUrl(inUrl.substring(2), - QuickSearch_D, - QUERY_PLACE_HOLDER); - - } else if (char0 == 'l') { - Browser.addSearchUrl(mResolver, inUrl); - // FIXME: we need location in this case - return URLUtil.composeSearchUrl(inUrl.substring(2), - QuickSearch_L, - QUERY_PLACE_HOLDER); - } - } - } else { - if (Regex.WEB_URL_PATTERN.matcher(inUrl).matches()) { - return URLUtil.guessUrl(inUrl); - } - } - - Browser.addSearchUrl(mResolver, inUrl); - return composeSearchUrl(inUrl); - } - - /* package */ String composeSearchUrl(String search) { - return URLUtil.composeSearchUrl(search, QuickSearch_G, - QUERY_PLACE_HOLDER); - } - - /* package */void setBaseSearchUrl(String url) { - if (url == null || url.length() == 0) { - /* - * get the google search url based on the SIM. Default is US. NOTE: - * This code uses resources to optionally select the search Uri, - * based on the MCC value from the SIM. The default string will most - * likely be fine. It is parameterized to accept info from the - * Locale, the language code is the first parameter (%1$s) and the - * country code is the second (%2$s). This code must function in the - * same way as a similar lookup in - * com.android.googlesearch.SuggestionProvider#onCreate(). If you - * change either of these functions, change them both. (The same is - * true for the underlying resource strings, which are stored in - * mcc-specific xml files.) - */ - Locale l = Locale.getDefault(); - QuickSearch_G = getResources().getString( - R.string.google_search_base, l.getLanguage(), - l.getCountry().toLowerCase()) - + "client=ms-" - + SystemProperties.get("persist.sys.com.google.clientid", "unknown") - + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s"; - } else { - QuickSearch_G = url; - } - } - - private final static int LOCK_ICON_UNSECURE = 0; - private final static int LOCK_ICON_SECURE = 1; - private final static int LOCK_ICON_MIXED = 2; - - private int mLockIconType = LOCK_ICON_UNSECURE; - private int mPrevLockType = LOCK_ICON_UNSECURE; - - private BrowserSettings mSettings; - private TabControl mTabControl; - private ContentResolver mResolver; - private FrameLayout mContentView; - private ImageGrid mTabOverview; - - // FIXME, temp address onPrepareMenu performance problem. When we move everything out of - // view, we should rewrite this. - private int mCurrentMenuState = 0; - private int mMenuState = R.id.MAIN_MENU; - private static final int EMPTY_MENU = -1; - private Menu mMenu; - - private FindDialog mFindDialog; - // Used to prevent chording to result in firing two shortcuts immediately - // one after another. Fixes bug 1211714. - boolean mCanChord; - - private boolean mInLoad; - private boolean mIsNetworkUp; - - private boolean mPageStarted; - private boolean mActivityInPause = true; - - private boolean mMenuIsDown; - - private final KeyTracker mKeyTracker = new KeyTracker(this); - - // As trackball doesn't send repeat down, we have to track it ourselves - private boolean mTrackTrackball; - - private static boolean mInTrace; - - // Performance probe - private static final int[] SYSTEM_CPU_FORMAT = new int[] { - Process.PROC_SPACE_TERM | Process.PROC_COMBINE, - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 1: user time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 2: nice time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 3: sys time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 4: idle time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 5: iowait time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG, // 6: irq time - Process.PROC_SPACE_TERM | Process.PROC_OUT_LONG // 7: softirq time - }; - - private long mStart; - private long mProcessStart; - private long mUserStart; - private long mSystemStart; - private long mIdleStart; - private long mIrqStart; - - private long mUiStart; - - private Drawable mMixLockIcon; - private Drawable mSecLockIcon; - private Drawable mGenericFavicon; - - /* hold a ref so we can auto-cancel if necessary */ - private AlertDialog mAlertDialog; - - // Wait for credentials before loading google.com - private ProgressDialog mCredsDlg; - - // The up-to-date URL and title (these can be different from those stored - // in WebView, since it takes some time for the information in WebView to - // get updated) - private String mUrl; - private String mTitle; - - // As PageInfo has different style for landscape / portrait, we have - // to re-open it when configuration changed - private AlertDialog mPageInfoDialog; - private TabControl.Tab mPageInfoView; - // If the Page-Info dialog is launched from the SSL-certificate-on-error - // dialog, we should not just dismiss it, but should get back to the - // SSL-certificate-on-error dialog. This flag is used to store this state - private Boolean mPageInfoFromShowSSLCertificateOnError; - - // as SSLCertificateOnError has different style for landscape / portrait, - // we have to re-open it when configuration changed - private AlertDialog mSSLCertificateOnErrorDialog; - private WebView mSSLCertificateOnErrorView; - private SslErrorHandler mSSLCertificateOnErrorHandler; - private SslError mSSLCertificateOnErrorError; - - // as SSLCertificate has different style for landscape / portrait, we - // have to re-open it when configuration changed - private AlertDialog mSSLCertificateDialog; - private TabControl.Tab mSSLCertificateView; - - // as HttpAuthentication has different style for landscape / portrait, we - // have to re-open it when configuration changed - private AlertDialog mHttpAuthenticationDialog; - private HttpAuthHandler mHttpAuthHandler; - - /*package*/ static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = - new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT); - // We may provide UI to customize these - // Google search from the browser - static String QuickSearch_G; - // Wikipedia search - final static String QuickSearch_W = "http://en.wikipedia.org/w/index.php?search=%s&go=Go"; - // Dictionary search - final static String QuickSearch_D = "http://dictionary.reference.com/search?q=%s"; - // Google Mobile Local search - final static String QuickSearch_L = "http://www.google.com/m/search?site=local&q=%s&near=mountain+view"; - - final static String QUERY_PLACE_HOLDER = "%s"; - - // "source" parameter for Google search through search key - final static String GOOGLE_SEARCH_SOURCE_SEARCHKEY = "browser-key"; - // "source" parameter for Google search through goto menu - final static String GOOGLE_SEARCH_SOURCE_GOTO = "browser-goto"; - // "source" parameter for Google search through simplily type - final static String GOOGLE_SEARCH_SOURCE_TYPE = "browser-type"; - // "source" parameter for Google search suggested by the browser - final static String GOOGLE_SEARCH_SOURCE_SUGGEST = "browser-suggest"; - // "source" parameter for Google search from unknown source - final static String GOOGLE_SEARCH_SOURCE_UNKNOWN = "unknown"; - - private final static String LOGTAG = "browser"; - - private TabListener mTabListener; - - private String mLastEnteredUrl; - - private PowerManager.WakeLock mWakeLock; - private final static int WAKELOCK_TIMEOUT = 5 * 60 * 1000; // 5 minutes - - private Toast mStopToast; - - // Used during animations to prevent other animations from being triggered. - // A count is used since the animation to and from the Window overview can - // overlap. A count of 0 means no animation where a count of > 0 means - // there are animations in progress. - private int mAnimationCount; - - // As the ids are dynamically created, we can't guarantee that they will - // be in sequence, so this static array maps ids to a window number. - final static private int[] WINDOW_SHORTCUT_ID_ARRAY = - { R.id.window_one_menu_id, R.id.window_two_menu_id, R.id.window_three_menu_id, - R.id.window_four_menu_id, R.id.window_five_menu_id, R.id.window_six_menu_id, - R.id.window_seven_menu_id, R.id.window_eight_menu_id }; - - // monitor platform changes - private IntentFilter mNetworkStateChangedFilter; - private BroadcastReceiver mNetworkStateIntentReceiver; - - // activity requestCode - final static int COMBO_PAGE = 1; - final static int DOWNLOAD_PAGE = 2; - final static int PREFERENCES_PAGE = 3; - - // the frenquency of checking whether system memory is low - final static int CHECK_MEMORY_INTERVAL = 30000; // 30 seconds -} diff --git a/src/com/android/browser/BrowserBookmarksAdapter.java b/src/com/android/browser/BrowserBookmarksAdapter.java deleted file mode 100644 index 479dc0e..0000000 --- a/src/com/android/browser/BrowserBookmarksAdapter.java +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.provider.Browser; -import android.provider.Browser.BookmarkColumns; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebIconDatabase; -import android.webkit.WebIconDatabase.IconListener; -import android.widget.BaseAdapter; - -import java.io.ByteArrayOutputStream; - -class BrowserBookmarksAdapter extends BaseAdapter { - - private final String LOGTAG = "Bookmarks"; - - private String mCurrentPage; - private Cursor mCursor; - private int mCount; - private String mLastWhereClause; - private String[] mLastSelectionArgs; - private String mLastOrderBy; - private BrowserBookmarksPage mBookmarksPage; - private ContentResolver mContentResolver; - private ChangeObserver mChangeObserver; - private DataSetObserver mDataSetObserver; - private boolean mDataValid; - - // When true, this adapter is used to pick a bookmark to create a shortcut - private boolean mCreateShortcut; - private int mExtraOffset; - - // Implementation of WebIconDatabase.IconListener - private class IconReceiver implements IconListener { - public void onReceivedIcon(String url, Bitmap icon) { - updateBookmarkFavicon(mContentResolver, url, icon); - } - } - - // Instance of IconReceiver - private final IconReceiver mIconReceiver = new IconReceiver(); - - /** - * Create a new BrowserBookmarksAdapter. - * @param b BrowserBookmarksPage that instantiated this. - * Necessary so it will adjust its focus - * appropriately after a search. - */ - public BrowserBookmarksAdapter(BrowserBookmarksPage b, String curPage) { - this(b, curPage, false); - } - - /** - * Create a new BrowserBookmarksAdapter. - * @param b BrowserBookmarksPage that instantiated this. - * Necessary so it will adjust its focus - * appropriately after a search. - */ - public BrowserBookmarksAdapter(BrowserBookmarksPage b, String curPage, - boolean createShortcut) { - mDataValid = false; - mCreateShortcut = createShortcut; - mExtraOffset = createShortcut ? 0 : 1; - mBookmarksPage = b; - mCurrentPage = b.getResources().getString(R.string.current_page) + - curPage; - mContentResolver = b.getContentResolver(); - mLastOrderBy = Browser.BookmarkColumns.CREATED + " DESC"; - mChangeObserver = new ChangeObserver(); - mDataSetObserver = new MyDataSetObserver(); - // FIXME: Should have a default sort order that the user selects. - search(null); - // FIXME: This requires another query of the database after the - // initial search(null). Can we optimize this? - Browser.requestAllIcons(mContentResolver, - Browser.BookmarkColumns.FAVICON + " is NULL AND " + - Browser.BookmarkColumns.BOOKMARK + " == 1", mIconReceiver); - } - - /** - * Return a hashmap with one row's Title, Url, and favicon. - * @param position Position in the list. - * @return Bundle Stores title, url of row position, favicon, and id - * for the url. Return a blank map if position is out of - * range. - */ - public Bundle getRow(int position) { - Bundle map = new Bundle(); - if (position < mExtraOffset || position >= mCount) { - return map; - } - mCursor.moveToPosition(position- mExtraOffset); - String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX); - map.putString(Browser.BookmarkColumns.TITLE, - mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX)); - map.putString(Browser.BookmarkColumns.URL, url); - byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX); - if (data != null) { - map.putParcelable(Browser.BookmarkColumns.FAVICON, - BitmapFactory.decodeByteArray(data, 0, data.length)); - } - map.putInt("id", mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX)); - return map; - } - - /** - * Update a row in the database with new information. - * Requeries the database if the information has changed. - * @param map Bundle storing id, title and url of new information - */ - public void updateRow(Bundle map) { - - // Find the record - int id = map.getInt("id"); - int position = -1; - for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) { - if (mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX) == id) { - position = mCursor.getPosition(); - break; - } - } - if (position < 0) { - return; - } - - mCursor.moveToPosition(position); - ContentValues values = new ContentValues(); - String title = map.getString(Browser.BookmarkColumns.TITLE); - if (!title.equals(mCursor - .getString(Browser.HISTORY_PROJECTION_TITLE_INDEX))) { - values.put(Browser.BookmarkColumns.TITLE, title); - } - String url = map.getString(Browser.BookmarkColumns.URL); - if (!url.equals(mCursor. - getString(Browser.HISTORY_PROJECTION_URL_INDEX))) { - values.put(Browser.BookmarkColumns.URL, url); - } - if (values.size() > 0 - && mContentResolver.update(Browser.BOOKMARKS_URI, values, - "_id = " + id, null) != -1) { - refreshList(); - } - } - - /** - * Delete a row from the database. Requeries the database. - * Does nothing if the provided position is out of range. - * @param position Position in the list. - */ - public void deleteRow(int position) { - if (position < mExtraOffset || position >= getCount()) { - return; - } - mCursor.moveToPosition(position- mExtraOffset); - String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX); - WebIconDatabase.getInstance().releaseIconForPageUrl(url); - Uri uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI, mCursor - .getInt(Browser.HISTORY_PROJECTION_ID_INDEX)); - int numVisits = mCursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX); - if (0 == numVisits) { - mContentResolver.delete(uri, null, null); - } else { - // It is no longer a bookmark, but it is still a visited site. - ContentValues values = new ContentValues(); - values.put(Browser.BookmarkColumns.BOOKMARK, 0); - mContentResolver.update(uri, values, null, null); - } - refreshList(); - } - - /** - * Delete all bookmarks from the db. Requeries the database. - * All bookmarks with become visited URLs or if never visited - * are removed - */ - public void deleteAllRows() { - StringBuilder deleteIds = null; - StringBuilder convertIds = null; - - for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) { - String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX); - WebIconDatabase.getInstance().releaseIconForPageUrl(url); - int id = mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX); - int numVisits = mCursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX); - if (0 == numVisits) { - if (deleteIds == null) { - deleteIds = new StringBuilder(); - deleteIds.append("( "); - } else { - deleteIds.append(" OR ( "); - } - deleteIds.append(BookmarkColumns._ID); - deleteIds.append(" = "); - deleteIds.append(id); - deleteIds.append(" )"); - } else { - // It is no longer a bookmark, but it is still a visited site. - if (convertIds == null) { - convertIds = new StringBuilder(); - convertIds.append("( "); - } else { - convertIds.append(" OR ( "); - } - convertIds.append(BookmarkColumns._ID); - convertIds.append(" = "); - convertIds.append(id); - convertIds.append(" )"); - } - } - - if (deleteIds != null) { - mContentResolver.delete(Browser.BOOKMARKS_URI, deleteIds.toString(), - null); - } - if (convertIds != null) { - ContentValues values = new ContentValues(); - values.put(Browser.BookmarkColumns.BOOKMARK, 0); - mContentResolver.update(Browser.BOOKMARKS_URI, values, - convertIds.toString(), null); - } - refreshList(); - } - - /** - * Refresh list to recognize a change in the database. - */ - public void refreshList() { - // FIXME: consider using requery(). - // Need to do more work to get it to function though. - searchInternal(mLastWhereClause, mLastSelectionArgs, mLastOrderBy); - } - - /** - * Search the database for bookmarks that match the input string. - * @param like String to use to search the database. Strings with spaces - * are treated as having multiple search terms using the - * OR operator. Search both the title and url. - */ - public void search(String like) { - String whereClause = Browser.BookmarkColumns.BOOKMARK + " == 1"; - String[] selectionArgs = null; - if (like != null) { - String[] likes = like.split(" "); - int count = 0; - boolean firstTerm = true; - StringBuilder andClause = new StringBuilder(256); - for (int j = 0; j < likes.length; j++) { - if (likes[j].length() > 0) { - if (firstTerm) { - firstTerm = false; - } else { - andClause.append(" OR "); - } - andClause.append(Browser.BookmarkColumns.TITLE - + " LIKE ? OR " + Browser.BookmarkColumns.URL - + " LIKE ? "); - count += 2; - } - } - if (count > 0) { - selectionArgs = new String[count]; - count = 0; - for (int j = 0; j < likes.length; j++) { - if (likes[j].length() > 0) { - like = "%" + likes[j] + "%"; - selectionArgs[count++] = like; - selectionArgs[count++] = like; - } - } - whereClause += " AND (" + andClause + ")"; - } - } - searchInternal(whereClause, selectionArgs, mLastOrderBy); - } - - /** - * Update the bookmark's favicon. - * @param cr The ContentResolver to use. - * @param url The url of the bookmark to update. - * @param favicon The favicon bitmap to write to the db. - */ - /* package */ static void updateBookmarkFavicon(ContentResolver cr, - String url, Bitmap favicon) { - if (url == null || favicon == null) { - return; - } - // Strip the query. - int query = url.indexOf('?'); - String noQuery = url; - if (query != -1) { - noQuery = url.substring(0, query); - } - url = noQuery + '?'; - // Use noQuery to search for the base url (i.e. if the url is - // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com) - // Use url to match the base url with other queries (i.e. if the url is - // http://www.google.com/m, search for - // http://www.google.com/m?some_query) - final String[] selArgs = new String[] { noQuery, url }; - final String where = "(" + Browser.BookmarkColumns.URL + " == ? OR " - + Browser.BookmarkColumns.URL + " GLOB ? || '*') AND " - + Browser.BookmarkColumns.BOOKMARK + " == 1"; - final String[] projection = new String[] { Browser.BookmarkColumns._ID }; - final Cursor c = cr.query(Browser.BOOKMARKS_URI, projection, where, - selArgs, null); - boolean succeed = c.moveToFirst(); - ContentValues values = null; - while (succeed) { - if (values == null) { - final ByteArrayOutputStream os = new ByteArrayOutputStream(); - favicon.compress(Bitmap.CompressFormat.PNG, 100, os); - values = new ContentValues(); - values.put(Browser.BookmarkColumns.FAVICON, os.toByteArray()); - } - cr.update(ContentUris.withAppendedId(Browser.BOOKMARKS_URI, c - .getInt(0)), values, null, null); - succeed = c.moveToNext(); - } - c.close(); - } - - /** - * This sorts alphabetically, with non-capitalized titles before - * capitalized. - */ - public void sortAlphabetical() { - searchInternal(mLastWhereClause, mLastSelectionArgs, - Browser.BookmarkColumns.TITLE + " COLLATE UNICODE ASC"); - } - - /** - * Internal function used in search, sort, and refreshList. - */ - private void searchInternal(String whereClause, String[] selectionArgs, - String orderBy) { - if (mCursor != null) { - mCursor.unregisterContentObserver(mChangeObserver); - mCursor.unregisterDataSetObserver(mDataSetObserver); - mBookmarksPage.stopManagingCursor(mCursor); - mCursor.deactivate(); - } - - mLastWhereClause = whereClause; - mLastSelectionArgs = selectionArgs; - mLastOrderBy = orderBy; - mCursor = mContentResolver.query( - Browser.BOOKMARKS_URI, - Browser.HISTORY_PROJECTION, - whereClause, - selectionArgs, - orderBy); - mCursor.registerContentObserver(mChangeObserver); - mCursor.registerDataSetObserver(mDataSetObserver); - mBookmarksPage.startManagingCursor(mCursor); - - mDataValid = true; - notifyDataSetChanged(); - - mCount = mCursor.getCount() + mExtraOffset; - } - - /** - * How many items should be displayed in the list. - * @return Count of items. - */ - public int getCount() { - if (mDataValid) { - return mCount; - } else { - return 0; - } - } - - public boolean areAllItemsEnabled() { - return true; - } - - public boolean isEnabled(int position) { - return true; - } - - /** - * Get the data associated with the specified position in the list. - * @param position Index of the item whose data we want. - * @return The data at the specified position. - */ - public Object getItem(int position) { - return null; - } - - /** - * Get the row id associated with the specified position in the list. - * @param position Index of the item whose row id we want. - * @return The id of the item at the specified position. - */ - public long getItemId(int position) { - return position; - } - - /** - * Get a View that displays the data at the specified position - * in the list. - * @param position Index of the item whose view we want. - * @return A View corresponding to the data at the specified position. - */ - public View getView(int position, View convertView, ViewGroup parent) { - if (!mDataValid) { - throw new IllegalStateException( - "this should only be called when the cursor is valid"); - } - if (position < 0 || position > mCount) { - throw new AssertionError( - "BrowserBookmarksAdapter tried to get a view out of range"); - } - if (position == 0 && !mCreateShortcut) { - AddNewBookmark b; - if (convertView instanceof AddNewBookmark) { - b = (AddNewBookmark) convertView; - } else { - b = new AddNewBookmark(mBookmarksPage); - } - b.setUrl(mCurrentPage); - return b; - } - if (convertView == null || convertView instanceof AddNewBookmark) { - convertView = new BookmarkItem(mBookmarksPage); - } - bind((BookmarkItem)convertView, position); - return convertView; - } - - /** - * Return the title for this item in the list. - */ - public String getTitle(int position) { - return getString(Browser.HISTORY_PROJECTION_TITLE_INDEX, position); - } - - /** - * Return the Url for this item in the list. - */ - public String getUrl(int position) { - return getString(Browser.HISTORY_PROJECTION_URL_INDEX, position); - } - - /** - * Private helper function to return the title or url. - */ - private String getString(int cursorIndex, int position) { - if (position < mExtraOffset || position > mCount) { - return ""; - } - mCursor.moveToPosition(position- mExtraOffset); - return mCursor.getString(cursorIndex); - } - - private void bind(BookmarkItem b, int position) { - mCursor.moveToPosition(position- mExtraOffset); - - String title = mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX); - if (title.length() > BrowserSettings.MAX_TEXTVIEW_LEN) { - title = title.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN); - } - b.setName(title); - String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX); - if (url.length() > BrowserSettings.MAX_TEXTVIEW_LEN) { - url = url.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN); - } - b.setUrl(url); - byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX); - if (data != null) { - b.setFavicon(BitmapFactory.decodeByteArray(data, 0, data.length)); - } else { - b.setFavicon(null); - } - } - - private class ChangeObserver extends ContentObserver { - public ChangeObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - refreshList(); - } - } - - private class MyDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - mDataValid = true; - notifyDataSetChanged(); - } - - @Override - public void onInvalidated() { - mDataValid = false; - notifyDataSetInvalidated(); - } - } -} diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java deleted file mode 100644 index 7708e8b..0000000 --- a/src/com/android/browser/BrowserBookmarksPage.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2006 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.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.ServiceManager; -import android.provider.Browser; -import android.text.IClipboard; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; -import android.widget.AdapterView; -import android.widget.ListView; - -/** - * View showing the user's bookmarks in the browser. - */ -public class BrowserBookmarksPage extends Activity implements - View.OnCreateContextMenuListener { - - private BrowserBookmarksAdapter mBookmarksAdapter; - private static final int BOOKMARKS_SAVE = 1; - private boolean mMaxTabsOpen; - private BookmarkItem mContextHeader; - private AddNewBookmark mAddHeader; - private boolean mCanceled = false; - private boolean mCreateShortcut; - // XXX: There is no public string defining this intent so if Home changes - // the value, we have to update this string. - private static final String INSTALL_SHORTCUT = - "com.android.launcher.action.INSTALL_SHORTCUT"; - - private final static String LOGTAG = "browser"; - - - @Override - public boolean onContextItemSelected(MenuItem item) { - // It is possible that the view has been canceled when we get to - // this point as back has a higher priority - if (mCanceled) { - return true; - } - AdapterView.AdapterContextMenuInfo i = - (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); - // If we have no menu info, we can't tell which item was selected. - if (i == null) { - return true; - } - - switch (item.getItemId()) { - case R.id.new_context_menu_id: - saveCurrentPage(); - break; - case R.id.open_context_menu_id: - loadUrl(i.position); - break; - case R.id.edit_context_menu_id: - editBookmark(i.position); - break; - case R.id.shortcut_context_menu_id: - final Intent send = createShortcutIntent(getUrl(i.position), - getBookmarkTitle(i.position)); - send.setAction(INSTALL_SHORTCUT); - sendBroadcast(send); - break; - case R.id.delete_context_menu_id: - displayRemoveBookmarkDialog(i.position); - break; - case R.id.new_window_context_menu_id: - openInNewWindow(i.position); - break; - case R.id.send_context_menu_id: - Browser.sendString(BrowserBookmarksPage.this, getUrl(i.position)); - break; - case R.id.copy_url_context_menu_id: - copy(getUrl(i.position)); - - default: - return super.onContextItemSelected(item); - } - return true; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - AdapterView.AdapterContextMenuInfo i = - (AdapterView.AdapterContextMenuInfo) menuInfo; - - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.bookmarkscontext, menu); - - if (0 == i.position) { - menu.setGroupVisible(R.id.CONTEXT_MENU, false); - if (mAddHeader == null) { - mAddHeader = new AddNewBookmark(BrowserBookmarksPage.this); - } else if (mAddHeader.getParent() != null) { - ((ViewGroup) mAddHeader.getParent()). - removeView(mAddHeader); - } - ((AddNewBookmark) i.targetView).copyTo(mAddHeader); - menu.setHeaderView(mAddHeader); - return; - } - menu.setGroupVisible(R.id.ADD_MENU, false); - BookmarkItem b = (BookmarkItem) i.targetView; - if (mContextHeader == null) { - mContextHeader = new BookmarkItem(BrowserBookmarksPage.this); - } else if (mContextHeader.getParent() != null) { - ((ViewGroup) mContextHeader.getParent()). - removeView(mContextHeader); - } - b.copyTo(mContextHeader); - menu.setHeaderView(mContextHeader); - - if (mMaxTabsOpen) { - menu.findItem(R.id.new_window_context_menu_id).setVisible( - false); - } - } - - /** - * Create a new BrowserBookmarksPage. - */ - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - setContentView(R.layout.browser_bookmarks_page); - setTitle(R.string.browser_bookmarks_page_bookmarks_text); - - if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) { - mCreateShortcut = true; - } - - mBookmarksAdapter = new BrowserBookmarksAdapter(this, - getIntent().getStringExtra("url"), mCreateShortcut); - mMaxTabsOpen = getIntent().getBooleanExtra("maxTabsOpen", false); - - ListView listView = (ListView) findViewById(R.id.list); - listView.setAdapter(mBookmarksAdapter); - listView.setDrawSelectorOnTop(false); - listView.setVerticalScrollBarEnabled(true); - listView.setOnItemClickListener(mListener); - - if (!mCreateShortcut) { - listView.setOnCreateContextMenuListener(this); - } - } - - private static final int SAVE_CURRENT_PAGE = 1000; - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - if (msg.what == SAVE_CURRENT_PAGE) { - saveCurrentPage(); - } - } - }; - - private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View v, int position, long id) { - // It is possible that the view has been canceled when we get to - // this point as back has a higher priority - if (mCanceled) { - android.util.Log.e("browser", "item clicked when dismising"); - return; - } - if (!mCreateShortcut) { - if (0 == position) { - // XXX: Work-around for a framework issue. - mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE); - } else { - loadUrl(position); - } - } else { - final Intent intent = createShortcutIntent(getUrl(position), - getBookmarkTitle(position)); - setResultToParent(RESULT_OK, intent); - finish(); - } - } - }; - - private Intent createShortcutIntent(String url, String title) { - final Intent i = new Intent(); - i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(Intent.ACTION_VIEW, - Uri.parse(url))); - i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); - i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext(BrowserBookmarksPage.this, - R.drawable.ic_launcher_browser)); - // Do not allow duplicate items - i.putExtra("duplicate", false); - return i; - } - - private void saveCurrentPage() { - Intent i = new Intent(BrowserBookmarksPage.this, - AddBookmarkPage.class); - i.putExtras(getIntent()); - startActivityForResult(i, BOOKMARKS_SAVE); - } - - private void loadUrl(int position) { - Intent intent = (new Intent()).setAction(getUrl(position)); - setResultToParent(RESULT_OK, intent); - finish(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - boolean result = super.onCreateOptionsMenu(menu); - if (!mCreateShortcut) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.bookmarks, menu); - return true; - } - return result; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.new_context_menu_id: - saveCurrentPage(); - break; - - default: - return super.onOptionsItemSelected(item); - } - return true; - } - - private void openInNewWindow(int position) { - Bundle b = new Bundle(); - b.putBoolean("new_window", true); - setResultToParent(RESULT_OK, - (new Intent()).setAction(getUrl(position)).putExtras(b)); - - finish(); - } - - - private void editBookmark(int position) { - Intent intent = new Intent(BrowserBookmarksPage.this, - AddBookmarkPage.class); - intent.putExtra("bookmark", getRow(position)); - startActivityForResult(intent, BOOKMARKS_SAVE); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - Intent data) { - switch(requestCode) { - case BOOKMARKS_SAVE: - if (resultCode == RESULT_OK) { - Bundle extras; - if (data != null && (extras = data.getExtras()) != null) { - // If there are extras, then we need to save - // the edited bookmark. This is done in updateRow() - String title = extras.getString("title"); - String url = extras.getString("url"); - if (title != null && url != null) { - mBookmarksAdapter.updateRow(extras); - } - } else { - // extras == null then a new bookmark was added to - // the database. - refreshList(); - } - } - break; - default: - break; - } - } - - private void displayRemoveBookmarkDialog(int position) { - // Put up a dialog asking if the user really wants to - // delete the bookmark - final int deletePos = position; - new AlertDialog.Builder(this) - .setTitle(R.string.delete_bookmark) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getText(R.string.delete_bookmark_warning).toString().replace( - "%s", getBookmarkTitle(deletePos))) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - deleteBookmark(deletePos); - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - /** - * Refresh the shown list after the database has changed. - */ - public void refreshList() { - mBookmarksAdapter.refreshList(); - } - - /** - * Return a hashmap representing the currently highlighted row. - */ - public Bundle getRow(int position) { - return mBookmarksAdapter.getRow(position); - } - - /** - * Return the url of the currently highlighted row. - */ - public String getUrl(int position) { - return mBookmarksAdapter.getUrl(position); - } - - private void copy(CharSequence text) { - try { - IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard")); - if (clip != null) { - clip.setClipboardText(text); - } - } catch (android.os.RemoteException e) { - Log.e(LOGTAG, "Copy failed", e); - } - } - - public String getBookmarkTitle(int position) { - return mBookmarksAdapter.getTitle(position); - } - - /** - * Delete the currently highlighted row. - */ - public void deleteBookmark(int position) { - mBookmarksAdapter.deleteRow(position); - } - - public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.isDown()) { - setResultToParent(RESULT_CANCELED, null); - mCanceled = true; - } - return super.dispatchKeyEvent(event); - } - - // This Activity is generally a sub-Activity of CombinedHistoryActivity. In - // that situation, we need to pass our result code up to our parent. - // However, if someone calls this Activity directly, then this has no - // parent, and it needs to set it on itself. - private void setResultToParent(int resultCode, Intent data) { - Activity a = getParent() == null ? this : getParent(); - a.setResult(resultCode, data); - } -} diff --git a/src/com/android/browser/BrowserDownloadAdapter.java b/src/com/android/browser/BrowserDownloadAdapter.java deleted file mode 100644 index 38b83fe..0000000 --- a/src/com/android/browser/BrowserDownloadAdapter.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2007 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.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.database.Cursor; -import android.drm.mobile1.DrmRawContent; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.provider.Downloads; -import android.text.format.Formatter; -import android.view.View; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.ResourceCursorAdapter; -import android.widget.TextView; - -import java.io.File; -import java.text.DateFormat; -import java.util.Date; -import java.util.List; - -/** - * This class is used to represent the data for the download list box. The only - * real work done by this class is to construct a custom view for the line - * items. - */ -public class BrowserDownloadAdapter extends ResourceCursorAdapter { - - private int mFilenameColumnId; - private int mTitleColumnId; - private int mDescColumnId; - private int mStatusColumnId; - private int mTotalBytesColumnId; - private int mCurrentBytesColumnId; - private int mMimetypeColumnId; - private int mDateColumnId; - - public BrowserDownloadAdapter(Context context, int layout, Cursor c) { - super(context, layout, c); - mFilenameColumnId = c.getColumnIndexOrThrow(Downloads._DATA); - mTitleColumnId = c.getColumnIndexOrThrow(Downloads.TITLE); - mDescColumnId = c.getColumnIndexOrThrow(Downloads.DESCRIPTION); - mStatusColumnId = c.getColumnIndexOrThrow(Downloads.STATUS); - mTotalBytesColumnId = c.getColumnIndexOrThrow(Downloads.TOTAL_BYTES); - mCurrentBytesColumnId = - c.getColumnIndexOrThrow(Downloads.CURRENT_BYTES); - mMimetypeColumnId = c.getColumnIndexOrThrow(Downloads.MIMETYPE); - mDateColumnId = c.getColumnIndexOrThrow(Downloads.LAST_MODIFICATION); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - Resources r = context.getResources(); - - // Retrieve the icon for this download - String mimeType = cursor.getString(mMimetypeColumnId); - ImageView iv = (ImageView) view.findViewById(R.id.download_icon); - if (DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { - iv.setImageResource(R.drawable.ic_launcher_drm_file); - } else if (mimeType == null) { - iv.setVisibility(View.INVISIBLE); - } else { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromParts("file", "", null), mimeType); - PackageManager pm = context.getPackageManager(); - List<ResolveInfo> list = pm.queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - if (list.size() > 0) { - Drawable icon = list.get(0).activityInfo.loadIcon(pm); - iv.setImageDrawable(icon); - iv.setVisibility(View.VISIBLE); - } else { - iv.setVisibility(View.INVISIBLE); - } - } - - TextView tv = (TextView) view.findViewById(R.id.download_title); - String title = cursor.getString(mTitleColumnId); - if (title == null) { - String fullFilename = cursor.getString(mFilenameColumnId); - if (fullFilename == null) { - title = r.getString(R.string.download_unknown_filename); - } else { - // We have a filename, so we can build a title from that - title = new File(fullFilename).getName(); - ContentValues values = new ContentValues(); - values.put(Downloads.TITLE, title); - // assume "_id" is the first column for the cursor - context.getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, - cursor.getLong(0)), values, null, null); - } - } - tv.setText(title); - - tv = (TextView) view.findViewById(R.id.domain); - tv.setText(cursor.getString(mDescColumnId)); - - long totalBytes = cursor.getLong(mTotalBytesColumnId); - - int status = cursor.getInt(mStatusColumnId); - if (Downloads.isStatusCompleted(status)) { // Download stopped - View v = view.findViewById(R.id.progress_text); - v.setVisibility(View.GONE); - - v = view.findViewById(R.id.download_progress); - v.setVisibility(View.GONE); - - tv = (TextView) view.findViewById(R.id.complete_text); - tv.setVisibility(View.VISIBLE); - if (Downloads.isStatusError(status)) { - tv.setText(getErrorText(status)); - } else { - tv.setText(r.getString(R.string.download_success, - Formatter.formatFileSize(mContext, totalBytes))); - } - - long time = cursor.getLong(mDateColumnId); - Date d = new Date(time); - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); - tv = (TextView) view.findViewById(R.id.complete_date); - tv.setVisibility(View.VISIBLE); - tv.setText(df.format(d)); - - } else { // Download is still running - tv = (TextView) view.findViewById(R.id.progress_text); - tv.setVisibility(View.VISIBLE); - - View progress = view.findViewById(R.id.download_progress); - progress.setVisibility(View.VISIBLE); - - View v = view.findViewById(R.id.complete_date); - v.setVisibility(View.GONE); - - v = view.findViewById(R.id.complete_text); - v.setVisibility(View.GONE); - - if (status == Downloads.STATUS_PENDING) { - tv.setText(r.getText(R.string.download_pending)); - } else if (status == Downloads.STATUS_PENDING_PAUSED) { - tv.setText(r.getText(R.string.download_pending_network)); - } else { - ProgressBar pb = (ProgressBar) progress; - - StringBuilder sb = new StringBuilder(); - if (status == Downloads.STATUS_RUNNING) { - sb.append(r.getText(R.string.download_running)); - } else { - sb.append(r.getText(R.string.download_running_paused)); - } - if (totalBytes > 0) { - long currentBytes = cursor.getLong(mCurrentBytesColumnId); - int progressAmount = (int)(currentBytes * 100 / totalBytes); - sb.append(' '); - sb.append(progressAmount); - sb.append("% ("); - sb.append(Formatter.formatFileSize(mContext, currentBytes)); - sb.append("/"); - sb.append(Formatter.formatFileSize(mContext, totalBytes)); - sb.append(")"); - pb.setIndeterminate(false); - pb.setProgress(progressAmount); - } else { - pb.setIndeterminate(true); - } - tv.setText(sb.toString()); - } - } - - } - - /** - * Provide the resource id for the error string. - * @param status status of the download item - * @return resource id for the error string. - */ - public static int getErrorText(int status) { - switch (status) { - case Downloads.STATUS_NOT_ACCEPTABLE: - return R.string.download_not_acceptable; - - case Downloads.STATUS_LENGTH_REQUIRED: - return R.string.download_length_required; - - case Downloads.STATUS_PRECONDITION_FAILED: - return R.string.download_precondition_failed; - - case Downloads.STATUS_CANCELED: - return R.string.download_canceled; - - case Downloads.STATUS_FILE_ERROR: - return R.string.download_file_error; - - case Downloads.STATUS_BAD_REQUEST: - case Downloads.STATUS_UNKNOWN_ERROR: - default: - return R.string.download_error; - } - } -} diff --git a/src/com/android/browser/BrowserDownloadPage.java b/src/com/android/browser/BrowserDownloadPage.java deleted file mode 100644 index 4397337..0000000 --- a/src/com/android/browser/BrowserDownloadPage.java +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2007 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.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.ContentValues; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.ContentUris; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Downloads; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.AdapterView.OnItemClickListener; - -import java.io.File; -import java.util.List; - -/** - * View showing the user's current browser downloads - */ -public class BrowserDownloadPage extends Activity - implements View.OnCreateContextMenuListener, OnItemClickListener { - - private ListView mListView; - private Cursor mDownloadCursor; - private BrowserDownloadAdapter mDownloadAdapter; - private int mStatusColumnId; - private int mIdColumnId; - private int mTitleColumnId; - private int mContextMenuPosition; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.browser_downloads_page); - - setTitle(getText(R.string.download_title)); - - mListView = (ListView) findViewById(R.id.list); - LayoutInflater factory = LayoutInflater.from(this); - View v = factory.inflate(R.layout.no_downloads, null); - addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.FILL_PARENT)); - mListView.setEmptyView(v); - - mDownloadCursor = managedQuery(Downloads.CONTENT_URI, - new String [] {"_id", Downloads.TITLE, Downloads.STATUS, - Downloads.TOTAL_BYTES, Downloads.CURRENT_BYTES, - Downloads._DATA, Downloads.DESCRIPTION, - Downloads.MIMETYPE, Downloads.LAST_MODIFICATION, - Downloads.VISIBILITY}, - null, null); - - // only attach everything to the listbox if we can access - // the download database. Otherwise, just show it empty - if (mDownloadCursor != null) { - mStatusColumnId = - mDownloadCursor.getColumnIndexOrThrow(Downloads.STATUS); - mIdColumnId = - mDownloadCursor.getColumnIndexOrThrow(Downloads._ID); - mTitleColumnId = - mDownloadCursor.getColumnIndexOrThrow(Downloads.TITLE); - - // Create a list "controller" for the data - mDownloadAdapter = new BrowserDownloadAdapter(this, - R.layout.browser_download_item, mDownloadCursor); - - mListView.setAdapter(mDownloadAdapter); - mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); - mListView.setOnCreateContextMenuListener(this); - mListView.setOnItemClickListener(this); - - Intent intent = getIntent(); - if (intent != null && intent.getData() != null) { - int position = checkStatus( - ContentUris.parseId(intent.getData())); - if (position >= 0) { - mListView.setSelection(position); - } - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (mDownloadCursor != null) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.downloadhistory, menu); - } - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - boolean showCancel = getCancelableCount() > 0; - menu.findItem(R.id.download_menu_cancel_all).setEnabled(showCancel); - - boolean showClear = getClearableCount() > 0; - menu.findItem(R.id.download_menu_clear_all).setEnabled(showClear); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.download_menu_cancel_all: - promptCancelAll(); - return true; - - case R.id.download_menu_clear_all: - promptClearList(); - return true; - } - return false; - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - mDownloadCursor.moveToPosition(mContextMenuPosition); - switch (item.getItemId()) { - case R.id.download_menu_open: - hideCompletedDownload(); - openCurrentDownload(); - return true; - - case R.id.download_menu_clear: - case R.id.download_menu_cancel: - getContentResolver().delete( - ContentUris.withAppendedId(Downloads.CONTENT_URI, - mDownloadCursor.getLong(mIdColumnId)), null, null); - return true; - } - return false; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - if (mDownloadCursor != null) { - AdapterView.AdapterContextMenuInfo info = - (AdapterView.AdapterContextMenuInfo) menuInfo; - mDownloadCursor.moveToPosition(info.position); - mContextMenuPosition = info.position; - menu.setHeaderTitle(mDownloadCursor.getString(mTitleColumnId)); - - MenuInflater inflater = getMenuInflater(); - int status = mDownloadCursor.getInt(mStatusColumnId); - if (Downloads.isStatusSuccess(status)) { - inflater.inflate(R.menu.downloadhistorycontextfinished, menu); - } else if (Downloads.isStatusError(status)) { - inflater.inflate(R.menu.downloadhistorycontextfailed, menu); - } else { - inflater.inflate(R.menu.downloadhistorycontextrunning, menu); - } - } - } - - /** - * This function is called to check the status of the download and if it - * has an error show an error dialog. - * @param id Row id of the download to check - * @return position of item - */ - int checkStatus(final long id) { - int position = -1; - for (mDownloadCursor.moveToFirst(); !mDownloadCursor.isAfterLast(); - mDownloadCursor.moveToNext()) { - if (id == mDownloadCursor.getLong(mIdColumnId)) { - position = mDownloadCursor.getPosition(); - break; - } - - } - if (!mDownloadCursor.isAfterLast()) { - int status = mDownloadCursor.getInt(mStatusColumnId); - if (!Downloads.isStatusError(status)) { - return position; - } - - if (status == Downloads.STATUS_FILE_ERROR) { - String title = mDownloadCursor.getString(mTitleColumnId); - if (title == null || title.length() == 0) { - title = getString(R.string.download_unknown_filename); - } - String msg = getString(R.string.download_file_error_dlg_msg, - title); - new AlertDialog.Builder(this) - .setTitle(R.string.download_file_error_dlg_title) - .setIcon(android.R.drawable.ic_popup_disk_full) - .setMessage(msg) - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.retry, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - resumeDownload(id); - } - }) - .show(); - } else { - new AlertDialog.Builder(this) - .setTitle(R.string.download_failed_generic_dlg_title) - .setIcon(R.drawable.ssl_icon) - .setMessage(BrowserDownloadAdapter.getErrorText(status)) - .setPositiveButton(R.string.ok, null) - .show(); - } - } - return position; - } - - /** - * Resume a given download - * @param id Row id of the download to resume - */ - private void resumeDownload(final long id) { - // the relevant functionality doesn't exist in the download manager - } - - /** - * Prompt the user if they would like to clear the download history - */ - private void promptClearList() { - new AlertDialog.Builder(this) - .setTitle(R.string.download_clear_dlg_title) - .setIcon(R.drawable.ssl_icon) - .setMessage(R.string.download_clear_dlg_msg) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - clearAllDownloads(); - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - /** - * Return the number of items in the list that can be canceled. - * @return count - */ - private int getCancelableCount() { - // Count the number of items that will be canceled. - int count = 0; - if (mDownloadCursor != null) { - for (mDownloadCursor.moveToFirst(); !mDownloadCursor.isAfterLast(); - mDownloadCursor.moveToNext()) { - int status = mDownloadCursor.getInt(mStatusColumnId); - if (!Downloads.isStatusCompleted(status)) { - count++; - } - } - } - - return count; - } - - /** - * Prompt the user if they would like to clear the download history - */ - private void promptCancelAll() { - int count = getCancelableCount(); - - // If there is nothing to do, just return - if (count == 0) { - return; - } - - // Don't show the dialog if there is only one download - if (count == 1) { - cancelAllDownloads(); - return; - } - String msg = - getString(R.string.download_cancel_dlg_msg, count); - new AlertDialog.Builder(this) - .setTitle(R.string.download_cancel_dlg_title) - .setIcon(R.drawable.ssl_icon) - .setMessage(msg) - .setPositiveButton(R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - cancelAllDownloads(); - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - /** - * Cancel all downloads. As canceled downloads are not - * listed, we removed them from the db. Removing a download - * record, cancels the download. - */ - private void cancelAllDownloads() { - if (mDownloadCursor.moveToFirst()) { - StringBuilder where = new StringBuilder(); - boolean firstTime = true; - while (!mDownloadCursor.isAfterLast()) { - int status = mDownloadCursor.getInt(mStatusColumnId); - if (!Downloads.isStatusCompleted(status)) { - if (firstTime) { - firstTime = false; - } else { - where.append(" OR "); - } - where.append("( "); - where.append(Downloads._ID); - where.append(" = '"); - where.append(mDownloadCursor.getLong(mIdColumnId)); - where.append("' )"); - } - mDownloadCursor.moveToNext(); - } - if (!firstTime) { - getContentResolver().delete(Downloads.CONTENT_URI, - where.toString(), null); - } - } - } - - private int getClearableCount() { - int count = 0; - if (mDownloadCursor.moveToFirst()) { - while (!mDownloadCursor.isAfterLast()) { - int status = mDownloadCursor.getInt(mStatusColumnId); - if (Downloads.isStatusCompleted(status)) { - count++; - } - mDownloadCursor.moveToNext(); - } - } - return count; - } - - /** - * Clear all stopped downloads, ie canceled (though should not be - * there), error and success download items. - */ - private void clearAllDownloads() { - if (mDownloadCursor.moveToFirst()) { - StringBuilder where = new StringBuilder(); - boolean firstTime = true; - while (!mDownloadCursor.isAfterLast()) { - int status = mDownloadCursor.getInt(mStatusColumnId); - if (Downloads.isStatusCompleted(status)) { - if (firstTime) { - firstTime = false; - } else { - where.append(" OR "); - } - where.append("( "); - where.append(Downloads._ID); - where.append(" = '"); - where.append(mDownloadCursor.getLong(mIdColumnId)); - where.append("' )"); - } - mDownloadCursor.moveToNext(); - } - if (!firstTime) { - getContentResolver().delete(Downloads.CONTENT_URI, - where.toString(), null); - } - } - } - - /** - * Open the content where the download db cursor currently is - */ - private void openCurrentDownload() { - int filenameColumnId = - mDownloadCursor.getColumnIndexOrThrow(Downloads._DATA); - String filename = mDownloadCursor.getString(filenameColumnId); - int mimetypeColumnId = - mDownloadCursor.getColumnIndexOrThrow(Downloads.MIMETYPE); - String mimetype = mDownloadCursor.getString(mimetypeColumnId); - Uri path = Uri.parse(filename); - // If there is no scheme, then it must be a file - if (path.getScheme() == null) { - path = Uri.fromFile(new File(filename)); - } - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(path, mimetype); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - try { - startActivity(intent); - } catch (ActivityNotFoundException ex) { - new AlertDialog.Builder(this) - .setTitle(R.string.download_failed_generic_dlg_title) - .setIcon(R.drawable.ssl_icon) - .setMessage(R.string.download_no_application) - .setPositiveButton(R.string.ok, null) - .show(); - } - } - - /* - * (non-Javadoc) - * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long) - */ - public void onItemClick(AdapterView parent, View view, int position, - long id) { - // Open the selected item - mDownloadCursor.moveToPosition(position); - - hideCompletedDownload(); - - int status = mDownloadCursor.getInt(mStatusColumnId); - if (Downloads.isStatusSuccess(status)) { - // Open it if it downloaded successfully - openCurrentDownload(); - } else { - // Check to see if there is an error. - checkStatus(id); - } - } - - /** - * hides the notification for the download pointed by mDownloadCursor - * if the download has completed. - */ - private void hideCompletedDownload() { - int status = mDownloadCursor.getInt(mStatusColumnId); - - int visibilityColumn = mDownloadCursor.getColumnIndexOrThrow(Downloads.VISIBILITY); - int visibility = mDownloadCursor.getInt(visibilityColumn); - - if (Downloads.isStatusCompleted(status) && - visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) { - ContentValues values = new ContentValues(); - values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE); - getContentResolver().update( - ContentUris.withAppendedId(Downloads.CONTENT_URI, - mDownloadCursor.getLong(mIdColumnId)), values, null, null); - } - } -} diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java deleted file mode 100644 index c529fe8..0000000 --- a/src/com/android/browser/BrowserHistoryPage.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.app.ExpandableListActivity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.os.Handler; -import android.os.ServiceManager; -import android.provider.Browser; -import android.text.IClipboard; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.ContextMenu.ContextMenuInfo; -import android.webkit.DateSorter; -import android.webkit.WebIconDatabase.IconListener; -import android.widget.AdapterView; -import android.widget.ExpandableListAdapter; -import android.widget.ExpandableListView; -import android.widget.ExpandableListView.ExpandableListContextMenuInfo; -import android.widget.TextView; - -import java.util.List; -import java.util.Vector; - -/** - * Activity for displaying the browser's history, divided into - * days of viewing. - */ -public class BrowserHistoryPage extends ExpandableListActivity { - private HistoryAdapter mAdapter; - private DateSorter mDateSorter; - private boolean mMaxTabsOpen; - - private final static String LOGTAG = "browser"; - - // Implementation of WebIconDatabase.IconListener - private class IconReceiver implements IconListener { - public void onReceivedIcon(String url, Bitmap icon) { - setListAdapter(mAdapter); - } - } - // Instance of IconReceiver - private final IconReceiver mIconReceiver = new IconReceiver(); - - /** - * Report back to the calling activity to load a site. - * @param url Site to load. - * @param newWindow True if the URL should be loaded in a new window - */ - private void loadUrl(String url, boolean newWindow) { - Intent intent = new Intent().setAction(url); - if (newWindow) { - Bundle b = new Bundle(); - b.putBoolean("new_window", true); - intent.putExtras(b); - } - setResultToParent(RESULT_OK, intent); - finish(); - } - - private void copy(CharSequence text) { - try { - IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard")); - if (clip != null) { - clip.setClipboardText(text); - } - } catch (android.os.RemoteException e) { - Log.e(LOGTAG, "Copy failed", e); - } - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - setTitle(R.string.browser_history); - - mDateSorter = new DateSorter(this); - - mAdapter = new HistoryAdapter(); - setListAdapter(mAdapter); - final ExpandableListView list = getExpandableListView(); - list.setOnCreateContextMenuListener(this); - LayoutInflater factory = LayoutInflater.from(this); - View v = factory.inflate(R.layout.empty_history, null); - addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.FILL_PARENT)); - list.setEmptyView(v); - list.post(new Runnable() { - public void run() { - list.expandGroup(0); - } - }); - mMaxTabsOpen = getIntent().getBooleanExtra("maxTabsOpen", false); - CombinedBookmarkHistoryActivity.getIconListenerSet(getContentResolver()) - .addListener(mIconReceiver); - - // initialize the result to canceled, so that if the user just presses - // back then it will have the correct result - setResultToParent(RESULT_CANCELED, null); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.history, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.findItem(R.id.clear_history_menu_id).setVisible(Browser.canClearHistory(this.getContentResolver())); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.clear_history_menu_id: - // FIXME: Need to clear the tab control in browserActivity - // as well - Browser.clearHistory(getContentResolver()); - mAdapter.refreshData(); - return true; - - default: - break; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - ExpandableListContextMenuInfo i = - (ExpandableListContextMenuInfo) menuInfo; - // Do not allow a context menu to come up from the group views. - if (!(i.targetView instanceof HistoryItem)) { - return; - } - - // Inflate the menu - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.historycontext, menu); - - // Setup the header - menu.setHeaderTitle(((HistoryItem)i.targetView).getUrl()); - - // Only show open in new tab if we have not maxed out available tabs - menu.findItem(R.id.new_window_context_menu_id).setVisible(!mMaxTabsOpen); - - // decide whether to show the share link option - PackageManager pm = getPackageManager(); - Intent send = new Intent(Intent.ACTION_SEND); - send.setType("text/plain"); - ResolveInfo ri = pm.resolveActivity(send, PackageManager.MATCH_DEFAULT_ONLY); - menu.findItem(R.id.share_link_context_menu_id).setVisible(ri != null); - - super.onCreateContextMenu(menu, v, menuInfo); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - ExpandableListContextMenuInfo i = - (ExpandableListContextMenuInfo) item.getMenuInfo(); - String url = ((HistoryItem)i.targetView).getUrl(); - String title = ((HistoryItem)i.targetView).getName(); - switch (item.getItemId()) { - case R.id.open_context_menu_id: - loadUrl(url, false); - return true; - case R.id.new_window_context_menu_id: - loadUrl(url, true); - return true; - case R.id.save_to_bookmarks_menu_id: - Browser.saveBookmark(this, title, url); - return true; - case R.id.share_link_context_menu_id: - Browser.sendString(this, url); - return true; - case R.id.copy_context_menu_id: - copy(url); - return true; - case R.id.delete_context_menu_id: - Browser.deleteFromHistory(getContentResolver(), url); - mAdapter.refreshData(); - return true; - default: - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onChildClick(ExpandableListView parent, View v, - int groupPosition, int childPosition, long id) { - if (v instanceof HistoryItem) { - loadUrl(((HistoryItem) v).getUrl(), false); - return true; - } - return false; - } - - // This Activity is generally a sub-Activity of CombinedHistoryActivity. In - // that situation, we need to pass our result code up to our parent. - // However, if someone calls this Activity directly, then this has no - // parent, and it needs to set it on itself. - private void setResultToParent(int resultCode, Intent data) { - Activity a = getParent() == null ? this : getParent(); - a.setResult(resultCode, data); - } - - private class ChangeObserver extends ContentObserver { - public ChangeObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - mAdapter.refreshData(); - } - } - - private class HistoryAdapter implements ExpandableListAdapter { - - // Map of items. Negative values are labels, positive values - // and zero are cursor offsets. - int mItemMap[]; - Vector<DataSetObserver> mObservers; - Cursor mCursor; - - HistoryAdapter() { - mObservers = new Vector<DataSetObserver>(); - - String whereClause = Browser.BookmarkColumns.VISITS + " > 0 "; - String orderBy = Browser.BookmarkColumns.DATE + " DESC"; - - mCursor = managedQuery( - Browser.BOOKMARKS_URI, - Browser.HISTORY_PROJECTION, - whereClause, null, orderBy); - - buildMap(); - mCursor.registerContentObserver(new ChangeObserver()); - } - - void refreshData() { - mCursor.requery(); - buildMap(); - for (DataSetObserver o : mObservers) { - o.onChanged(); - } - } - - private void buildMap() { - // The cursor is sorted by date - // The ItemMap will store the number of items in each bin. - int array[] = new int[DateSorter.DAY_COUNT]; - // Zero out the array. - for (int j = 0; j < DateSorter.DAY_COUNT; j++) { - array[j] = 0; - } - int dateIndex = -1; - if (mCursor.moveToFirst() && mCursor.getCount() > 0) { - while (!mCursor.isAfterLast()) { - long date = mCursor.getLong(Browser.HISTORY_PROJECTION_DATE_INDEX); - int index = mDateSorter.getIndex(date); - if (index > dateIndex) { - if (index == DateSorter.DAY_COUNT - 1) { - // We are already in the last bin, so it will - // include all the remaining items - array[index] = mCursor.getCount() - - mCursor.getPosition(); - break; - } - dateIndex = index; - } - array[dateIndex]++; - mCursor.moveToNext(); - } - } - mItemMap = array; - } - - public View getChildView(int groupPosition, int childPosition, boolean isLastChild, - View convertView, ViewGroup parent) { - HistoryItem item; - if (null == convertView || !(convertView instanceof HistoryItem)) { - item = new HistoryItem(BrowserHistoryPage.this); - // Add padding on the left so it will be indented from the - // arrows on the group views. - item.setPadding(item.getPaddingLeft() + 10, - item.getPaddingTop(), - item.getPaddingRight(), - item.getPaddingBottom()); - } else { - item = (HistoryItem) convertView; - } - int index = childPosition; - for (int i = 0; i < groupPosition; i++) { - index += mItemMap[i]; - } - mCursor.moveToPosition(index); - item.setName(mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX)); - String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX); - item.setUrl(url); - item.setFavicon(CombinedBookmarkHistoryActivity.getIconListenerSet( - getContentResolver()).getFavicon(url)); - item.setIsBookmark(1 == - mCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX)); - return item; - } - - public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { - TextView item; - if (null == convertView || !(convertView instanceof TextView)) { - LayoutInflater factory = - LayoutInflater.from(BrowserHistoryPage.this); - item = (TextView) - factory.inflate(R.layout.history_header, null); - } else { - item = (TextView) convertView; - } - item.setText(mDateSorter.getLabel(groupPosition)); - return item; - } - - public boolean areAllItemsEnabled() { - return true; - } - - public boolean isChildSelectable(int groupPosition, int childPosition) { - return true; - } - - public int getGroupCount() { - return DateSorter.DAY_COUNT; - } - - public int getChildrenCount(int groupPosition) { - return mItemMap[groupPosition]; - } - - public Object getGroup(int groupPosition) { - return null; - } - - public Object getChild(int groupPosition, int childPosition) { - return null; - } - - public long getGroupId(int groupPosition) { - return groupPosition; - } - - public long getChildId(int groupPosition, int childPosition) { - return (childPosition << 3) + groupPosition; - } - - public boolean hasStableIds() { - return true; - } - - public void registerDataSetObserver(DataSetObserver observer) { - mObservers.add(observer); - } - - public void unregisterDataSetObserver(DataSetObserver observer) { - mObservers.remove(observer); - } - - public void onGroupExpanded(int groupPosition) { - - } - - public void onGroupCollapsed(int groupPosition) { - - } - - public long getCombinedChildId(long groupId, long childId) { - return childId; - } - - public long getCombinedGroupId(long groupId) { - return groupId; - } - - public boolean isEmpty() { - return mCursor.getCount() == 0; - } - } -} diff --git a/src/com/android/browser/BrowserHomepagePreference.java b/src/com/android/browser/BrowserHomepagePreference.java deleted file mode 100644 index bc21143..0000000 --- a/src/com/android/browser/BrowserHomepagePreference.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.preference.EditTextPreference; -import android.text.Editable; -import android.text.TextWatcher; -import android.text.util.Regex; -import android.util.AttributeSet; - -public class BrowserHomepagePreference extends EditTextPreference implements - TextWatcher { - - public BrowserHomepagePreference(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - getEditText().addTextChangedListener(this); - } - - public BrowserHomepagePreference(Context context, AttributeSet attrs) { - super(context, attrs); - getEditText().addTextChangedListener(this); - } - - public BrowserHomepagePreference(Context context) { - super(context); - getEditText().addTextChangedListener(this); - } - - public void afterTextChanged(Editable s) { - AlertDialog dialog = (AlertDialog) getDialog(); - // This callback is called before the dialog has been fully constructed - if (dialog != null) { - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled( - Regex.WEB_URL_PATTERN.matcher(s.toString()).matches()); - } - } - - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } -} diff --git a/src/com/android/browser/BrowserPluginList.java b/src/com/android/browser/BrowserPluginList.java deleted file mode 100644 index 6689b0e..0000000 --- a/src/com/android/browser/BrowserPluginList.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.ListActivity; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.Plugin; -import android.webkit.PluginList; -import android.webkit.WebView; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import android.widget.ListView; -import android.widget.TextView; -import java.util.ArrayList; -import java.util.List; - -// Manages the list of installed (and loaded) plugins. -public class BrowserPluginList extends ListActivity { - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - // The list of plugins can change under us, as the plugins are - // loaded and unloaded in a different thread. We make a copy - // of the list here. - List loadedPlugins = WebView.getPluginList().getList(); - ArrayList localLoadedPluginList = new ArrayList(); - synchronized (loadedPlugins) { - localLoadedPluginList.addAll(loadedPlugins); - } - setListAdapter(new ArrayAdapter(this, - android.R.layout.simple_list_item_1, - localLoadedPluginList)); - setTitle(R.string.pref_plugin_installed); - // Add a text view to this ListActivity. This text view - // will be displayed when the list of plugins is empty. - TextView textView = new TextView(this); - textView.setId(android.R.id.empty); - textView.setText(R.string.pref_plugin_installed_empty_list); - addContentView(textView, new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - WebView.getPluginList().pluginClicked(this, position); - } -} diff --git a/src/com/android/browser/BrowserPreferencesPage.java b/src/com/android/browser/BrowserPreferencesPage.java deleted file mode 100644 index b23f750..0000000 --- a/src/com/android/browser/BrowserPreferencesPage.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import java.util.List; - -import android.net.Uri; -import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.webkit.WebView; -import android.webkit.Plugin; - -public class BrowserPreferencesPage extends PreferenceActivity - implements Preference.OnPreferenceChangeListener, - Preference.OnPreferenceClickListener { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Load the XML preferences file - addPreferencesFromResource(R.xml.browser_preferences); - - Preference e = findPreference(BrowserSettings.PREF_HOMEPAGE); - e.setOnPreferenceChangeListener(this); - e.setSummary(getPreferenceScreen().getSharedPreferences() - .getString(BrowserSettings.PREF_HOMEPAGE, null)); - - e = findPreference(BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS); - e.setOnPreferenceChangeListener(this); - - 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_TEXT_ENCODING); - e.setOnPreferenceChangeListener(this); - - if (BrowserSettings.getInstance().showDebugSettings()) { - addPreferencesFromResource(R.xml.debug_preferences); - } - - e = findPreference(BrowserSettings.PREF_GEARS_SETTINGS); - e.setOnPreferenceClickListener(this); - } - - @Override - protected void onPause() { - super.onPause(); - - // sync the shared preferences back to BrowserSettings - BrowserSettings.getInstance().syncSharedPreferences( - getPreferenceScreen().getSharedPreferences()); - } - - public boolean onPreferenceChange(Preference pref, Object objValue) { - if (pref.getKey().equals(BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS)) { - Boolean value = (Boolean) objValue; - if (value.booleanValue() == true) { - finish(); - } - } else if (pref.getKey().equals(BrowserSettings.PREF_HOMEPAGE)) { - String value = (String) objValue; - boolean needUpdate = value.indexOf(' ') != -1; - if (needUpdate) { - value = value.trim().replace(" ", "%20"); - } - Uri path = Uri.parse(value); - if (path.getScheme() == null) { - value = "http://" + value; - needUpdate = true; - } - // Set the summary value. - pref.setSummary(value); - if (needUpdate) { - // Update through the EditText control as it has a cached copy - // of the string and it will handle persisting the value - ((EditTextPreference) pref).setText(value); - - // as we update the value above, we need to return false - // here so that setText() is not called by EditTextPref - // with the old value. - return false; - } else { - return true; - } - } else if (pref.getKey().equals(BrowserSettings.PREF_TEXT_SIZE)) { - pref.setSummary(getVisualTextSizeName((String) objValue)); - return true; - } else if (pref.getKey().equals( - BrowserSettings.PREF_DEFAULT_TEXT_ENCODING)) { - pref.setSummary((String) objValue); - return true; - } - - return false; - } - - public boolean onPreferenceClick(Preference pref) { - if (pref.getKey().equals(BrowserSettings.PREF_GEARS_SETTINGS)) { - List<Plugin> loadedPlugins = WebView.getPluginList().getList(); - for(Plugin p : loadedPlugins) { - if (p.getName().equals("gears")) { - p.dispatchClickEvent(this); - return true; - } - } - - } - return true; - } - - private CharSequence getVisualTextSizeName(String enumName) { - CharSequence[] visualNames = - getResources().getTextArray(R.array.pref_text_size_choices); - CharSequence[] enumNames = - getResources().getTextArray(R.array.pref_text_size_values); - - // Sanity check - if (visualNames.length != enumNames.length) { - return ""; - } - - for (int i = 0; i < enumNames.length; i++) { - if (enumNames[i].equals(enumName)) { - return visualNames[i]; - } - } - - return ""; - } -} diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java deleted file mode 100644 index 0c930c6..0000000 --- a/src/com/android/browser/BrowserProvider.java +++ /dev/null @@ -1,654 +0,0 @@ -/* - * Copyright (C) 2006 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.ISearchManager; -import android.app.SearchManager; -import android.content.ComponentName; -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.UriMatcher; -import android.database.AbstractCursor; -import android.database.Cursor; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemProperties; -import android.provider.Browser; -import android.util.Log; -import android.server.search.SearchableInfo; -import android.text.util.Regex; - -public class BrowserProvider extends ContentProvider { - - private SQLiteOpenHelper mOpenHelper; - private 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[] TABLE_NAMES = new String[] { - "bookmarks", "searches" - }; - private static final String[] SUGGEST_PROJECTION = new String[] { - "_id", "url", "title", "bookmark" - }; - private static final String SUGGEST_SELECTION = - "url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?"; - private String[] SUGGEST_ARGS = new String[4]; - - // shared suggestion array index, make sure to match COLUMNS - private static final int SUGGEST_COLUMN_INTENT_ACTION_ID = 1; - private static final int SUGGEST_COLUMN_INTENT_DATA_ID = 2; - private static final int SUGGEST_COLUMN_TEXT_1_ID = 3; - private static final int SUGGEST_COLUMN_TEXT_2_ID = 4; - private static final int SUGGEST_COLUMN_ICON_1_ID = 5; - private static final int SUGGEST_COLUMN_ICON_2_ID = 6; - private static final int SUGGEST_COLUMN_QUERY_ID = 7; - - // shared suggestion columns - private static final String[] COLUMNS = new String[] { - "_id", - SearchManager.SUGGEST_COLUMN_INTENT_ACTION, - SearchManager.SUGGEST_COLUMN_INTENT_DATA, - SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_TEXT_2, - SearchManager.SUGGEST_COLUMN_ICON_1, - SearchManager.SUGGEST_COLUMN_ICON_2, - SearchManager.SUGGEST_COLUMN_QUERY}; - - private static final int MAX_SUGGESTION_SHORT_ENTRIES = 3; - private static final int MAX_SUGGESTION_LONG_ENTRIES = 6; - - // make sure that these match the index of TABLE_NAMES - private 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; - private static final int URI_MATCH_SEARCHES_ID = 11; - // - private static final int URI_MATCH_SUGGEST = 20; - - private static final UriMatcher URI_MATCHER; - - static { - URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); - URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_BOOKMARKS], - URI_MATCH_BOOKMARKS); - URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_BOOKMARKS] + "/#", - URI_MATCH_BOOKMARKS_ID); - URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_SEARCHES], - URI_MATCH_SEARCHES); - URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_SEARCHES] + "/#", - URI_MATCH_SEARCHES_ID); - URI_MATCHER.addURI("browser", SearchManager.SUGGEST_URI_PATH_QUERY, - URI_MATCH_SUGGEST); - } - - // 1 -> 2 add cache table - // 2 -> 3 update history table - // 3 -> 4 add passwords table - // 4 -> 5 add settings table - // 5 -> 6 ? - // 6 -> 7 ? - // 7 -> 8 drop proxy table - // 8 -> 9 drop settings table - // 9 -> 10 add form_urls and form_data - // 10 -> 11 add searches table - // 11 -> 12 modify cache table - // 12 -> 13 modify cache table - // 13 -> 14 correspond with Google Bookmarks schema - // 14 -> 15 move couple of tables to either browser private database or webview database - // 15 -> 17 Set it up for the SearchManager - // 17 -> 18 Added favicon in bookmarks table for Home shortcuts - // 18 -> 19 Remove labels table - private static final int DATABASE_VERSION = 19; - - public BrowserProvider() { - } - - - private static CharSequence replaceSystemPropertyInString(CharSequence srcString) { - StringBuffer sb = new StringBuffer(); - int lastCharLoc = 0; - for (int i = 0; i < srcString.length(); ++i) { - char c = srcString.charAt(i); - if (c == '{') { - sb.append(srcString.subSequence(lastCharLoc, i)); - lastCharLoc = i; - inner: - for (int j = i; j < srcString.length(); ++j) { - char k = srcString.charAt(j); - if (k == '}') { - String propertyKeyValue = srcString.subSequence(i + 1, j).toString(); - // See if the propertyKeyValue specifies a default value - int defaultOffset = propertyKeyValue.indexOf(':'); - if (defaultOffset == -1) { - sb.append(SystemProperties.get(propertyKeyValue)); - } else { - String propertyKey = propertyKeyValue.substring(0, defaultOffset); - String defaultValue = - propertyKeyValue.substring(defaultOffset + 1, - propertyKeyValue.length()); - sb.append(SystemProperties.get(propertyKey, defaultValue)); - } - lastCharLoc = j + 1; - i = j; - break inner; - } - } - } - } - if (srcString.length() - lastCharLoc > 0) { - // Put on the tail, if there is one - sb.append(srcString.subSequence(lastCharLoc, srcString.length())); - } - return sb; - } - - private static class DatabaseHelper extends SQLiteOpenHelper { - private Context mContext; - - public DatabaseHelper(Context context) { - super(context, sDatabaseName, null, DATABASE_VERSION); - mContext = context; - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE bookmarks (" + - "_id INTEGER PRIMARY KEY," + - "title TEXT," + - "url TEXT," + - "visits INTEGER," + - "date LONG," + - "created LONG," + - "description TEXT," + - "bookmark INTEGER," + - "favicon BLOB DEFAULT NULL" + - ");"); - - final CharSequence[] bookmarks = mContext.getResources() - .getTextArray(R.array.bookmarks); - int size = bookmarks.length; - try { - for (int i = 0; i < size; i = i + 2) { - CharSequence bookmarkDestination = replaceSystemPropertyInString(bookmarks[i + 1]); - db.execSQL("INSERT INTO bookmarks (title, url, visits, " + - "date, created, bookmark)" + " VALUES('" + - bookmarks[i] + "', '" + bookmarkDestination + - "', 0, 0, 0, 1);"); - } - } catch (ArrayIndexOutOfBoundsException e) { - } - - db.execSQL("CREATE TABLE searches (" + - "_id INTEGER PRIMARY KEY," + - "search TEXT," + - "date LONG" + - ");"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - Log.w(TAG, "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will destroy all old data"); - if (oldVersion == 18) { - db.execSQL("DROP TABLE IF EXISTS labels"); - } else { - db.execSQL("DROP TABLE IF EXISTS bookmarks"); - db.execSQL("DROP TABLE IF EXISTS searches"); - onCreate(db); - } - } - } - - @Override - public boolean onCreate() { - mOpenHelper = new DatabaseHelper(getContext()); - return true; - } - - /* - * Subclass AbstractCursor so we can combine multiple Cursors and add - * "Google Search". - * Here are the rules. - * 1. We only have MAX_SUGGESTION_LONG_ENTRIES in the list plus - * "Google Search"; - * 2. If bookmark/history entries are less than - * (MAX_SUGGESTION_SHORT_ENTRIES -1), we include Google suggest. - */ - private class MySuggestionCursor extends AbstractCursor { - private Cursor mHistoryCursor; - private Cursor mSuggestCursor; - private int mHistoryCount; - private int mSuggestionCount; - private boolean mBeyondCursor; - private String mString; - - public MySuggestionCursor(Cursor hc, Cursor sc, String string) { - mHistoryCursor = hc; - mSuggestCursor = sc; - mHistoryCount = hc.getCount(); - mSuggestionCount = sc != null ? sc.getCount() : 0; - if (mSuggestionCount > (MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount)) { - mSuggestionCount = MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount; - } - mString = string; - mBeyondCursor = false; - } - - @Override - public boolean onMove(int oldPosition, int newPosition) { - if (mHistoryCursor == null) { - return false; - } - if (mHistoryCount > newPosition) { - mHistoryCursor.moveToPosition(newPosition); - mBeyondCursor = false; - } else if (mHistoryCount + mSuggestionCount > newPosition) { - mSuggestCursor.moveToPosition(newPosition - mHistoryCount); - mBeyondCursor = false; - } else { - mBeyondCursor = true; - } - return true; - } - - @Override - public int getCount() { - if (mString.length() > 0) { - return mHistoryCount + mSuggestionCount + 1; - } else { - return mHistoryCount + mSuggestionCount; - } - } - - @Override - public String[] getColumnNames() { - return COLUMNS; - } - - @Override - public String getString(int columnIndex) { - if ((mPos != -1 && mHistoryCursor != null)) { - switch(columnIndex) { - case SUGGEST_COLUMN_INTENT_ACTION_ID: - if (mHistoryCount > mPos) { - return Intent.ACTION_VIEW; - } else { - return Intent.ACTION_SEARCH; - } - - case SUGGEST_COLUMN_INTENT_DATA_ID: - if (mHistoryCount > mPos) { - return mHistoryCursor.getString(1); - } else { - return null; - } - - case SUGGEST_COLUMN_TEXT_1_ID: - if (mHistoryCount > mPos) { - return mHistoryCursor.getString(1); - } else if (!mBeyondCursor) { - return mSuggestCursor.getString(1); - } else { - return mString; - } - - case SUGGEST_COLUMN_TEXT_2_ID: - if (mHistoryCount > mPos) { - return mHistoryCursor.getString(2); - } else if (!mBeyondCursor) { - return mSuggestCursor.getString(2); - } else { - return getContext().getString(R.string.search_google); - } - - case SUGGEST_COLUMN_ICON_1_ID: - if (mHistoryCount > mPos) { - if (mHistoryCursor.getInt(3) == 1) { - return new Integer( - R.drawable.ic_search_category_bookmark) - .toString(); - } else { - return new Integer( - R.drawable.ic_search_category_history) - .toString(); - } - } else { - return new Integer( - R.drawable.ic_search_category_suggest) - .toString(); - } - - case SUGGEST_COLUMN_ICON_2_ID: - return new String("0"); - - case SUGGEST_COLUMN_QUERY_ID: - if (mHistoryCount > mPos) { - return null; - } else if (!mBeyondCursor) { - return mSuggestCursor.getString(3); - } else { - return mString; - } - } - } - return null; - } - - @Override - public double getDouble(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public float getFloat(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public int getInt(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public long getLong(int column) { - if ((mPos != -1) && column == 0) { - return mPos; // use row# as the _Id - } - throw new UnsupportedOperationException(); - } - - @Override - public short getShort(int column) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isNull(int column) { - throw new UnsupportedOperationException(); - } - - // TODO Temporary change, finalize after jq's changes go in - public void deactivate() { - if (mHistoryCursor != null) { - mHistoryCursor.deactivate(); - } - if (mSuggestCursor != null) { - mSuggestCursor.deactivate(); - } - super.deactivate(); - } - - public boolean requery() { - return (mHistoryCursor != null ? mHistoryCursor.requery() : false) | - (mSuggestCursor != null ? mSuggestCursor.requery() : false); - } - - // TODO Temporary change, finalize after jq's changes go in - public void close() { - super.close(); - if (mHistoryCursor != null) { - mHistoryCursor.close(); - mHistoryCursor = null; - } - if (mSuggestCursor != null) { - mSuggestCursor.close(); - mSuggestCursor = null; - } - } - } - - @Override - public Cursor query(Uri url, String[] projectionIn, String selection, - String[] selectionArgs, String sortOrder) - throws IllegalStateException { - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - - int match = URI_MATCHER.match(url); - if (match == -1) { - throw new IllegalArgumentException("Unknown URL"); - } - - if (match == URI_MATCH_SUGGEST) { - String suggestSelection; - String [] myArgs; - if (selectionArgs[0] == null || selectionArgs[0].equals("")) { - suggestSelection = null; - myArgs = null; - } else { - String like = selectionArgs[0] + "%"; - if (selectionArgs[0].startsWith("http")) { - myArgs = new String[1]; - myArgs[0] = like; - suggestSelection = selection; - } else { - SUGGEST_ARGS[0] = "http://" + like; - SUGGEST_ARGS[1] = "http://www." + like; - SUGGEST_ARGS[2] = "https://" + like; - SUGGEST_ARGS[3] = "https://www." + like; - myArgs = SUGGEST_ARGS; - suggestSelection = SUGGEST_SELECTION; - } - } - - Cursor c = db.query(TABLE_NAMES[URI_MATCH_BOOKMARKS], - SUGGEST_PROJECTION, suggestSelection, myArgs, null, null, - ORDER_BY, - (new Integer(MAX_SUGGESTION_LONG_ENTRIES)).toString()); - - if (Regex.WEB_URL_PATTERN.matcher(selectionArgs[0]).matches()) { - return new MySuggestionCursor(c, null, ""); - } else { - // get Google suggest if there is still space in the list - if (myArgs != null && myArgs.length > 1 - && c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) { - ISearchManager sm = ISearchManager.Stub - .asInterface(ServiceManager - .getService(Context.SEARCH_SERVICE)); - SearchableInfo si = null; - try { - // use the global search to get Google suggest provider - si = sm.getSearchableInfo(new ComponentName( - getContext(), "com.android.browser"), true); - - // similar to the getSuggestions() in SearchDialog.java - StringBuilder uriStr = new StringBuilder("content://"); - uriStr.append(si.getSuggestAuthority()); - // if content path provided, insert it now - final String contentPath = si.getSuggestPath(); - if (contentPath != null) { - uriStr.append('/'); - uriStr.append(contentPath); - } - // append standard suggestion query path - uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY); - // inject query, either as selection args or inline - String[] selArgs = null; - if (si.getSuggestSelection() != null) { - selArgs = new String[] {selectionArgs[0]}; - } else { - uriStr.append('/'); - uriStr.append(Uri.encode(selectionArgs[0])); - } - - // finally, make the query - Cursor sc = getContext().getContentResolver().query( - Uri.parse(uriStr.toString()), null, - si.getSuggestSelection(), selArgs, null); - - return new MySuggestionCursor(c, sc, selectionArgs[0]); - } catch (RemoteException e) { - } - } - return new MySuggestionCursor(c, null, selectionArgs[0]); - } - } - - String[] projection = null; - if (projectionIn != null && projectionIn.length > 0) { - projection = new String[projectionIn.length + 1]; - System.arraycopy(projectionIn, 0, projection, 0, projectionIn.length); - projection[projectionIn.length] = "_id AS _id"; - } - - StringBuilder whereClause = new StringBuilder(256); - if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) { - whereClause.append("(_id = ").append(url.getPathSegments().get(1)) - .append(")"); - } - - // Tack on the user's selection, if present - if (selection != null && selection.length() > 0) { - if (whereClause.length() > 0) { - whereClause.append(" AND "); - } - - whereClause.append('('); - whereClause.append(selection); - whereClause.append(')'); - } - Cursor c = db.query(TABLE_NAMES[match % 10], projection, - whereClause.toString(), selectionArgs, null, null, sortOrder, - null); - c.setNotificationUri(getContext().getContentResolver(), url); - return c; - } - - @Override - public String getType(Uri url) { - int match = URI_MATCHER.match(url); - switch (match) { - case URI_MATCH_BOOKMARKS: - return "vnd.android.cursor.dir/bookmark"; - - case URI_MATCH_BOOKMARKS_ID: - return "vnd.android.cursor.item/bookmark"; - - case URI_MATCH_SEARCHES: - return "vnd.android.cursor.dir/searches"; - - case URI_MATCH_SEARCHES_ID: - return "vnd.android.cursor.item/searches"; - - case URI_MATCH_SUGGEST: - return SearchManager.SUGGEST_MIME_TYPE; - - default: - throw new IllegalArgumentException("Unknown URL"); - } - } - - @Override - public Uri insert(Uri url, ContentValues initialValues) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - - int match = URI_MATCHER.match(url); - Uri uri = null; - switch (match) { - case URI_MATCH_BOOKMARKS: { - // Insert into the bookmarks table - long rowID = db.insert(TABLE_NAMES[URI_MATCH_BOOKMARKS], "url", - initialValues); - if (rowID > 0) { - uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI, - rowID); - } - break; - } - - case URI_MATCH_SEARCHES: { - // Insert into the searches table - long rowID = db.insert(TABLE_NAMES[URI_MATCH_SEARCHES], "url", - initialValues); - if (rowID > 0) { - uri = ContentUris.withAppendedId(Browser.SEARCHES_URI, - rowID); - } - break; - } - - default: - throw new IllegalArgumentException("Unknown URL"); - } - - if (uri == null) { - throw new IllegalArgumentException("Unknown URL"); - } - getContext().getContentResolver().notifyChange(uri, null); - return uri; - } - - @Override - public int delete(Uri url, String where, String[] whereArgs) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - - int match = URI_MATCHER.match(url); - if (match == -1 || match == URI_MATCH_SUGGEST) { - throw new IllegalArgumentException("Unknown URL"); - } - - if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) { - StringBuilder sb = new StringBuilder(); - if (where != null && where.length() > 0) { - sb.append("( "); - sb.append(where); - sb.append(" ) AND "); - } - sb.append("_id = "); - sb.append(url.getPathSegments().get(1)); - where = sb.toString(); - } - - int count = db.delete(TABLE_NAMES[match % 10], where, whereArgs); - getContext().getContentResolver().notifyChange(url, null); - return count; - } - - @Override - public int update(Uri url, ContentValues values, String where, - String[] whereArgs) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - - int match = URI_MATCHER.match(url); - if (match == -1 || match == URI_MATCH_SUGGEST) { - throw new IllegalArgumentException("Unknown URL"); - } - - if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) { - StringBuilder sb = new StringBuilder(); - if (where != null && where.length() > 0) { - sb.append("( "); - sb.append(where); - sb.append(" ) AND "); - } - sb.append("_id = "); - sb.append(url.getPathSegments().get(1)); - where = sb.toString(); - } - - int ret = db.update(TABLE_NAMES[match % 10], values, where, whereArgs); - getContext().getContentResolver().notifyChange(url, null); - return ret; - } -} diff --git a/src/com/android/browser/BrowserSearchpagePreference.java b/src/com/android/browser/BrowserSearchpagePreference.java deleted file mode 100644 index 09e8993..0000000 --- a/src/com/android/browser/BrowserSearchpagePreference.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.preference.EditTextPreference; -import android.text.Editable; -import android.text.TextWatcher; -import android.text.util.Regex; -import android.util.AttributeSet; - -public class BrowserSearchpagePreference extends EditTextPreference implements - TextWatcher { - - public BrowserSearchpagePreference(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - getEditText().addTextChangedListener(this); - } - - public BrowserSearchpagePreference(Context context, AttributeSet attrs) { - super(context, attrs); - getEditText().addTextChangedListener(this); - } - - public BrowserSearchpagePreference(Context context) { - super(context); - getEditText().addTextChangedListener(this); - } - - public void afterTextChanged(Editable s) { - AlertDialog dialog = (AlertDialog) getDialog(); - // This callback is called before the dialog has been fully constructed - if (dialog != null) { - String string = s.toString(); - int length = string.length(); - int first = length > 0 ? string - .indexOf(BrowserActivity.QUERY_PLACE_HOLDER) : -1; - int last = length > 0 ? string - .lastIndexOf(BrowserActivity.QUERY_PLACE_HOLDER) : -1; - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled( - length == 0 || (first > 0 && first == last)); - } - } - - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - } -} diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java deleted file mode 100644 index 35b4096..0000000 --- a/src/com/android/browser/BrowserSettings.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (C) 2007 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.ContentResolver; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.SystemProperties; -import android.view.WindowManager; -import android.webkit.CacheManager; -import android.webkit.CookieManager; -import android.webkit.WebViewDatabase; -import android.webkit.WebIconDatabase; -import android.webkit.WebSettings; -import android.preference.PreferenceManager; -import android.provider.Browser; - -import java.util.HashMap; -import java.util.Observable; - -/* - * 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 BrowserSettings extends Observable { - - // Public variables for settings - // NOTE: these defaults need to be kept in sync with the XML - // until the performance of PreferenceManager.setDefaultValues() - // is improved. - private boolean loadsImagesAutomatically = true; - private boolean javaScriptEnabled = true; - private boolean pluginsEnabled = true; - private String pluginsPath; // default value set in loadFromDb(). - private boolean javaScriptCanOpenWindowsAutomatically = false; - private boolean showSecurityWarnings = true; - private boolean rememberPasswords = true; - private boolean saveFormData = true; - private boolean openInBackground = false; - private String defaultTextEncodingName; - private String homeUrl = "http://www.google.com/m?client=ms-" + - SystemProperties.get("persist.sys.com.google.clientid", "unknown"); - private boolean loginInitialized = false; - private boolean autoFitPage = true; - private boolean showDebugSettings = false; - - // 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; - // Browser only settings - private boolean doFlick = false; - - // Private preconfigured values - private static int minimumFontSize = 8; - private static int minimumLogicalFontSize = 8; - private static int defaultFontSize = 16; - private static int defaultFixedFontSize = 13; - private static WebSettings.TextSize textSize = - WebSettings.TextSize.NORMAL; - - // 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_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_GEARS_SETTINGS = "gears_settings"; - public final static String PREF_TEXT_SIZE = "text_size"; - public final static String PREF_DEFAULT_TEXT_ENCODING = - "default_text_encoding"; - - private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " + - "U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.18 (KHTML, " + - "like Gecko) Version/3.1.2 Safari/525.20.1"; - - private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " + - "CPU iPhone OS 2_2 like Mac OS X; en-us) AppleWebKit/525.18.1 " + - "(KHTML, like Gecko) Version/3.1.1 Mobile/5G77 Safari/525.20"; - - // Value to truncate strings when adding them to a TextView within - // a ListView - public final static int MAX_TEXTVIEW_LEN = 80; - - private TabControl mTabControl; - - // 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>(); - - /* - * 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; - - Observer(WebSettings w) { - mSettings = w; - } - - 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); - } - s.setUseWideViewPort(b.useWideViewPort); - s.setLoadsImagesAutomatically(b.loadsImagesAutomatically); - s.setJavaScriptEnabled(b.javaScriptEnabled); - s.setPluginsEnabled(b.pluginsEnabled); - s.setPluginsPath(b.pluginsPath); - 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.setLightTouchEnabled(b.lightTouch); - s.setSaveFormData(b.saveFormData); - s.setSavePassword(b.rememberPasswords); - - // WebView inside Browser doesn't want initial focus to be set. - s.setNeedInitialFocus(false); - // Browser supports multiple windows - s.setSupportMultipleWindows(true); - // Turn off file access - s.setAllowFileAccess(false); - } - } - - /** - * Load settings from the browser app's database. - * NOTE: Strings used for the preferences must match those specified - * in the browser_preferences.xml - * @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. - */ - public void loadFromDb(Context ctx) { - SharedPreferences p = - PreferenceManager.getDefaultSharedPreferences(ctx); - - // Set the default value for the plugins path to the application's - // local directory. - pluginsPath = ctx.getDir("plugins", 0).getPath(); - - // Load the defaults from the xml - // This call is TOO SLOW, need to manually keep the defaults - // in sync - //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences); - syncSharedPreferences(p); - } - - /* package */ void syncSharedPreferences(SharedPreferences p) { - homeUrl = - p.getString(PREF_HOMEPAGE, homeUrl); - loadsImagesAutomatically = p.getBoolean("load_images", - loadsImagesAutomatically); - javaScriptEnabled = p.getBoolean("enable_javascript", - javaScriptEnabled); - pluginsEnabled = p.getBoolean("enable_plugins", - pluginsEnabled); - pluginsPath = p.getString("plugins_path", pluginsPath); - 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); - boolean accept_cookies = p.getBoolean("accept_cookies", - CookieManager.getInstance().acceptCookie()); - CookieManager.getInstance().setAcceptCookie(accept_cookies); - openInBackground = p.getBoolean("open_in_background", openInBackground); - loginInitialized = p.getBoolean("login_initialized", loginInitialized); - textSize = WebSettings.TextSize.valueOf( - p.getString(PREF_TEXT_SIZE, textSize.name())); - autoFitPage = p.getBoolean("autofit_pages", autoFitPage); - 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); - doFlick = p.getBoolean("enable_flick", doFlick); - userAgent = Integer.parseInt(p.getString("user_agent", "0")); - mTabControl.getBrowserActivity().setBaseSearchUrl( - p.getString("search_url", "")); - } - update(); - } - - public String getPluginsPath() { - return pluginsPath; - } - - public String getHomePage() { - return homeUrl; - } - - public void setHomePage(Context context, String url) { - Editor ed = PreferenceManager. - getDefaultSharedPreferences(context).edit(); - ed.putString(PREF_HOMEPAGE, url); - ed.commit(); - homeUrl = url; - } - - public boolean isLoginInitialized() { - return loginInitialized; - } - - public void setLoginInitialized(Context context) { - loginInitialized = true; - Editor ed = PreferenceManager. - getDefaultSharedPreferences(context).edit(); - ed.putBoolean("login_initialized", loginInitialized); - ed.commit(); - } - - public WebSettings.TextSize getTextSize() { - return textSize; - } - - public boolean openInBackground() { - return openInBackground; - } - - public boolean showSecurityWarnings() { - return showSecurityWarnings; - } - - public boolean isTracing() { - return tracing; - } - - public boolean isLightTouch() { - return lightTouch; - } - - public boolean isNavDump() { - return navDump; - } - - public boolean doFlick() { - return doFlick; - } - - public boolean showDebugSettings() { - return showDebugSettings; - } - - public void toggleDebugSettings() { - showDebugSettings = !showDebugSettings; - navDump = showDebugSettings; - update(); - } - - /** - * 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; - } - - /** - * 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); - } - } - - /* - * Package level method for obtaining a single app instance of the - * BrowserSettings. - */ - /*package*/ static BrowserSettings getInstance() { - if (sSingleton == null ) { - sSingleton = new BrowserSettings(); - } - return sSingleton; - } - - /* - * Package level method for associating the BrowserSettings with TabControl - */ - /* package */void setTabControl(TabControl tabControl) { - mTabControl = tabControl; - } - - /* - * Update all the observers of the object. - */ - /*package*/ void update() { - setChanged(); - notifyObservers(); - } - - /*package*/ void clearCache(Context context) { - WebIconDatabase.getInstance().removeAllIcons(); - if (mTabControl != null) { - mTabControl.getCurrentWebView().clearCache(true); - } - } - - /*package*/ void clearCookies(Context context) { - CookieManager.getInstance().removeAllCookie(); - } - - /* package */void clearHistory(Context context) { - ContentResolver resolver = context.getContentResolver(); - Browser.clearHistory(resolver); - Browser.clearSearches(resolver); - } - - /* package */ void clearFormData(Context context) { - WebViewDatabase.getInstance(context).clearFormData(); - if (mTabControl != null) { - mTabControl.getCurrentTopWebView().clearFormData(); - } - } - - /*package*/ void clearPasswords(Context context) { - WebViewDatabase db = WebViewDatabase.getInstance(context); - db.clearUsernamePassword(); - db.clearHttpAuthUsernamePassword(); - } - - /*package*/ void resetDefaultPreferences(Context context) { - SharedPreferences p = - PreferenceManager.getDefaultSharedPreferences(context); - p.edit().clear().commit(); - PreferenceManager.setDefaultValues(context, R.xml.browser_preferences, - true); - } - - // Private constructor that does nothing. - private BrowserSettings() { - } -} diff --git a/src/com/android/browser/BrowserYesNoPreference.java b/src/com/android/browser/BrowserYesNoPreference.java deleted file mode 100644 index 65cde71..0000000 --- a/src/com/android/browser/BrowserYesNoPreference.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import com.android.internal.preference.YesNoPreference; - -import android.content.Context; -import android.util.AttributeSet; - -class BrowserYesNoPreference extends YesNoPreference { - - // This is the constructor called by the inflater - public BrowserYesNoPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - - if (positiveResult) { - setEnabled(false); - - Context context = getContext(); - if (BrowserSettings.PREF_CLEAR_CACHE.equals(getKey())) { - BrowserSettings.getInstance().clearCache(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( - getKey())) { - BrowserSettings.getInstance().resetDefaultPreferences(context); - setEnabled(true); - } - } - } -} diff --git a/src/com/android/browser/CombinedBookmarkHistoryActivity.java b/src/com/android/browser/CombinedBookmarkHistoryActivity.java deleted file mode 100644 index 963f179..0000000 --- a/src/com/android/browser/CombinedBookmarkHistoryActivity.java +++ /dev/null @@ -1,124 +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.app.TabActivity; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.provider.Browser; -import android.webkit.WebIconDatabase.IconListener; -import android.widget.TabHost; -import android.widget.TabHost.TabSpec; -import android.view.Window; - -import java.util.HashMap; -import java.util.Vector; - -public class CombinedBookmarkHistoryActivity extends TabActivity - implements TabHost.OnTabChangeListener { - /* package */ static String BOOKMARKS_TAB = "bookmark"; - /* package */ static String VISITED_TAB = "visited"; - /* package */ static String HISTORY_TAB = "history"; - /* package */ static String STARTING_TAB = "tab"; - - static class IconListenerSet implements IconListener { - // Used to store favicons as we get them from the database - // FIXME: We use a different method to get the Favicons in - // BrowserBookmarksAdapter. They should probably be unified. - private HashMap<String, Bitmap> mUrlsToIcons; - private Vector<IconListener> mListeners; - - public IconListenerSet() { - mUrlsToIcons = new HashMap<String, Bitmap>(); - mListeners = new Vector<IconListener>(); - } - public void onReceivedIcon(String url, Bitmap icon) { - mUrlsToIcons.put(url, icon); - for (IconListener listener : mListeners) { - listener.onReceivedIcon(url, icon); - } - } - public void addListener(IconListener listener) { - mListeners.add(listener); - } - public Bitmap getFavicon(String url) { - return (Bitmap) mUrlsToIcons.get(url); - } - } - private static IconListenerSet sIconListenerSet; - static IconListenerSet getIconListenerSet(ContentResolver cr) { - if (null == sIconListenerSet) { - sIconListenerSet = new IconListenerSet(); - Browser.requestAllIcons(cr, null, sIconListenerSet); - } - return sIconListenerSet; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.tabs); - TabHost tabHost = getTabHost(); - tabHost.setOnTabChangedListener(this); - - Bundle extras = getIntent().getExtras(); - Resources resources = getResources(); - - getIconListenerSet(getContentResolver()); - Intent bookmarksIntent = new Intent(this, BrowserBookmarksPage.class); - bookmarksIntent.putExtras(extras); - tabHost.addTab(tabHost.newTabSpec(BOOKMARKS_TAB) - .setIndicator(resources.getString(R.string.tab_bookmarks), - resources.getDrawable(R.drawable.browser_bookmark_tab)) - .setContent(bookmarksIntent)); - - Intent visitedIntent = new Intent(this, MostVisitedActivity.class); - visitedIntent.putExtras(extras); - tabHost.addTab(tabHost.newTabSpec(VISITED_TAB) - .setIndicator(resources.getString(R.string.tab_most_visited), - resources.getDrawable(R.drawable.browser_visited_tab)) - .setContent(visitedIntent)); - - Intent historyIntent = new Intent(this, BrowserHistoryPage.class); - historyIntent.putExtras(extras); - tabHost.addTab(tabHost.newTabSpec(HISTORY_TAB) - .setIndicator(resources.getString(R.string.tab_history), - resources.getDrawable(R.drawable. - browser_history_tab)).setContent(historyIntent)); - - String defaultTab = extras.getString(STARTING_TAB); - if (defaultTab != null) { - tabHost.setCurrentTab(2); - } - } - - // Copied from DialTacts Activity - /** {@inheritDoc} */ - public void onTabChanged(String tabId) { - Activity activity = getLocalActivityManager().getActivity(tabId); - if (activity != null) { - activity.onWindowFocusChanged(true); - } - } - - -} diff --git a/src/com/android/browser/Dots.java b/src/com/android/browser/Dots.java deleted file mode 100644 index eb8d493..0000000 --- a/src/com/android/browser/Dots.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.Gravity; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import java.util.Map; - -/** - * Displays a series of dots. The selected one is highlighted. - * No animations yet. Nothing fancy. - */ -class Dots extends LinearLayout { - - private static final int MAX_DOTS = 8; - private int mSelected = -1; - - public Dots(Context context) { - this(context, null); - } - - public Dots(Context context, AttributeSet attrs) { - super(context, attrs); - - setGravity(Gravity.CENTER); - setPadding(0, 4, 0, 4); - - LayoutParams lp = - new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - - for (int i = 0; i < MAX_DOTS; i++) { - ImageView dotView = new ImageView(mContext); - dotView.setImageResource(R.drawable.page_indicator_unselected2); - addView(dotView, lp); - } - } - - /** - * @param dotCount if less than 1 or greater than MAX_DOTS, Dots - * disappears - */ - public void setDotCount(int dotCount) { - if (dotCount > 1 && dotCount <= MAX_DOTS) { - setVisibility(VISIBLE); - for (int i = 0; i < MAX_DOTS; i++) { - getChildAt(i).setVisibility(i < dotCount? VISIBLE : GONE); - } - } else { - setVisibility(GONE); - } - } - - public void setSelected(int index) { - if (index < 0 || index >= MAX_DOTS) return; - - if (mSelected >= 0) { - // Unselect old - ((ImageView)getChildAt(mSelected)).setImageResource( - R.drawable.page_indicator_unselected2); - } - ((ImageView)getChildAt(index)).setImageResource(R.drawable.page_indicator); - mSelected = index; - } -} diff --git a/src/com/android/browser/FakeWebView.java b/src/com/android/browser/FakeWebView.java deleted file mode 100644 index 633b799..0000000 --- a/src/com/android/browser/FakeWebView.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.browser; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Picture; -import android.util.AttributeSet; -import android.view.View; -import android.webkit.WebView; -import android.widget.ImageView; - -import android.util.Log; - -/** - * This class is used by ImageAdapter to draw a representation of each tab. It - * overrides ImageView so it can be used for the new tab image as well. - */ -public class FakeWebView extends ImageView { - private TabControl.Tab mTab; - private Picture mPicture; - private boolean mUsesResource; - - private class Listener implements WebView.PictureListener { - public void onNewPicture(WebView view, Picture p) { - FakeWebView.this.mPicture = p; - FakeWebView.this.invalidate(); - } - }; - - public FakeWebView(Context context) { - this(context, null); - } - - public FakeWebView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public FakeWebView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onDraw(Canvas canvas) { - if (mUsesResource) { - super.onDraw(canvas); - } else { - // Always draw white behind the picture just in case the picture - // draws nothing. - // FIXME: We used to draw white only when the WebView was null but - // sometimes the picture was empty. So now we always draw white. It - // would be nice to know if the picture is empty so we can avoid - // drawing white. - canvas.drawColor(Color.WHITE); - if (mTab != null) { - final WebView w = mTab.getTopWindow(); - if (w != null) { - if (mPicture != null) { - canvas.save(); - float scale = getWidth() * w.getScale() / w.getWidth(); - canvas.scale(scale, scale); - canvas.translate(-w.getScrollX(), -w.getScrollY()); - canvas.drawPicture(mPicture); - canvas.restore(); - } - } - } - } - } - - @Override - public void setImageResource(int resId) { - mUsesResource = true; - mTab = null; - super.setImageResource(resId); - } - - /** - * Set a WebView for this FakeWebView to represent. - * @param v WebView whose picture and other data will be used in onDraw. - */ - public void setTab(TabControl.Tab t) { - mUsesResource = false; - mTab = t; - if (t != null && t.getWebView() != null) { - Listener l = new Listener(); - if (t.getSubWebView() != null) { - t.getSubWebView().setPictureListener(l); - } else { - t.getWebView().setPictureListener(l); - } - mPicture = mTab.getTopWindow().capturePicture(); - } - } -} diff --git a/src/com/android/browser/FetchUrlMimeType.java b/src/com/android/browser/FetchUrlMimeType.java deleted file mode 100644 index 8578643..0000000 --- a/src/com/android/browser/FetchUrlMimeType.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.ContentValues; -import android.net.Uri; -import android.net.http.AndroidHttpClient; - -import org.apache.http.HttpResponse; -import org.apache.http.Header; -import org.apache.http.client.methods.HttpHead; - -import java.io.IOException; - -import android.os.AsyncTask; -import android.provider.Downloads; -import android.webkit.MimeTypeMap; -import android.webkit.URLUtil; - -/** - * This class is used to pull down the http headers of a given URL so that - * we can analyse the mimetype and make any correction needed before we give - * the URL to the download manager. The ContentValues class holds the - * content that would be provided to the download manager, so that on - * completion of checking the mimetype, we can issue the download to - * the download manager. - * This operation is needed when the user long-clicks on a link or image and - * we don't know the mimetype. If the user just clicks on the link, we will - * do the same steps of correcting the mimetype down in - * android.os.webkit.LoadListener rather than handling it here. - * - */ -class FetchUrlMimeType extends AsyncTask<ContentValues, String, String> { - - BrowserActivity mActivity; - ContentValues mValues; - - public FetchUrlMimeType(BrowserActivity activity) { - mActivity = activity; - } - - @Override - public String doInBackground(ContentValues... values) { - mValues = values[0]; - - // Check to make sure we have a URI to download - String uri = mValues.getAsString(Downloads.URI); - if (uri == null || uri.length() == 0) { - return null; - } - - // User agent is likely to be null, though the AndroidHttpClient - // seems ok with that. - AndroidHttpClient client = AndroidHttpClient.newInstance( - mValues.getAsString(Downloads.USER_AGENT)); - HttpHead request = new HttpHead(uri); - - String cookie = mValues.getAsString(Downloads.COOKIE_DATA); - if (cookie != null && cookie.length() > 0) { - request.addHeader("Cookie", cookie); - } - - String referer = mValues.getAsString(Downloads.REFERER); - if (referer != null && referer.length() > 0) { - request.addHeader("Referer", referer); - } - - HttpResponse response; - Boolean succeeded = true; - String mimeType = null; - try { - response = client.execute(request); - // We could get a redirect here, but if we do lets let - // the download manager take care of it, and thus trust that - // the server sends the right mimetype - if (response.getStatusLine().getStatusCode() == 200) { - Header header = response.getFirstHeader("Content-Type"); - if (header != null) { - mimeType = header.getValue(); - final int semicolonIndex = mimeType.indexOf(';'); - if (semicolonIndex != -1) { - mimeType = mimeType.substring(0, semicolonIndex); - } - } - } - } catch (IllegalArgumentException ex) { - request.abort(); - } catch (IOException ex) { - request.abort(); - } finally { - client.close(); - } - - return mimeType; - } - - @Override - public void onPostExecute(String mimeType) { - if (mimeType != null) { - String url = mValues.getAsString(Downloads.URI); - if (mimeType.equalsIgnoreCase("text/plain") || - mimeType.equalsIgnoreCase("application/octet-stream")) { - String newMimeType = - MimeTypeMap.getSingleton().getMimeTypeFromExtension( - MimeTypeMap.getFileExtensionFromUrl(url)); - if (newMimeType != null) { - mValues.put(Downloads.MIMETYPE, newMimeType); - } - } - String filename = URLUtil.guessFileName(url, - null, mimeType); - mValues.put(Downloads.FILENAME_HINT, filename); - } - - // Start the download - final Uri contentUri = - mActivity.getContentResolver().insert(Downloads.CONTENT_URI, mValues); - mActivity.viewDownloads(contentUri); - } - -} diff --git a/src/com/android/browser/FindDialog.java b/src/com/android/browser/FindDialog.java deleted file mode 100644 index 44109ff..0000000 --- a/src/com/android/browser/FindDialog.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2007 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.Dialog; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.text.Editable; -import android.text.Spannable; -import android.text.TextWatcher; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.webkit.WebView; -import android.widget.EditText; -import android.widget.TextView; - -/* package */ class FindDialog extends Dialog implements TextWatcher { - private WebView mWebView; - private TextView mMatches; - private BrowserActivity mBrowserActivity; - - // Views with which the user can interact. - private View mOk; - private EditText mEditText; - private View mNextButton; - private View mPrevButton; - private View mMatchesView; - - private View.OnClickListener mFindListener = new View.OnClickListener() { - public void onClick(View v) { - findNext(); - } - }; - - private View.OnClickListener mFindCancelListener = - new View.OnClickListener() { - public void onClick(View v) { - dismiss(); - } - }; - - private View.OnClickListener mFindPreviousListener = - new View.OnClickListener() { - public void onClick(View v) { - if (mWebView == null) { - throw new AssertionError("No WebView for FindDialog::onClick"); - } - mWebView.findNext(false); - } - }; - - private void disableButtons() { - mPrevButton.setEnabled(false); - mNextButton.setEnabled(false); - mPrevButton.setFocusable(false); - mNextButton.setFocusable(false); - } - - /* package */ void setWebView(WebView webview) { - mWebView = webview; - } - - /* package */ FindDialog(BrowserActivity context) { - super(context, R.style.FindDialogTheme); - mBrowserActivity = context; - setCanceledOnTouchOutside(true); - } - - /* package */ void onConfigurationChanged(Configuration newConfig) { - // FIXME: Would like to call mWebView.findAll again, so that the - // matches would refresh, but the new picture has not yet been - // created, so it is too soon. - mEditText.getText().clear(); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Window theWindow = getWindow(); - theWindow.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL); - - setContentView(R.layout.browser_find); - - theWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - - mEditText = (EditText) findViewById(R.id.edit); - - View button = findViewById(R.id.next); - button.setOnClickListener(mFindListener); - mNextButton = button; - - button = findViewById(R.id.previous); - button.setOnClickListener(mFindPreviousListener); - mPrevButton = button; - - button = findViewById(R.id.done); - button.setOnClickListener(mFindCancelListener); - mOk = button; - - mMatches = (TextView) findViewById(R.id.matches); - mMatchesView = findViewById(R.id.matches_view); - disableButtons(); - theWindow.setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - } - - public void dismiss() { - super.dismiss(); - mBrowserActivity.closeFind(); - mWebView.clearMatches(); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - int code = event.getKeyCode(); - boolean up = event.getAction() == KeyEvent.ACTION_UP; - switch (code) { - case KeyEvent.KEYCODE_DPAD_CENTER: - case KeyEvent.KEYCODE_ENTER: - if (!mEditText.hasFocus()) { - break; - } - if (up) { - findNext(); - } - return true; - default: - break; - } - return super.dispatchKeyEvent(event); - } - - private void findNext() { - if (mWebView == null) { - throw new AssertionError("No WebView for FindDialog::findNext"); - } - mWebView.findNext(true); - } - - public void show() { - super.show(); - mEditText.requestFocus(); - mEditText.setText(""); - Spannable span = (Spannable) mEditText.getText(); - span.setSpan(this, 0, span.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - mMatches.setText(R.string.zero); - disableButtons(); - } - - // TextWatcher methods - public void beforeTextChanged(CharSequence s, - int start, - int count, - int after) { - } - - public void onTextChanged(CharSequence s, - int start, - int before, - int count) { - if (mWebView == null) { - throw new AssertionError( - "No WebView for FindDialog::onTextChanged"); - } - CharSequence find = mEditText.getText(); - if (0 == find.length()) { - disableButtons(); - mWebView.clearMatches(); - mMatchesView.setVisibility(View.INVISIBLE); - } else { - mMatchesView.setVisibility(View.VISIBLE); - int found = mWebView.findAll(find.toString()); - mMatches.setText(Integer.toString(found)); - if (found < 2) { - disableButtons(); - if (found == 0) { - mMatches.setText(R.string.zero); - } - } else { - mPrevButton.setFocusable(true); - mNextButton.setFocusable(true); - mPrevButton.setEnabled(true); - mNextButton.setEnabled(true); - } - } - } - - public void afterTextChanged(Editable s) { - } -} diff --git a/src/com/android/browser/GearsBaseDialog.java b/src/com/android/browser/GearsBaseDialog.java deleted file mode 100644 index 638ba27..0000000 --- a/src/com/android/browser/GearsBaseDialog.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Handler; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.UnderlineSpan; -import android.util.Log; -import android.view.InflateException; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import java.io.InputStream; -import java.io.IOException; -import java.lang.ClassCastException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Base dialog class for gears - */ -class GearsBaseDialog { - - private static final String TAG = "GearsNativeDialog"; - protected Handler mHandler; - protected Activity mActivity; - protected String mDialogArguments; - - private Bitmap mIcon; - private final int MAX_ICON_SIZE = 64; - protected int mChoosenIconSize; - - // Dialog closing types - public static final int CANCEL = 0; - public static final int ALWAYS_DENY = 1; - public static final int ALLOW = 2; - public static final int DENY = 3; - public static final int NEW_ICON = 4; - public static final int UPDATE_ICON = 5; - public static final int REQUEST_ICON = 6; - public static final int PAUSE_REQUEST_ICON = 7; - public static final int CLEAR_REQUEST_ICON = 8; - - protected final String LOCAL_DATA_STRING = "localData"; - protected final String LOCAL_STORAGE_STRING = "localStorage"; - protected final String LOCATION_DATA_STRING = "locationData"; - - protected String mGearsVersion = "UNDEFINED"; - protected boolean mDebug = false; - - public GearsBaseDialog(Activity activity, Handler handler, String arguments) { - mActivity = activity; - mHandler = handler; - mDialogArguments = arguments; - } - - Resources getResources() { - return mActivity.getResources(); - } - - Object getSystemService(String name) { - return mActivity.getSystemService(name); - } - - View findViewById(int id) { - return mActivity.findViewById(id); - } - - private String getString(int id) { - return mActivity.getString(id); - } - - public void setDebug(boolean debug) { - mDebug = debug; - } - - public void setGearsVersion(String version) { - mGearsVersion = version; - } - - public String closeDialog(int closingType) { - return null; - } - - /* - * Utility methods for setting up the dialogs elements - */ - - /** - * Inflate a given layout in a view (which has to be - * a ViewGroup, e.g. LinearLayout). - * This is used to share the basic dialog outline among - * the different dialog types. - */ - void inflate(int layout, int viewID) { - LayoutInflater inflater = (LayoutInflater) getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - View view = findViewById(viewID); - if (view != null) { - try { - ViewGroup viewGroup = (ViewGroup) view; - inflater.inflate(layout, viewGroup); - } catch (ClassCastException e) { - String msg = "exception, the view (" + view + ")"; - msg += " is not a ViewGroup"; - Log.e(TAG, msg, e); - } catch (InflateException e) { - Log.e(TAG, "exception while inflating the layout", e); - } - } else { - String msg = "problem, trying to inflate a non-existent view"; - msg += " (" + viewID + ")"; - Log.e(TAG, msg); - } - } - - /** - * Button setup. - * Set the button's text and its listener. If the text resource's id - * is 0, makes the button invisible. - */ - void setupButton(int buttonRscID, - int rscString, - View.OnClickListener listener, - boolean isLink, - boolean requestFocus) { - View view = findViewById(buttonRscID); - if (view == null) { - return; - } - - Button button = (Button) view; - - if (rscString == 0) { - button.setVisibility(View.GONE); - } else { - CharSequence text = getString(rscString); - button.setText(text); - button.setOnClickListener(listener); - if (isLink) { - displayAsLink(button); - } - if (requestFocus) { - button.requestFocus(); - } - } - } - - /** - * Button setup: as the above method, except that 'isLink' and - * 'requestFocus' default to false. - */ - void setupButton(int buttonRsc, int rsc, - View.OnClickListener listener) { - setupButton(buttonRsc, rsc, listener, false, false); - } - - /** - * Utility method to setup the three dialog buttons. - */ - void setupButtons(int alwaysDenyRsc, int allowRsc, int denyRsc) { - setupButton(R.id.button_alwaysdeny, alwaysDenyRsc, - new Button.OnClickListener() { - public void onClick(View v) { - mHandler.sendEmptyMessage(ALWAYS_DENY); - } - }); - - setupButton(R.id.button_allow, allowRsc, - new Button.OnClickListener() { - public void onClick(View v) { - mHandler.sendEmptyMessage(ALLOW); - } - }); - - setupButton(R.id.button_deny, denyRsc, - new Button.OnClickListener() { - public void onClick(View v) { - mHandler.sendEmptyMessage(DENY); - } - }); - } - - /** - * Display a button as an HTML link. Remove the background, set the - * text color to R.color.dialog_link and draw an underline - */ - void displayAsLink(Button button) { - if (button == null) { - return; - } - - CharSequence text = button.getText(); - button.setBackgroundDrawable(null); - int color = getResources().getColor(R.color.dialog_link); - button.setTextColor(color); - SpannableString str = new SpannableString(text); - str.setSpan(new UnderlineSpan(), 0, str.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - button.setText(str); - button.setFocusable(false); - } - - /** - * Utility method to set elements' text indicated in - * the dialogs' arguments. - */ - void setLabel(JSONObject json, String name, int rsc) { - try { - if (json.has(name)) { - String text = json.getString(name); - View view = findViewById(rsc); - if (view != null && text != null) { - TextView textView = (TextView) view; - textView.setText(text); - textView.setVisibility(View.VISIBLE); - } - } - } catch (JSONException e) { - Log.e(TAG, "json exception", e); - } - } - - /** - * Utility method to hide a view. - */ - void hideView(View v, int rsc) { - if (rsc == 0) { - return; - } - View view; - if (v == null) { - view = findViewById(rsc); - } else { - view = v.findViewById(rsc); - } - if (view != null) { - view.setVisibility(View.GONE); - } - } - - /** - * Utility method to show a view. - */ - void showView(View v, int rsc) { - if (rsc == 0) { - return; - } - View view; - if (v == null) { - view = findViewById(rsc); - } else { - view = v.findViewById(rsc); - } - if (view != null) { - view.setVisibility(View.VISIBLE); - } - } - - /** - * Utility method to set a text. - */ - void setText(View v, int rsc, CharSequence text) { - if (rsc == 0) { - return; - } - View view = v.findViewById(rsc); - if (view != null) { - TextView textView = (TextView) view; - textView.setText(text); - textView.setVisibility(View.VISIBLE); - } - } - - /** - * Utility method to set a text. - */ - void setText(View v, int rsc, int txtRsc) { - if (rsc == 0) { - return; - } - View view = v.findViewById(rsc); - if (view != null) { - TextView textView = (TextView) view; - if (txtRsc == 0) { - textView.setVisibility(View.GONE); - } else { - CharSequence text = getString(txtRsc); - textView.setText(text); - textView.setVisibility(View.VISIBLE); - } - } - } - - /** - * Utility class to download an icon in the background. - * Once done ask the UI thread to update the icon. - */ - class IconDownload implements Runnable { - private String mUrlString; - - IconDownload(String url) { - mUrlString = url; - } - - public void run() { - if (mUrlString == null) { - return; - } - try { - URL url = new URL(mUrlString); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setDoInput(true); - connection.connect(); - int length = connection.getContentLength(); - InputStream is = connection.getInputStream(); - Bitmap customIcon = BitmapFactory.decodeStream(is); - if (customIcon != null) { - mIcon = customIcon; - mHandler.sendEmptyMessage(UPDATE_ICON); - } - } catch (ClassCastException e) { - Log.e(TAG, "Class cast exception (" + mUrlString + ")", e); - } catch (MalformedURLException e) { - Log.e(TAG, "Malformed url (" + mUrlString + ") ", e); - } catch (IOException e) { - Log.e(TAG, "Exception downloading icon (" + mUrlString + ") ", e); - } - } - } - - /** - * Utility method to update the icon. - * Called on the UI thread. - */ - public void updateIcon() { - if (mIcon == null) { - return; - } - View view = findViewById(R.id.origin_icon); - if (view != null) { - ImageView imageView = (ImageView) view; - imageView.setMaxHeight(MAX_ICON_SIZE); - imageView.setMaxWidth(MAX_ICON_SIZE); - imageView.setScaleType(ImageView.ScaleType.FIT_XY); - imageView.setImageBitmap(mIcon); - imageView.setVisibility(View.VISIBLE); - } - } - - /** - * Utility method to download an icon from a url and set - * it to the GUI element R.id.origin_icon. - * It is used both in the shortcut dialog and the - * permission dialog. - * The actual download is done in the background via - * IconDownload; once the icon is downlowded the UI is updated - * via updateIcon(). - * The icon size is included in the layout with the choosen - * size, although not displayed, to limit text reflow once - * the icon is received. - */ - void downloadIcon(String url) { - if (url == null) { - return; - } - View view = findViewById(R.id.origin_icon); - if (view != null) { - view.setMinimumWidth(mChoosenIconSize); - view.setMinimumHeight(mChoosenIconSize); - view.setVisibility(View.INVISIBLE); - } - Thread thread = new Thread(new IconDownload(url)); - thread.start(); - } - - /** - * Utility method that get the dialogMessage - * and icon and ask the setupDialog(message,icon) - * method to set the values. - */ - public void setupDialog() { - TextView dialogMessage = null; - ImageView icon = null; - - View view = findViewById(R.id.dialog_message); - if (view != null) { - dialogMessage = (TextView) view; - } - - View iconView = findViewById(R.id.icon); - if (iconView != null) { - icon = (ImageView) iconView; - } - - if ((dialogMessage != null) && (icon != null)) { - setupDialog(dialogMessage, icon); - dialogMessage.setVisibility(View.VISIBLE); - } - } - - /* - * Set the message and icon of the dialog - */ - public void setupDialog(TextView message, ImageView icon) { - message.setText(R.string.unrecognized_dialog_message); - icon.setImageResource(R.drawable.ic_dialog_menu_generic); - message.setVisibility(View.VISIBLE); - } - - /** - * Setup the dialog - * By default, just display a simple message. - */ - public void setup() { - setupButtons(0, 0, R.string.default_button); - setupDialog(); - } - - /** - * Method called when the back button is pressed, - * allowing the dialog to intercept the default behaviour. - */ - public boolean handleBackButton() { - return false; - } - - /** - * Returns the resource string of the notification displayed - * after the dialog. By default, does not return one. - */ - public int notification() { - return 0; - } - - /** - * If a secondary dialog (e.g. a confirmation dialog) is created, - * GearsNativeDialog will call this method. - */ - public Dialog onCreateDialog(int id) { - // This should be redefined by subclasses as needed. - return null; - } - -} diff --git a/src/com/android/browser/GearsFilePickerDialog.java b/src/com/android/browser/GearsFilePickerDialog.java deleted file mode 100644 index 10cc03f..0000000 --- a/src/com/android/browser/GearsFilePickerDialog.java +++ /dev/null @@ -1,930 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.net.Uri; -import android.os.Environment; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.MediaStore; -import android.provider.MediaStore.Images.Media; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.TextView; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Gears FilePicker dialog - */ -class GearsFilePickerDialog extends GearsBaseDialog - implements View.OnTouchListener { - - private static final String TAG = "Gears FilePicker"; - private static Bitmap mDirectoryIcon; - private static Bitmap mDefaultIcon; - private static Bitmap mImageIcon; - private static Bitmap mBackIcon; - - private static String MULTIPLE_FILES = "MULTIPLE_FILES"; - private static String SINGLE_FILE = "SINGLE_FILE"; - - private static ImagesLoad mImagesLoader; - private static SystemThumbnails mSystemThumbnails; - private FilePickerAdapter mAdapter; - private String mSelectionMode; - private boolean mMultipleSelection; - private String mCurrentPath; - - // Disable saving thumbnails until this is refactored to fit into - // existing schemes. - private static final boolean enableSavedThumbnails = false; - - public GearsFilePickerDialog(Activity activity, - Handler handler, - String arguments) { - super (activity, handler, arguments); - mAdapter = new FilePickerAdapter(activity); - parseArguments(); - } - - public void parseArguments() { - mSelectionMode = MULTIPLE_FILES; - try { - JSONObject json = new JSONObject(mDialogArguments); - - if (json.has("mode")) { - mSelectionMode = json.getString("mode"); - } - } catch (JSONException e) { - Log.e(TAG, "exc: " + e); - } - if (mSelectionMode.equalsIgnoreCase(SINGLE_FILE)) { - mMultipleSelection = false; - } else { - mMultipleSelection = true; - } - } - - public void setup() { - inflate(R.layout.gears_dialog_filepicker, R.id.panel_content); - setupButtons(0, - R.string.filepicker_button_allow, - R.string.filepicker_button_deny); - setupDialog(); - - TextView textViewPath = (TextView) findViewById(R.id.path_name); - if (textViewPath != null) { - textViewPath.setText(R.string.filepicker_path); - } - - GridView view = (GridView) findViewById(R.id.files_list); - view.setAdapter(mAdapter); - view.setOnTouchListener(this); - - showView(null, R.id.selection); - setSelectionText(); - - mImagesLoader = new ImagesLoad(mAdapter); - mImagesLoader.setAdapterView(view); - Thread imagesLoaderThread = new Thread(mImagesLoader); - imagesLoaderThread.setPriority(Thread.MIN_PRIORITY); - imagesLoaderThread.start(); - - mSystemThumbnails = new SystemThumbnails(); - Thread systemThumbnailsThread = new Thread(mSystemThumbnails); - systemThumbnailsThread.setPriority(Thread.MIN_PRIORITY); - systemThumbnailsThread.start(); - } - - public void setSelectionText() { - Vector elements = mAdapter.selectedElements(); - if (elements == null) - return; - TextView info = (TextView) findViewById(R.id.selection); - int nbElements = elements.size(); - if (nbElements == 0) { - info.setText(R.string.filepicker_no_files_selected); - } else if (nbElements == 1) { - info.setText(R.string.filepicker_one_file_selected); - } else { - info.setText(nbElements + " " + - mActivity.getString( - R.string.filepicker_some_files_selected)); - } - } - - public void setCurrentPath(String path) { - if (path != null) { - mCurrentPath = path; - TextView textViewPath = (TextView) findViewById(R.id.current_path); - if (textViewPath != null) { - textViewPath.setText(path); - } - } - } - - public void setupDialog(TextView message, ImageView icon) { - message.setText(R.string.filepicker_message); - message.setTextSize(24); - icon.setImageResource(R.drawable.ic_dialog_menu_generic); - } - - public boolean onTouch(View v, MotionEvent event) { - mImagesLoader.pauseIconRequest(); - return false; - } - - /** - * Utility class encapsulating thumbnails information - * for a file (file image id and magic number) - */ - class SystemThumbnailInfo { - private long mID; - private long mMagicNumber; - SystemThumbnailInfo(long anID, long magicNumber) { - mID = anID; - mMagicNumber = magicNumber; - } - public long getID() { - return mID; - } - public long getMagicNumber() { - return mMagicNumber; - } - } - - /** - * Utility class to pre-fetch the thumbnails information - */ - class SystemThumbnails implements Runnable { - private Map<String, SystemThumbnailInfo> mThumbnails; - - SystemThumbnails() { - mThumbnails = Collections.synchronizedMap(new HashMap()); - } - - public void run() { - Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - Cursor cursor = mActivity.managedQuery(query, - new String[] { "_id", "mini_thumb_magic", "_data" }, - null, null, null); - - if (cursor != null) { - int count = cursor.getCount(); - for (int i = 0; i < count; i++) { - cursor.moveToPosition(i); - SystemThumbnailInfo info = new SystemThumbnailInfo(cursor.getLong(0), - cursor.getLong(1)); - mThumbnails.put(cursor.getString(2), info); - } - } - } - - public SystemThumbnailInfo getThumb(String path) { - SystemThumbnailInfo ret = mThumbnails.get(path); - if (ret == null) { - Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - Cursor cursor = mActivity.managedQuery(query, - new String[] { "_id", "mini_thumb_magic", "_data" }, - "_data = ?", new String[] { path }, null); - if (cursor != null && cursor.moveToFirst()) { - long longid = cursor.getLong(0); - long miniThumbMagic = cursor.getLong(1); - ret = new SystemThumbnailInfo(longid, miniThumbMagic); - mThumbnails.put(path, ret); - } - } - return ret; - } - } - - /** - * Utility class to load and generate thumbnails - * for image files - */ - class ImagesLoad implements Runnable { - private Vector mImagesPath; - private BaseAdapter mAdapter; - private AdapterView mAdapterView; - private Vector<FilePickerElement> mElements; - private Handler mLoaderHandler; - // We use the same value as in Camera.app's ImageManager.java - private static final int BYTES_PER_MINI_THUMB = 10000; - private final byte[] mMiniThumbData = new byte[BYTES_PER_MINI_THUMB]; - private final int MINI_THUMB_DATA_FILE_VERSION = 3; - private final int THUMBNAIL_SIZE = 128; - private Map<Uri, RandomAccessFile> mThumbFiles; - - ImagesLoad(BaseAdapter adapter) { - mAdapter = adapter; - mThumbFiles = Collections.synchronizedMap(new HashMap()); - } - - public void signalChanges() { - Message message = mHandler.obtainMessage(GearsBaseDialog.NEW_ICON, - mAdapter); - mHandler.sendMessage(message); - } - - private String getMiniThumbFileFromUri(Uri uri) { - if (uri == null) { - return null; - } - String directoryName = - Environment.getExternalStorageDirectory().toString() + - "/dcim/.thumbnails"; - String path = directoryName + "/.thumbdata" + - MINI_THUMB_DATA_FILE_VERSION + "-" + uri.hashCode(); - return path; - } - - private Bitmap getMiniThumbFor(Uri uri, long longid, long magic) { - RandomAccessFile thumbFile = mThumbFiles.get(uri); - try { - if (thumbFile == null) { - String path = getMiniThumbFileFromUri(uri); - File f = new File(path); - if (f.exists()) { - thumbFile = new RandomAccessFile(f, "rw"); - mThumbFiles.put(uri, thumbFile); - } - } - } catch (IOException ex) { - } - if (thumbFile == null) { - return null; - } - byte[] data = getMiniThumbFromFile(thumbFile, longid, - mMiniThumbData, magic); - if (data != null) { - return BitmapFactory.decodeByteArray(data, 0, data.length); - } - return null; - } - - private byte [] getMiniThumbFromFile(RandomAccessFile r, - long id, - byte [] data, - long magicCheck) { - if (r == null) - return null; - long pos = id * BYTES_PER_MINI_THUMB; - RandomAccessFile f = r; - synchronized (f) { - try { - f.seek(pos); - if (f.readByte() == 1) { - long magic = f.readLong(); - if (magic != magicCheck) { - return null; - } - int length = f.readInt(); - f.read(data, 0, length); - return data; - } else { - return null; - } - } catch (IOException ex) { - long fileLength; - try { - fileLength = f.length(); - } catch (IOException ex1) { - fileLength = -1; - } - return null; - } - } - } - - /* - * Returns a thumbnail saved by the Camera application - * We pre-cached the information (image id and magic number) - * when starting the filepicker. - */ - public Bitmap getSystemThumbnail(FilePickerElement elem) { - if (elem.askedForSystemThumbnail() == false) { - elem.setAskedForSystemThumbnail(true); - String path = elem.getPath(); - SystemThumbnailInfo thumbInfo = mSystemThumbnails.getThumb(path); - if (thumbInfo != null) { - Uri query = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - Bitmap bmp = getMiniThumbFor(query, thumbInfo.getID(), - thumbInfo.getMagicNumber()); - if (bmp != null) { - return bmp; - } - } - } - return null; - } - - /* - * Generate a thumbnail for a given element - */ - public Bitmap generateImage(FilePickerElement elem) { - String path = elem.getPath(); - Bitmap finalImage = null; - try { - - // First we try to get the thumbnail from the system - // (created by the Camera application) - - finalImage = getSystemThumbnail(elem); - if (finalImage != null) { - return finalImage; - } - - // No thumbnail was found, so we have to create one - // - // First we get the image information and - // determine the sampleSize - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(path, options); - - int width = options.outWidth; - int height = options.outHeight; - int sampleSize = 1; - if (width > THUMBNAIL_SIZE || height > THUMBNAIL_SIZE) { - sampleSize = 2; - while ((width / sampleSize > 2*THUMBNAIL_SIZE) - || (height / sampleSize > 2*THUMBNAIL_SIZE)) { - sampleSize += 2; - } - } - options.inJustDecodeBounds = false; - options.inSampleSize = sampleSize; - Bitmap originalImage = BitmapFactory.decodeFile(path, options); - if (originalImage == null) { - return null; - } - - // Let's rescale the image to a THUMBNAIL_SIZE - - width = originalImage.getWidth(); - height = originalImage.getHeight(); - - if (width > height) { - width = (int) (width * (THUMBNAIL_SIZE / (double) height)); - height = THUMBNAIL_SIZE; - } else { - height = (int) (height * (THUMBNAIL_SIZE / (double) width)); - width = THUMBNAIL_SIZE; - } - originalImage = Bitmap.createScaledBitmap(originalImage, - width, height, true); - - // We can now crop the image to a THUMBNAIL_SIZE rectangle - - width = originalImage.getWidth(); - height = originalImage.getHeight(); - int d = 0; - if (width > height) { - d = (width - height) / 2; - finalImage = Bitmap.createBitmap(originalImage, d, 0, - THUMBNAIL_SIZE, THUMBNAIL_SIZE); - } else { - d = (height - width) / 2; - finalImage = Bitmap.createBitmap(originalImage, 0, d, - THUMBNAIL_SIZE, THUMBNAIL_SIZE); - } - - originalImage.recycle(); - } catch (java.lang.OutOfMemoryError e) { - Log.e(TAG, "Intercepted OOM ", e); - } - return finalImage; - } - - public void pauseIconRequest() { - Message message = Message.obtain(mLoaderHandler, - GearsBaseDialog.PAUSE_REQUEST_ICON); - mLoaderHandler.sendMessageAtFrontOfQueue(message); - } - - public void clearIconRequests() { - Message message = Message.obtain(mLoaderHandler, - GearsBaseDialog.CLEAR_REQUEST_ICON); - mLoaderHandler.sendMessageAtFrontOfQueue(message); - } - - public void postIconRequest(FilePickerElement item, - int position, - boolean front) { - if (item == null) { - return; - } - if (item.isImage() && (item.getThumbnail() == null)) { - Message message = mLoaderHandler.obtainMessage( - GearsBaseDialog.REQUEST_ICON, position, 0, item); - if (front) { - mLoaderHandler.sendMessageAtFrontOfQueue(message); - } else { - mLoaderHandler.sendMessage(message); - } - } - } - - public boolean generateIcon(FilePickerElement elem) { - if (elem.isImage()) { - if (elem.getThumbnail() == null) { - Bitmap image = generateImage(elem); - if (image != null) { - elem.setThumbnail(image); - return true; - } - } - } - return false; - } - - public void setAdapterView(AdapterView view) { - mAdapterView = view; - } - - public void run() { - Looper.prepare(); - mLoaderHandler = new Handler() { - public void handleMessage(Message msg) { - if (msg.what == GearsBaseDialog.CLEAR_REQUEST_ICON) { - mLoaderHandler.removeMessages( - GearsBaseDialog.PAUSE_REQUEST_ICON); - mLoaderHandler.removeMessages( - GearsBaseDialog.REQUEST_ICON); - } else if (msg.what == GearsBaseDialog.PAUSE_REQUEST_ICON) { - try { - // We are busy (likely) scrolling the view, - // so we just pause the loading. - Thread.sleep(1000); - mLoaderHandler.removeMessages( - GearsBaseDialog.PAUSE_REQUEST_ICON); - } catch (InterruptedException e) { - Log.e(TAG, "InterruptedException ", e); - } - } else if (msg.what == GearsBaseDialog.REQUEST_ICON) { - FilePickerElement elem = (FilePickerElement) msg.obj; - if (generateIcon(elem)) { - signalChanges(); - } - try { - Thread.sleep(50); - } catch (InterruptedException e) { - Log.e(TAG, "InterruptedException ", e); - } - } - } - }; - Looper.loop(); - } - } - - /** - * Utility class representing an element displayed in the - * file picker, associated with an icon and/or thumbnail - */ - class FilePickerElement { - private File mPath; - private String mName; - private Bitmap mIcon; - private boolean mIsSelected; - private Vector mChildren; - private FilePickerElement mParent; - private boolean mIsParent; - private BaseAdapter mAdapter; - private String mExtension; - private Bitmap mThumbnail; - private boolean mIsImage; - private boolean mAskedForSystemThumbnail; - - public FilePickerElement(String name, BaseAdapter adapter) { - this(name, adapter, null); - } - - public FilePickerElement(String path, String name, BaseAdapter adapter) { - this(path, name, adapter, null); - } - - public FilePickerElement(String name, - BaseAdapter adapter, - FilePickerElement parent) { - mName = name; - mAdapter = adapter; - mParent = parent; - mIsSelected = false; - mChildren = null; - mAskedForSystemThumbnail = false; - } - - public FilePickerElement(String path, - String name, - BaseAdapter adapter, - FilePickerElement parent) { - mPath = new File(path); - mName = name; - mIsSelected = false; - mChildren = null; - mParent = parent; - mAdapter = adapter; - mExtension = null; - mAskedForSystemThumbnail = false; - - setIcons(); - } - - public void setAskedForSystemThumbnail(boolean value) { - mAskedForSystemThumbnail = value; - } - - public boolean askedForSystemThumbnail() { - return mAskedForSystemThumbnail; - } - - public void setIcons() { - if (mPath.isDirectory()) { - if (mDirectoryIcon == null) { - mDirectoryIcon = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_folder); - } - mIcon = mDirectoryIcon; - - } else { - if (isImage()) { - if (mImageIcon == null) { - mImageIcon = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_file_image); - } - mIcon = mImageIcon; - } else if (isAudio()) { - mIcon = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_file_audio); - } else if (isVideo()) { - mIcon = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_file_video); - } else { - if (mDefaultIcon == null) { - mDefaultIcon = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_file_unknown); - } - mIcon = mDefaultIcon; - } - } - if (mBackIcon == null) { - mBackIcon = BitmapFactory.decodeResource(getResources(), - com.android.internal.R.drawable.ic_menu_back); - } - } - - public boolean isImage() { - if (mIsImage) return mIsImage; - String extension = getExtension(); - if (extension != null) { - if (extension.equalsIgnoreCase("jpg") || - extension.equalsIgnoreCase("jpeg") || - extension.equalsIgnoreCase("png") || - extension.equalsIgnoreCase("gif")) { - mIsImage = true; - return true; - } - } - return false; - } - - public boolean isAudio() { - String extension = getExtension(); - if (extension != null) { - if (extension.equalsIgnoreCase("mp3") || - extension.equalsIgnoreCase("wav") || - extension.equalsIgnoreCase("aac")) { - return true; - } - } - return false; - } - - public boolean isVideo() { - String extension = getExtension(); - if (extension != null) { - if (extension.equalsIgnoreCase("mpg") || - extension.equalsIgnoreCase("mpeg") || - extension.equalsIgnoreCase("mpe") || - extension.equalsIgnoreCase("divx") || - extension.equalsIgnoreCase("3gpp") || - extension.equalsIgnoreCase("avi")) { - return true; - } - } - return false; - } - - public void setParent(boolean isParent) { - mIsParent = isParent; - } - - public boolean isDirectory() { - return mPath.isDirectory(); - } - - public String getExtension() { - if (isDirectory()) { - return null; - } - if (mExtension == null) { - String path = getPath(); - int index = path.lastIndexOf("."); - if ((index != -1) && (index != path.length() - 1)){ - // if we find a dot that is not the last character - mExtension = path.substring(index+1); - return mExtension; - } - } - return mExtension; - } - - public void refresh() { - mChildren = null; - Vector children = getChildren(); - mImagesLoader.clearIconRequests(); - } - - public Vector getChildren() { - if (isDirectory()) { - if (mChildren == null) { - mChildren = new Vector(); - File[] files = mPath.listFiles(); - if (mParent != null) { - mChildren.add(mParent); - mParent.setParent(true); - } - for (int i = 0; i < files.length; i++) { - String name = files[i].getName(); - String fpath = files[i].getPath(); - if (!name.startsWith(".")) { // hide dotfiles - FilePickerElement elem = new FilePickerElement(fpath, name, - mAdapter, this); - elem.setParent(false); - mChildren.add(elem); - } - } - } - } - return mChildren; - } - - public FilePickerElement getChild(int position) { - Vector children = getChildren(); - if (children != null) { - FilePickerElement elem = (FilePickerElement) children.get(position); - return elem; - } - return null; - } - - /* - * Depending on the type, we return either - * the icon (mIcon) or the back icon (mBackIcon). - * If we can load a system thumbnail we do this - * synchronously and return it, else we ask the - * mImagesLoader to generate a thumbnail for us. - */ - public Bitmap getIcon(int position) { - if (mIsParent) { - return mBackIcon; - } - if (isImage()) { - if (mThumbnail != null) { - return mThumbnail; - } else { - Bitmap image = mImagesLoader.getSystemThumbnail(this); - if (image != null) { - mThumbnail = image; - return mThumbnail; - } - mImagesLoader.postIconRequest(this, position, true); - } - } - return mIcon; - } - - public Bitmap getThumbnail() { - return mThumbnail; - } - - public void setThumbnail(Bitmap icon) { - mThumbnail = icon; - } - - public String getName() { - return mName; - } - - public String getPath() { - return mPath.getPath(); - } - - public void toggleSelection() { - mIsSelected = !mIsSelected; - } - - public boolean isSelected() { - return mIsSelected; - } - - } - - /** - * Adapter for the GridView - */ - class FilePickerAdapter extends BaseAdapter { - private Context mContext; - private Map mImagesMap; - private Map mImagesSelected; - - private Vector mImages; - private Vector<FilePickerElement> mFiles; - - private FilePickerElement mRootElement; - private FilePickerElement mCurrentElement; - - public FilePickerAdapter(Context context) { - mContext = context; - mImages = new Vector(); - mFiles = new Vector(); - - mImagesMap = Collections.synchronizedMap(new HashMap()); - mImagesSelected = new HashMap(); - - String startingPath = Environment.getExternalStorageDirectory().getPath(); - mRootElement = new FilePickerElement(startingPath, "SD Card", this); - mCurrentElement = mRootElement; - } - - public void addImage(String path) { - mImages.add(path); - Bitmap image = BitmapFactory.decodeResource( - getResources(), R.drawable.gears_file_unknown); - mImagesMap.put(path, image); - mImagesSelected.put(path, Boolean.FALSE); - } - - public int getCount() { - Vector elems = mCurrentElement.getChildren(); - setCurrentPath(mCurrentElement.getPath()); - return elems.size(); - } - - public Object getItem(int position) { - return position; - } - - public long getItemId(int position) { - return position; - } - - public Vector selectedElements() { - if (mCurrentElement == null) { - return null; - } - Vector children = mCurrentElement.getChildren(); - Vector ret = new Vector(); - for (int i = 0; i < children.size(); i++) { - FilePickerElement elem = (FilePickerElement) children.get(i); - if (elem.isSelected()) { - ret.add(elem); - } - } - return ret; - } - - public View getView(int position, View convertView, ViewGroup parent) { - View cell = convertView; - if (cell == null) { - LayoutInflater inflater = (LayoutInflater) getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - cell = inflater.inflate(R.layout.gears_dialog_filepicker_cell, null); - } - ImageView imageView = (ImageView) cell.findViewById(R.id.icon); - TextView textView = (TextView) cell.findViewById(R.id.name); - FilePickerElement elem = mCurrentElement.getChild(position); - if (elem == null) { - String message = "Could not get elem " + position; - message += " for " + mCurrentElement.getPath(); - Log.e(TAG, message); - return null; - } - String path = elem.getPath(); - textView.setText(elem.getName()); - - View.OnClickListener listener = new View.OnClickListener() { - public void onClick(View view) { - int pos = (Integer) view.getTag(); - FilePickerElement elem = mCurrentElement.getChild(pos); - if (elem.isDirectory()) { - mCurrentElement = elem; - mCurrentElement.refresh(); - } else { - if (mMultipleSelection) { - elem.toggleSelection(); - } else { - Vector elems = selectedElements(); - if (elems != null) { - if (elems.size() == 0) { - elem.toggleSelection(); - } else if ((elems.size() == 1) - && elem.isSelected()) { - elem.toggleSelection(); - } - } - } - } - setSelectionText(); - notifyDataSetChanged(); - } - }; - cell.setLayoutParams(new GridView.LayoutParams(96, 96)); - cell.setOnClickListener(listener); - cell.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - int color = getResources().getColor(R.color.icon_selection); - v.setBackgroundColor(color); - } else { - v.setBackgroundColor(android.R.color.background_dark); - } - return false; - } - }); - - cell.setTag(position); - - if (elem.isSelected()) { - int color = getResources().getColor(R.color.icon_selection); - cell.setBackgroundColor(color); - } else { - cell.setBackgroundColor(android.R.color.background_dark); - } - Bitmap bmp = elem.getIcon(position); - if (bmp != null) { - imageView.setImageBitmap(bmp); - } - - return cell; - } - } - - private String selectedFiles() { - Vector selection = mAdapter.selectedElements(); - JSONArray jsonSelection = new JSONArray(); - if (selection != null) { - for (int i = 0; i < selection.size(); i++) { - FilePickerElement elem = (FilePickerElement) selection.get(i); - jsonSelection.put(elem.getPath()); - } - } - return jsonSelection.toString(); - } - - public String closeDialog(int closingType) { - return selectedFiles(); - } -} diff --git a/src/com/android/browser/GearsNativeDialog.java b/src/com/android/browser/GearsNativeDialog.java deleted file mode 100644 index c72ad8e..0000000 --- a/src/com/android/browser/GearsNativeDialog.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.util.Config; -import android.util.Log; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.Window; -import android.widget.BaseAdapter; -import android.widget.Toast; - -import android.webkit.gears.NativeDialog; - -import com.android.browser.GearsBaseDialog; -import com.android.browser.GearsPermissionsDialog; -import com.android.browser.GearsSettingsDialog; -import com.android.browser.GearsShortcutDialog; -import com.android.browser.GearsFilePickerDialog; - -/** - * Native dialog Activity used by gears - * TODO: rename in GearsNativeDialogActivity - * @hide - */ -public class GearsNativeDialog extends Activity { - - private static final String TAG = "GearsNativeDialog"; - - private String mDialogArguments; - - private String mGearsVersion = null; - - private boolean mDebug = false; - - private int mDialogType; - private final int SETTINGS_DIALOG = 1; - private final int PERMISSION_DIALOG = 2; - private final int SHORTCUT_DIALOG = 3; - private final int LOCATION_DIALOG = 4; - private final int FILEPICKER_DIALOG = 5; - - private final String VERSION_STRING = "version"; - private final String SETTINGS_DIALOG_STRING = "settings_dialog"; - private final String PERMISSION_DIALOG_STRING = "permissions_dialog"; - private final String SHORTCUT_DIALOG_STRING = "shortcuts_dialog"; - private final String LOCATION_DIALOG_STRING = "locations_dialog"; - private final String FILEPICKER_DIALOG_STRING = "filepicker_dialog"; - - private boolean mDialogDismissed = false; - - GearsBaseDialog dialog; - - // Handler for callbacks to the UI thread - final Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - if (msg.what == GearsBaseDialog.NEW_ICON) { - BaseAdapter adapter = (BaseAdapter) msg.obj; - adapter.notifyDataSetChanged(); - } else if (msg.what == GearsBaseDialog.UPDATE_ICON) { - dialog.updateIcon(); - } else if (msg.what == GearsBaseDialog.ALWAYS_DENY) { - closeDialog(GearsBaseDialog.ALWAYS_DENY); - } else if (msg.what == GearsBaseDialog.ALLOW) { - closeDialog(GearsBaseDialog.ALLOW); - } else if (msg.what == GearsBaseDialog.DENY) { - closeDialog(GearsBaseDialog.DENY); - } - super.handleMessage(msg); - } - }; - - @Override - public void onCreate(Bundle icicle) { - getArguments(); - if (mDialogType == SETTINGS_DIALOG) { - setTheme(android.R.style.Theme); - } - super.onCreate(icicle); - if (mDialogType != SETTINGS_DIALOG) { - requestWindowFeature(Window.FEATURE_NO_TITLE); - setContentView(R.layout.gears_dialog); - } - - switch (mDialogType) { - case SETTINGS_DIALOG: - dialog = new GearsSettingsDialog(this, mHandler, mDialogArguments); - dialog.setGearsVersion(mGearsVersion); - break; - case PERMISSION_DIALOG: - dialog = new GearsPermissionsDialog(this, mHandler, mDialogArguments); - break; - case SHORTCUT_DIALOG: - dialog = new GearsShortcutDialog(this, mHandler, mDialogArguments); - break; - case LOCATION_DIALOG: - dialog = new GearsPermissionsDialog(this, mHandler, mDialogArguments); - break; - case FILEPICKER_DIALOG: - dialog = new GearsFilePickerDialog(this, mHandler, mDialogArguments); - break; - default: - dialog = new GearsBaseDialog(this, mHandler, mDialogArguments); - } - dialog.setDebug(mDebug); - dialog.setup(); - } - - /** - * Get the arguments for the dialog - * - * The dialog needs a json string as an argument, as - * well as a dialogType. In debug mode the arguments - * are mocked. - */ - private void getArguments() { - if (mDebug) { - mDialogType = FILEPICKER_DIALOG +1; - mockArguments(); - - return; - } - - Intent intent = getIntent(); - mDialogArguments = intent.getStringExtra("dialogArguments"); - String dialogTypeString = intent.getStringExtra("dialogType"); - if (dialogTypeString == null) { - return; - } - - if (Config.LOGV) { - Log.v(TAG, "dialogtype: " + dialogTypeString); - } - - if (dialogTypeString.equalsIgnoreCase(SETTINGS_DIALOG_STRING)) { - mDialogType = SETTINGS_DIALOG; - mGearsVersion = intent.getStringExtra(VERSION_STRING); - } else if (dialogTypeString.equalsIgnoreCase(PERMISSION_DIALOG_STRING)) { - mDialogType = PERMISSION_DIALOG; - } else if (dialogTypeString.equalsIgnoreCase(SHORTCUT_DIALOG_STRING)) { - mDialogType = SHORTCUT_DIALOG; - } else if (dialogTypeString.equalsIgnoreCase(LOCATION_DIALOG_STRING)) { - mDialogType = LOCATION_DIALOG; - } else if (dialogTypeString.equalsIgnoreCase(FILEPICKER_DIALOG_STRING)) { - mDialogType = FILEPICKER_DIALOG; - } - } - - /** - * Utility method for debugging the dialog. - * - * Set mock arguments. - */ - private void mockArguments() { - String argumentsShortcuts = "{ locale: \"en-US\"," - + "name: \"My Application\", link: \"http://www.google.com/\"," - + "description: \"This application does things does things!\"," - + "icon16x16: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/16.png\"," - + "icon32x32: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/32.png\"," - + "icon48x48: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/48.png\"," - + "icon128x128: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/128.png\"}"; - - String argumentsPermissions = "{ locale: \"en-US\", " - + "origin: \"http://www.google.com\", dialogType: \"localData\"," - + "customIcon: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/32.png\"," - + "customName: \"My Application\"," - + "customMessage: \"Press the button to enable my " - + "application to run offline!\" };"; - - String argumentsPermissions2 = "{ locale: \"en-US\", " - + "origin: \"http://www.google.com\", dialogType: \"localData\" };"; - - String argumentsLocation = "{ locale: \"en-US\", " - + "origin: \"http://www.google.com\", dialogType: \"locationData\"," - + "customIcon: \"http://google-gears.googlecode.com/" - + "svn/trunk/gears/test/manual/shortcuts/32.png\"," - + "customName: \"My Application\"," - + "customMessage: \"Press the button to enable my " - + "application to run offline!\" };"; - - String argumentsSettings = "{ locale: \"en-US\", permissions: [ { " - + "name: \"http://www.google.com\", " - + "localStorage: { permissionState: 0 }, " - + "locationData: { permissionState: 1 } }, " - + "{ name: \"http://www.aaronboodman.com\", " - + "localStorage: { permissionState: 1 }, " - + "locationData: { permissionState: 2 } }, " - + "{ name: \"http://www.evil.org\", " - + "localStorage: { permissionState: 2 }, " - + "locationData: { permissionState: 2 } } ] }"; - - String argumentsFilePicker = "{ \"cameraMode\" : \"OFF\", \"filters\"" - + ": [ \"text/html\", \".txt\" ], \"mode\" : \"MULTIPLE_FILES\" }\""; - - String argumentsFilePicker2 = "{ \"cameraMode\" : \"OFF\", \"filters\"" - + ": [ \"text/html\", \".txt\" ], \"mode\" : \"SINGLE_FILE\" }\""; - - switch (mDialogType) { - case SHORTCUT_DIALOG: - mDialogArguments = argumentsShortcuts; - break; - case PERMISSION_DIALOG: - mDialogArguments = argumentsPermissions; - break; - case LOCATION_DIALOG: - mDialogArguments = argumentsLocation; - break; - case SETTINGS_DIALOG: - mDialogArguments = argumentsSettings; - break; - case FILEPICKER_DIALOG: - mDialogArguments = argumentsFilePicker2; - } - } - - /** - * Close the dialog and set the return string value. - */ - private void closeDialog(int closingType) { - String ret = dialog.closeDialog(closingType); - - if (mDebug) { - Log.v(TAG, "closeDialog ret value: " + ret); - } - - NativeDialog.closeDialog(ret); - notifyEndOfDialog(); - finish(); - - // If the dialog sets a notification, we display it. - int notification = dialog.notification(); - if (notification != 0) { - Toast toast = Toast.makeText(this, notification, Toast.LENGTH_LONG); - toast.setGravity(Gravity.BOTTOM, 0, 0); - toast.show(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - // In case we reach this point without - // notifying NativeDialog, we do it now. - if (!mDialogDismissed) { - notifyEndOfDialog(); - } - } - - @Override - public void onPause(){ - super.onPause(); - if (!mDialogDismissed) { - closeDialog(GearsBaseDialog.CANCEL); - } - } - - /** - * Signal to NativeDialog that we are done. - */ - private void notifyEndOfDialog() { - NativeDialog.signalFinishedDialog(); - mDialogDismissed = true; - } - - /** - * Intercepts the back key to immediately notify - * NativeDialog that we are done. - */ - public boolean dispatchKeyEvent(KeyEvent event) { - if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK) - && (event.getAction() == KeyEvent.ACTION_DOWN)) { - if (!dialog.handleBackButton()) { - // if the dialog doesn't do anything with the back button - closeDialog(GearsBaseDialog.CANCEL); - } - return true; // event consumed - } - return super.dispatchKeyEvent(event); - } - - /** - * If the dialog call showDialog() on ourself, we let - * it handle the creation of this secondary dialog. - * It is used in GearsSettingsDialog, to create the confirmation - * dialog when the user click on "Remove this site from Gears" - */ - @Override - protected Dialog onCreateDialog(int id) { - return dialog.onCreateDialog(id); - } - -} diff --git a/src/com/android/browser/GearsPermissions.java b/src/com/android/browser/GearsPermissions.java deleted file mode 100644 index e48e045..0000000 --- a/src/com/android/browser/GearsPermissions.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.util.Log; - -import java.util.HashMap; -import java.util.Iterator; - -/** - * The permission mechanism works the following way: - * - * PermissionType allows to define a type of permission - * (e.g. localStorage/locationData), storing a name and a set of - * resource ids corresponding to the GUI resources. - * - * Permission defines an actual permission instance, with a type and a value. - * - * OriginPermissions holds an origin with a set of Permission objects - */ -class GearsPermissions { - - private static final String TAG = "GearsPermissions"; - - /** - * Defines a type of permission - * - * Store the permission's name (used in the json result) - * Graphically, each permission is a label followed by two radio buttons. - * We store the resources ids here. - */ - public static class PermissionType { - public static final int PERMISSION_NOT_SET = 0; - public static final int PERMISSION_ALLOWED = 1; - public static final int PERMISSION_DENIED = 2; - - String mName; - int mTitleRsc; - int mSubtitleOnRsc; - int mSubtitleOffRsc; - - PermissionType(String name) { - mName = name; - } - - public void setResources(int titleRsc, - int subtitleOnRsc, int subtitleOffRsc) { - mTitleRsc = titleRsc; - mSubtitleOnRsc = subtitleOnRsc; - mSubtitleOffRsc = subtitleOffRsc; - } - - public String getName() { - return mName; - } - - public int getTitleRsc() { - return mTitleRsc; - } - - public int getSubtitleOnRsc() { - return mSubtitleOnRsc; - } - - public int getSubtitleOffRsc() { - return mSubtitleOffRsc; - } - - } - - /** - * Simple class to store an instance of a permission - * - * i.e. a permission type and a value - * Value can be either PERMISSION_NOT_SET, - * PERMISSION_ALLOWED or PERMISSION_DENIED - * (defined in PermissionType). - */ - public static class Permission { - PermissionType mType; - int mValue; - - Permission(PermissionType type, int value) { - mType = type; - mValue = value; - } - - Permission(PermissionType type) { - mType = type; - mValue = 0; - } - - public PermissionType getType() { - return mType; - } - - public void setValue(int value) { - mValue = value; - } - - public int getValue() { - return mValue; - } - } - - /** - * Interface used by the GearsNativeDialog implementation - * to listen to changes in the permissions. - */ - public interface PermissionsChangesListener { - public boolean setPermission(PermissionType type, int perm); - } - - /** - * Holds the model for an origin -- each origin has a set of - * permissions. - */ - public static class OriginPermissions { - HashMap<PermissionType, Permission> mPermissions; - String mOrigin; - public static PermissionsChangesListener mListener; - - public static void setListener(PermissionsChangesListener listener) { - mListener = listener; - } - - OriginPermissions(String anOrigin) { - mOrigin = anOrigin; - mPermissions = new HashMap<PermissionType, Permission>(); - } - - OriginPermissions(OriginPermissions perms) { - mOrigin = perms.getOrigin(); - mPermissions = new HashMap<PermissionType, Permission>(); - HashMap<PermissionType, Permission> permissions = perms.getPermissions(); - Iterator<PermissionType> iterator = permissions.keySet().iterator(); - while (iterator.hasNext()) { - Permission permission = permissions.get(iterator.next()); - int value = permission.getValue(); - setPermission(permission.getType(), value); - } - } - - public String getOrigin() { - return mOrigin; - } - - public HashMap<PermissionType, Permission> getPermissions() { - return mPermissions; - } - - public int getPermission(PermissionType type) { - return mPermissions.get(type).getValue(); - } - - public void setPermission(PermissionType type, int perm) { - if (mPermissions.get(type) == null) { - Permission permission = new Permission(type, perm); - mPermissions.put(type, permission); - return; - } - - if (mListener != null) { - mListener.setPermission(type, perm); - } - - mPermissions.get(type).setValue(perm); - } - - public void print() { - Log.v(TAG, "Permissions for " + mOrigin); - Iterator<PermissionType> iterator = mPermissions.keySet().iterator(); - while (iterator.hasNext()) { - Permission permission = mPermissions.get(iterator.next()); - String name = permission.getType().getName(); - int value = permission.getValue(); - Log.v(TAG, " " + name + ": " + value); - } - } - } - -} diff --git a/src/com/android/browser/GearsPermissionsDialog.java b/src/com/android/browser/GearsPermissionsDialog.java deleted file mode 100644 index dbec363..0000000 --- a/src/com/android/browser/GearsPermissionsDialog.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.os.Handler; -import android.util.Log; -import android.view.Gravity; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Gears permission dialog - */ -class GearsPermissionsDialog extends GearsBaseDialog { - - private static final String TAG = "GearsPermissionsDialog"; - - private String mDialogType; - private int mNotification = 0; - - public GearsPermissionsDialog(Activity activity, - Handler handler, - String arguments) { - super (activity, handler, arguments); - } - - public void setup() { - inflate(R.layout.gears_dialog_permission, R.id.panel_content); - setupButtons(R.string.permission_button_alwaysdeny, - R.string.permission_button_allow, - R.string.permission_button_deny); - - try { - JSONObject json = new JSONObject(mDialogArguments); - - if (json.has("dialogType")) { - mDialogType = json.getString("dialogType"); - setupDialog(); - } - - if (!json.has("customName")) { - setLabel(json, "origin", R.id.origin_title); - View titleView = findViewById(R.id.origin_title); - if (titleView != null) { - TextView title = (TextView) titleView; - title.setGravity(Gravity.CENTER); - } - } else { - setLabel(json, "customName", R.id.origin_title); - setLabel(json, "origin", R.id.origin_subtitle); - setLabel(json, "customMessage", R.id.origin_message); - } - - if (json.has("customIcon")) { - String iconUrl = json.getString("customIcon"); - mChoosenIconSize = 32; - downloadIcon(iconUrl); - } - - View msg = findViewById(R.id.permission_dialog_message); - if (msg != null) { - TextView dialogMessage = (TextView) msg; - if (mDialogType.equalsIgnoreCase(LOCAL_DATA_STRING)) { - dialogMessage.setText(R.string.query_data_message); - } else if (mDialogType.equalsIgnoreCase(LOCATION_DATA_STRING)) { - dialogMessage.setText(R.string.location_message); - } - } - - } catch (JSONException e) { - Log.e(TAG, "JSON exception ", e); - } - } - - public void setupDialog(TextView message, ImageView icon) { - if (mDialogType.equalsIgnoreCase(LOCAL_DATA_STRING)) { - message.setText(R.string.query_data_prompt); - icon.setImageResource(android.R.drawable.ic_popup_disk_full); - } else if (mDialogType.equalsIgnoreCase(LOCATION_DATA_STRING)) { - message.setText(R.string.location_prompt); - icon.setImageResource(R.drawable.ic_dialog_menu_generic); - } - } - - public String closeDialog(int closingType) { - String ret = null; - switch (closingType) { - case ALWAYS_DENY: - ret = "{\"allow\": false, \"permanently\": true }"; - if (mDialogType.equalsIgnoreCase(LOCAL_DATA_STRING)) { - mNotification = R.string.storage_notification_alwaysdeny; - } else if (mDialogType.equalsIgnoreCase(LOCATION_DATA_STRING)) { - mNotification = R.string.location_notification_alwaysdeny; - } - break; - case ALLOW: - ret = "{\"allow\": true, \"permanently\": true }"; - if (mDialogType.equalsIgnoreCase(LOCAL_DATA_STRING)) { - mNotification = R.string.storage_notification; - } else if (mDialogType.equalsIgnoreCase(LOCATION_DATA_STRING)) { - mNotification = R.string.location_notification; - } - break; - case DENY: - ret = "{\"allow\": false, \"permanently\": false }"; - break; - } - return ret; - } - - public int notification() { - return mNotification; - } -} diff --git a/src/com/android/browser/GearsSettingsDialog.java b/src/com/android/browser/GearsSettingsDialog.java deleted file mode 100644 index 5ea2342..0000000 --- a/src/com/android/browser/GearsSettingsDialog.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Handler; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.RadioButton; -import android.widget.TextView; - -import com.android.browser.GearsPermissions.OriginPermissions; -import com.android.browser.GearsPermissions.Permission; -import com.android.browser.GearsPermissions.PermissionsChangesListener; -import com.android.browser.GearsPermissions.PermissionType; - -import java.util.Vector; -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Gears Settings dialog - */ -class GearsSettingsDialog extends GearsBaseDialog - implements PermissionsChangesListener { - - private static final String TAG = "GearsPermissionsDialog"; - private Vector<OriginPermissions> mSitesPermissions = null; - private Vector<OriginPermissions> mOriginalPermissions = null; - private Vector<OriginPermissions> mCurrentPermissions = null; - - private Vector<PermissionType> mPermissions; - private static final int CONFIRMATION_REMOVE_DIALOG = 1; - - // We declare the permissions globally to simplify the code - private final PermissionType LOCAL_STORAGE = - new PermissionType(LOCAL_STORAGE_STRING); - private final PermissionType LOCATION_DATA = - new PermissionType(LOCATION_DATA_STRING); - - private boolean mChanges = false; - - SettingsAdapter mListAdapter; - - public GearsSettingsDialog(Activity activity, - Handler handler, - String arguments) { - super (activity, handler, arguments); - activity.setContentView(R.layout.gears_settings); - } - - public void setup() { - // First let's add the permissions' resources - LOCAL_STORAGE.setResources(R.string.settings_storage_title, - R.string.settings_storage_subtitle_on, - R.string.settings_storage_subtitle_off); - LOCATION_DATA.setResources(R.string.settings_location_title, - R.string.settings_location_subtitle_on, - R.string.settings_location_subtitle_off); - // add the permissions to the list of permissions. - mPermissions = new Vector<PermissionType>(); - mPermissions.add(LOCAL_STORAGE); - mPermissions.add(LOCATION_DATA); - OriginPermissions.setListener(this); - - - setupDialog(); - - // We manage the permissions using three vectors, mSitesPermissions, - // mOriginalPermissions and mCurrentPermissions. - // The dialog's arguments are parsed and a list of permissions is - // generated and stored in those three vectors. - // mOriginalPermissions is a separate copy and will not be modified; - // mSitesPermissions contains the current permissions _only_ -- - // if an origin is removed, it is also removed from mSitesPermissions. - // Finally, mCurrentPermissions contains the current permissions and - // is a clone of mSitesPermissions, but removed sites aren't removed, - // their permissions are simply set to PERMISSION_NOT_SET. This - // allows us to easily generate the final difference between the - // original permissions and the final permissions, while directly - // using mSitesPermissions for the listView adapter (SettingsAdapter). - - mSitesPermissions = new Vector<OriginPermissions>(); - mOriginalPermissions = new Vector<OriginPermissions>(); - - try { - JSONObject json = new JSONObject(mDialogArguments); - if (json.has("permissions")) { - JSONArray jsonArray = json.getJSONArray("permissions"); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject infos = jsonArray.getJSONObject(i); - String name = null; - int localStorage = PermissionType.PERMISSION_NOT_SET; - int locationData = PermissionType.PERMISSION_NOT_SET; - if (infos.has("name")) { - name = infos.getString("name"); - } - if (infos.has(LOCAL_STORAGE_STRING)) { - JSONObject perm = infos.getJSONObject(LOCAL_STORAGE_STRING); - if (perm.has("permissionState")) { - localStorage = perm.getInt("permissionState"); - } - } - if (infos.has(LOCATION_DATA_STRING)) { - JSONObject perm = infos.getJSONObject(LOCATION_DATA_STRING); - if (perm.has("permissionState")) { - locationData = perm.getInt("permissionState"); - } - } - OriginPermissions perms = new OriginPermissions(name); - perms.setPermission(LOCAL_STORAGE, localStorage); - perms.setPermission(LOCATION_DATA, locationData); - - mSitesPermissions.add(perms); - mOriginalPermissions.add(new OriginPermissions(perms)); - } - } - } catch (JSONException e) { - Log.e(TAG, "JSON exception ", e); - } - mCurrentPermissions = (Vector<OriginPermissions>)mSitesPermissions.clone(); - - View listView = findViewById(R.id.sites_list); - if (listView != null) { - ListView list = (ListView) listView; - mListAdapter = new SettingsAdapter(mActivity, mSitesPermissions); - list.setAdapter(mListAdapter); - list.setScrollBarStyle(android.view.View.SCROLLBARS_OUTSIDE_INSET); - list.setOnItemClickListener(mListAdapter); - } - if (mDebug) { - printPermissions(); - } - } - - private void setMainTitle() { - String windowTitle = mActivity.getString(R.string.pref_extras_gears_settings); - mActivity.setTitle(windowTitle); - } - - public void setupDialog() { - setMainTitle(); - } - - /** - * GearsPermissions.PermissionsChangesListener delegate - */ - public boolean setPermission(PermissionType type, int perm) { - if (mChanges == false) { - mChanges = true; - } - return mChanges; - } - - public boolean handleBackButton() { - return mListAdapter.backButtonPressed(); - } - - /** - * We use this to create a confirmation dialog when the user - * clicks on "remove this site from gears" - */ - public Dialog onCreateDialog(int id) { - return new AlertDialog.Builder(mActivity) - .setTitle(R.string.settings_confirmation_remove_title) - .setMessage(R.string.settings_confirmation_remove) - .setPositiveButton(android.R.string.ok, - new AlertDialog.OnClickListener() { - public void onClick(DialogInterface dlg, int which) { - mListAdapter.removeCurrentSite(); - } - }) - .setNegativeButton(android.R.string.cancel, null) - .setIcon(android.R.drawable.ic_dialog_alert) - .create(); - } - - /** - * Adapter class for the list view in the settings dialog - * - * We first display a list of all the origins (sites), or - * a message saying that no permission is set if the list is empty. - * When the user click on one of the origin, we then display - * the list of the permissions existing for that origin. - * Each permission can be either allowed or denied by clicking - * on the checkbox. - * The last row is a special case, allowing to remove the entire origin. - */ - class SettingsAdapter extends BaseAdapter - implements AdapterView.OnItemClickListener { - private Activity mContext; - private List mItems; - private OriginPermissions mCurrentSite; - private Vector mCurrentPermissions; - private int MAX_ROW_HEIGHT = 64; - - SettingsAdapter(Activity context, List items) { - mContext = context; - mItems = items; - mCurrentSite = null; - } - - public int getCount() { - if (mCurrentSite == null) { - int size = mItems.size(); - if (size == 0) { - return 1; - } else { - return size; - } - } - return mCurrentPermissions.size() + 1; - } - - public long getItemId(int position) { - return position; - } - - private String shortName(String url) { - // We remove the http and https prefix - if (url.startsWith("http://")) { - return url.substring(7); - } - if (url.startsWith("https://")) { - return url.substring(8); - } - return url; - } - - public Object getItem(int position) { - if (mCurrentSite == null) { - if (mItems.size() == 0) { - return null; - } else { - return mItems.get(position); - } - } - return mCurrentPermissions.get(position); - } - - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - if (row == null) { // no cached view, we create one - LayoutInflater inflater = (LayoutInflater) getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - row = inflater.inflate(R.layout.gears_settings_row, null); - } - row.setMinimumHeight(MAX_ROW_HEIGHT); - - if (mCurrentSite == null) { - if (mItems.size() == 0) { - hideView(row, R.id.title); - hideView(row, R.id.subtitle); - hideView(row, R.id.checkbox); - hideView(row, R.id.icon); - setText(row, R.id.info, R.string.settings_empty); - } else { - hideView(row, R.id.subtitle); - hideView(row, R.id.info); - hideView(row, R.id.checkbox); - OriginPermissions perms = (OriginPermissions) mItems.get(position); - setText(row, R.id.title, shortName(perms.getOrigin())); - showView(row, R.id.icon); - } - } else { - if (position == getCount() - 1) { - // last position: "remove this site from gears" - hideView(row, R.id.subtitle); - hideView(row, R.id.info); - hideView(row, R.id.checkbox); - hideView(row, R.id.icon); - setText(row, R.id.title, R.string.settings_remove_site); - } else { - hideView(row, R.id.info); - hideView(row, R.id.icon); - showView(row, R.id.checkbox); - - PermissionType type = - (PermissionType) mCurrentPermissions.get(position); - setText(row, R.id.title, type.getTitleRsc()); - - View checkboxView = row.findViewById(R.id.checkbox); - if (checkboxView != null) { - CheckBox checkbox = (CheckBox) checkboxView; - int perm = mCurrentSite.getPermission(type); - if (perm == PermissionType.PERMISSION_DENIED) { - setText(row, R.id.subtitle, type.getSubtitleOffRsc()); - checkbox.setChecked(false); - } else { - setText(row, R.id.subtitle, type.getSubtitleOnRsc()); - checkbox.setChecked(true); - } - } - } - } - return row; - } - - public void removeCurrentSite() { - mCurrentSite.setPermission(LOCAL_STORAGE, - PermissionType.PERMISSION_NOT_SET); - mCurrentSite.setPermission(LOCATION_DATA, - PermissionType.PERMISSION_NOT_SET); - mSitesPermissions.remove(mCurrentSite); - mCurrentSite = null; - setMainTitle(); - notifyDataSetChanged(); - } - - public void onItemClick(AdapterView<?> parent, - View view, - int position, - long id) { - if (mItems.size() == 0) { - return; - } - if (mCurrentSite == null) { - mCurrentSite = (OriginPermissions) mItems.get(position); - mCurrentPermissions = new Vector(); - for (int i = 0; i < mPermissions.size(); i++) { - PermissionType type = mPermissions.get(i); - int perm = mCurrentSite.getPermission(type); - if (perm != PermissionType.PERMISSION_NOT_SET) { - mCurrentPermissions.add(type); - } - } - mContext.setTitle(shortName(mCurrentSite.getOrigin())); - } else { - if (position == getCount() - 1) { // last item (remove site) - // Ask the user to confirm - // If yes, removeCurrentSite() will be called via the dialog callback. - mActivity.showDialog(CONFIRMATION_REMOVE_DIALOG); - } else { - PermissionType type = - (PermissionType) mCurrentPermissions.get(position); - if (mCurrentSite.getPermission(type) == - PermissionType.PERMISSION_ALLOWED) { - mCurrentSite.setPermission(type, PermissionType.PERMISSION_DENIED); - } else { - mCurrentSite.setPermission(type, PermissionType.PERMISSION_ALLOWED); - } - } - } - notifyDataSetChanged(); - } - - public boolean backButtonPressed() { - if (mCurrentSite != null) { // we intercept the back button - mCurrentSite = null; - setMainTitle(); - notifyDataSetChanged(); - return true; - } - return false; - } - - } - - /** - * Utility method used in debug mode to print the list of - * permissions (original values and current values). - */ - public void printPermissions() { - Log.v(TAG, "Original Permissions: "); - for (int i = 0; i < mOriginalPermissions.size(); i++) { - OriginPermissions p = mOriginalPermissions.get(i); - p.print(); - } - Log.v(TAG, "Current Permissions: "); - for (int i = 0; i < mSitesPermissions.size(); i++) { - OriginPermissions p = mSitesPermissions.get(i); - p.print(); - } - } - - /** - * Computes the difference between the original permissions and the - * current ones. Returns a json-formatted string. - * It is used by the Settings dialog. - */ - public String computeDiff(boolean modif) { - String ret = null; - try { - JSONObject results = new JSONObject(); - JSONArray permissions = new JSONArray(); - - for (int i = 0; modif && i < mOriginalPermissions.size(); i++) { - OriginPermissions original = mOriginalPermissions.get(i); - OriginPermissions current = mCurrentPermissions.get(i); - JSONObject permission = new JSONObject(); - boolean modifications = false; - - for (int j = 0; j < mPermissions.size(); j++) { - PermissionType type = mPermissions.get(j); - - if (current.getPermission(type) != original.getPermission(type)) { - JSONObject state = new JSONObject(); - state.put("permissionState", current.getPermission(type)); - permission.put(type.getName(), state); - modifications = true; - } - } - - if (modifications) { - permission.put("name", current.getOrigin()); - permissions.put(permission); - } - } - results.put("modifiedOrigins", permissions); - ret = results.toString(); - } catch (JSONException e) { - Log.e(TAG, "JSON exception ", e); - } - return ret; - } - - public String closeDialog(int closingType) { - String ret = computeDiff(mChanges); - - if (mDebug) { - printPermissions(); - } - - return ret; - } - -} diff --git a/src/com/android/browser/GearsShortcutDialog.java b/src/com/android/browser/GearsShortcutDialog.java deleted file mode 100644 index 11d936d..0000000 --- a/src/com/android/browser/GearsShortcutDialog.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.Activity; -import android.os.Handler; -import android.util.Log; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Gears Shortcut dialog - */ -class GearsShortcutDialog extends GearsBaseDialog { - - private static final String TAG = "GearsPermissionsDialog"; - - private final String ICON_16 = "icon16x16"; - private final String ICON_32 = "icon32x32"; - private final String ICON_48 = "icon48x48"; - private final String ICON_128 = "icon128x128"; - private int mNotification = 0; - - public GearsShortcutDialog(Activity activity, - Handler handler, - String arguments) { - super (activity, handler, arguments); - } - - public void setup() { - inflate(R.layout.gears_dialog_shortcut, R.id.panel_content); - setupButtons(R.string.shortcut_button_alwaysdeny, - R.string.shortcut_button_allow, - R.string.shortcut_button_deny); - - try { - JSONObject json = new JSONObject(mDialogArguments); - - String iconUrl = pickIconToRender(json); - if (iconUrl != null) { - downloadIcon(iconUrl); - } - - setupDialog(); - - setLabel(json, "name", R.id.shortcut_name); - setLabel(json, "link", R.id.origin_subtitle); - setLabel(json, "description", R.id.origin_message); - } catch (JSONException e) { - Log.e(TAG, "JSON exception", e); - } - - TextView msg = (TextView) findViewById(R.id.permission_dialog_message); - msg.setText(R.string.shortcut_message); - - View shortcutIcon = findViewById(R.id.shortcut_panel); - if (shortcutIcon != null) { - shortcutIcon.setVisibility(View.VISIBLE); - } - } - - public void setupDialog(TextView message, ImageView icon) { - message.setText(R.string.shortcut_prompt); - icon.setImageResource(R.drawable.ic_dialog_menu_generic); - } - - /** - * Utility method to validate an icon url. Used in the - * shortcut dialog. - */ - boolean validIcon(JSONObject json, String name) { - try { - if (json.has(name)) { - String str = json.getString(name); - if (str.length() > 0) { - return true; - } - } - } catch (JSONException e) { - Log.e(TAG, "JSON exception", e); - } - return false; - } - - - /** - * Utility method to pick the best indicated icon - * from the dialogs' arguments. Used in the - * shortcut dialog. - */ - String pickIconToRender(JSONObject json) { - try { - if (validIcon(json, ICON_48)) { // ideal size - mChoosenIconSize = 48; - return json.getString(ICON_48); - } else if (validIcon(json, ICON_32)) { - mChoosenIconSize = 32; - return json.getString(ICON_32); - } else if (validIcon(json, ICON_128)) { - mChoosenIconSize = 128; - return json.getString(ICON_128); - } else if (validIcon(json, ICON_16)) { - mChoosenIconSize = 16; - return json.getString(ICON_16); - } - } catch (JSONException e) { - Log.e(TAG, "JSON exception", e); - } - mChoosenIconSize = 0; - return null; - } - - public String closeDialog(int closingType) { - String ret = null; - switch (closingType) { - case ALWAYS_DENY: - ret = "{\"allow\": false, \"permanently\": true }"; - break; - case ALLOW: - ret = "{\"allow\": true, \"locations\": 0 }"; - mNotification = R.string.shortcut_notification; - break; - case DENY: - ret = null; - break; - } - return ret; - } - - public int notification() { - return mNotification; - } -} diff --git a/src/com/android/browser/HistoryItem.java b/src/com/android/browser/HistoryItem.java deleted file mode 100644 index 55e43f0..0000000 --- a/src/com/android/browser/HistoryItem.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.browser; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.net.Uri; -import android.provider.Browser; -import android.util.Log; -import android.view.View; -import android.webkit.WebIconDatabase; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.Date; - -/** - * Layout representing a history item in the classic history viewer. - */ -/* package */ class HistoryItem extends BookmarkItem { - - private CompoundButton mStar; // Star for bookmarking - private CompoundButton.OnCheckedChangeListener mListener; - /** - * Create a new HistoryItem. - * @param context Context for this HistoryItem. - */ - /* package */ HistoryItem(Context context) { - super(context); - - mStar = (CompoundButton) findViewById(R.id.star); - mStar.setVisibility(View.VISIBLE); - mListener = new CompoundButton.OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - ContentResolver cr = mContext.getContentResolver(); - Cursor cursor = cr.query( - Browser.BOOKMARKS_URI, - Browser.HISTORY_PROJECTION, - "url = ?", - new String[] { mUrl }, - null); - boolean first = cursor.moveToFirst(); - // Should be in the database no matter what - if (!first) { - throw new AssertionError("URL is not in the database!"); - } - if (isChecked) { - // Add to bookmarks - // FIXME: Share code with AddBookmarkPage.java - ContentValues map = new ContentValues(); - map.put(Browser.BookmarkColumns.CREATED, - new Date().getTime()); - map.put(Browser.BookmarkColumns.TITLE, getName()); - map.put(Browser.BookmarkColumns.BOOKMARK, 1); - try { - cr.update(Browser.BOOKMARKS_URI, map, - "_id = " + cursor.getInt(0), null); - } catch (IllegalStateException e) { - Log.e("HistoryItem", "no database!"); - } - WebIconDatabase.getInstance().retainIconForPageUrl(mUrl); - // catch IllegalStateException? - Toast.makeText(mContext, R.string.added_to_bookmarks, - Toast.LENGTH_LONG).show(); - } else { - // Remove from bookmarks - // FIXME: This code should be shared with - // BrowserBookmarksAdapter.java - WebIconDatabase.getInstance().releaseIconForPageUrl(mUrl); - Uri uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI, - cursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX)); - // It is no longer a bookmark, but it is still a visited - // site. - ContentValues values = new ContentValues(); - values.put(Browser.BookmarkColumns.BOOKMARK, 0); - try { - cr.update(uri, values, null, null); - } catch (IllegalStateException e) { - Log.e("HistoryItem", "no database!"); - } - Toast.makeText(mContext, R.string.removed_from_bookmarks, - Toast.LENGTH_LONG).show(); - } - cursor.deactivate(); - } - }; - } - - void copyTo(HistoryItem item) { - item.mTextView.setText(mTextView.getText()); - item.mUrlText.setText(mUrlText.getText()); - item.setIsBookmark(mStar.isChecked()); - item.mImageView.setImageDrawable(mImageView.getDrawable()); - } - - /** - * Set whether or not this represents a bookmark, and make sure the star - * behaves appropriately. - */ - void setIsBookmark(boolean isBookmark) { - mStar.setOnCheckedChangeListener(null); - mStar.setChecked(isBookmark); - mStar.setOnCheckedChangeListener(mListener); - } -} diff --git a/src/com/android/browser/ImageAdapter.java b/src/com/android/browser/ImageAdapter.java deleted file mode 100644 index b4c1209..0000000 --- a/src/com/android/browser/ImageAdapter.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.database.DataSetObserver; -import android.graphics.Color; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.LayoutInflater; -import android.webkit.WebView; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.TextView; - -import java.util.ArrayList; - -/** - * Adapter used by ImageGrid. - */ -public class ImageAdapter implements ListAdapter { - - ArrayList<TabControl.Tab> mItems; // Items shown in the grid - private ArrayList<DataSetObserver> mDataObservers; // Data change listeners - private Context mContext; // Context to use to inflate views - private boolean mMaxedOut; - private ImageGrid mImageGrid; - private boolean mIsLive; - private int mTabHeight; - - ImageAdapter(Context context, ImageGrid grid, boolean live) { - mContext = context; - mIsLive = live; - mItems = new ArrayList<TabControl.Tab>(); - mImageGrid = grid; - mDataObservers = new ArrayList<DataSetObserver>(); - } - - void heightChanged(int newHeight) { - mTabHeight = newHeight; - } - - /** - * Whether the adapter is at its limit, determined by TabControl.MAX_TABS - * - * @return True if the number of Tabs represented in this Adapter is at its - * maximum. - */ - public boolean maxedOut() { - return mMaxedOut; - } - - /** - * Clear the internal WebViews and remove their picture listeners. - */ - public void clear() { - for (TabControl.Tab t : mItems) { - clearPictureListeners(t); - } - mItems.clear(); - notifyObservers(); - } - - private void clearPictureListeners(TabControl.Tab t) { - if (t.getWebView() != null) { - t.getWebView().setPictureListener(null); - if (t.getSubWebView() != null) { - t.getSubWebView().setPictureListener(null); - } - } - } - - /** - * Add a new window web page to the grid - * - * @param t The tab to display - */ - public void add(TabControl.Tab t) { - if (mMaxedOut) { - return; - } - mItems.add(t); - notifyObservers(); - if (mItems.size() == TabControl.MAX_TABS) { - mMaxedOut = true; - } - } - - /** - * Remove a window from the list. At this point, the window - * has already gone. It just needs to be removed from the screen - * - * @param index window to remove - */ - public void remove(int index) { - if (index >= 0 && index < mItems.size()) { - clearPictureListeners(mItems.remove(index)); - notifyObservers(); - mMaxedOut = false; - } - } - - /* (non-Javadoc) - * @see android.widget.ListAdapter#areAllItemsSelectable() - */ - public boolean areAllItemsEnabled() { - return true; - } - - /* (non-Javadoc) - * @see android.widget.ListAdapter#isSelectable(int) - */ - public boolean isEnabled(int position) { - if (position >= 0 && position <= mItems.size()) { - return true; - } - return false; - } - - /* (non-Javadoc) - * @see android.widget.Adapter#getCount() - */ - public int getCount() { - // Include the New Window button if we have not reached the tab limit - if (!mMaxedOut) { - return mItems.size()+1; - } - return mItems.size(); - } - - /* (non-Javadoc) - * @see android.widget.Adapter#getItem(int) - */ - public Object getItem(int position) { - if (!mMaxedOut) { - if (0 == position) { - return null; - } - return mItems.get(position); - } - return mItems.get(position); - } - - /* (non-Javadoc) - * @see android.widget.Adapter#getItemId(int) - */ - public long getItemId(int position) { - return position; - } - - /* (non-Javadoc) - * @see android.widget.Adapter#getView(int, android.view.View, - * android.view.ViewGroup) - */ - public View getView(int position, View convertView, ViewGroup parent) { - View v = null; - if (convertView != null) { - v = convertView; - } else { - LayoutInflater factory = LayoutInflater.from(mContext); - v = factory.inflate(R.layout.tabitem, null); - } - FakeWebView img = (FakeWebView) v.findViewById(R.id.icon); - ImageView close = (ImageView) v.findViewById(R.id.close); - TextView tv = (TextView) v.findViewById(R.id.label); - - // position needs to be in the range of Tab indices. - if (!mMaxedOut) { - position--; - } - - // Create the View for actual tabs - if (position != ImageGrid.NEW_TAB) { - TabControl.Tab t = mItems.get(position); - img.setTab(t); - tv.setText(t.getTitle()); - // Do not put the 'X' if the tab picker isn't "live" (meaning the - // user cannot click on a tab) - if (!mIsLive) { - close.setVisibility(View.GONE); - } else { - close.setVisibility(View.VISIBLE); - final int pos = position; - close.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - ImageAdapter.this.confirmClose(pos); - } - }); - } - } else { - img.setBackgroundColor(Color.BLACK); - img.setImageResource(R.drawable.ic_new_window); - img.setScaleType(ImageView.ScaleType.CENTER); - img.setPadding(0, 0, 0, 34); - tv.setText(R.string.new_window); - close.setVisibility(View.GONE); - } - ViewGroup.LayoutParams lp = img.getLayoutParams(); - if (lp.height != mTabHeight) { - lp.height = mTabHeight; - img.requestLayout(); - } - return v; - } - - /* - * Pop a confirmation dialog to the user asking if they want to close this - * tab. - */ - private void confirmClose(final int position) { - final ImageGrid.Listener l = mImageGrid.getListener(); - if (l == null) { - return; - } - DialogInterface.OnClickListener confirm = - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int whichButton) { - l.remove(position); - } - }; - new AlertDialog.Builder(mContext) - .setTitle(R.string.close) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.close_window) - .setPositiveButton(R.string.ok, confirm) - .setNegativeButton(R.string.cancel, null) - .show(); - } - - /* (non-Javadoc) - * @see android.widget.Adapter#registerDataSetObserver(android.database.DataSetObserver) - */ - public void registerDataSetObserver(DataSetObserver observer) { - mDataObservers.add(observer); - } - - /* (non-Javadoc) - * @see android.widget.Adapter#hasStableIds() - */ - public boolean hasStableIds() { - return true; - } - - /* (non-Javadoc) - * @see android.widget.Adapter#unregisterDataSetObserver(android.database.DataSetObserver) - */ - public void unregisterDataSetObserver(DataSetObserver observer) { - mDataObservers.remove(observer); - } - - /** - * Notify all the observers that a change has happened. - */ - void notifyObservers() { - for (DataSetObserver observer : mDataObservers) { - observer.onChanged(); - } - } - - public int getItemViewType(int position) { - return 0; - } - - public int getViewTypeCount() { - return 1; - } - - public boolean isEmpty() { - return getCount() == 0; - } -} diff --git a/src/com/android/browser/ImageGrid.java b/src/com/android/browser/ImageGrid.java deleted file mode 100644 index 9eccb16..0000000 --- a/src/com/android/browser/ImageGrid.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.browser; - -import android.content.Context; -import android.util.Config; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnCreateContextMenuListener; -import android.webkit.WebView; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.GridView; - -/** - * This class implements a Grid layout of Views for the Tab picker. - */ -class ImageGrid extends GridView implements OnItemClickListener, - OnCreateContextMenuListener { - - private Listener mListener; - private ImageAdapter mAdapter; - private boolean mIsLive; - private static final int SPACING = 10; - public static final int CANCEL = -99; - public static final int NEW_TAB = -1; - - /** - * Constructor - * @param context Context to use when inflating resources. - * @param live TRUE if the view can accept touch or click - * @param l Listener to respond to clicks etc. - */ - public ImageGrid(Context context, boolean live, Listener l) { - super(context); - - mIsLive = live; - if (live) { - setFocusable(true); - setFocusableInTouchMode(true); - setOnItemClickListener(this); - setOnCreateContextMenuListener(this); - } - mListener = l; - - mAdapter = new ImageAdapter(context, this, live); - setAdapter(mAdapter); - - setBackgroundColor(0xFF000000); - - setVerticalSpacing(SPACING); - setHorizontalSpacing(SPACING); - setNumColumns(2); - setStretchMode(GridView.STRETCH_COLUMN_WIDTH); - setSelector(android.R.drawable.gallery_thumb); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // We always consume the BACK key even if mListener is null or the - // ImageGrid is not "live." This prevents crashes during tab animations - // if the user presses BACK. - if ((event.getAction() == KeyEvent.ACTION_DOWN) && - (event.getKeyCode() == KeyEvent.KEYCODE_BACK)) { - if (mListener != null && mIsLive) { - mListener.onClick(CANCEL); - invalidate(); - } - return true; - } - return super.dispatchKeyEvent(event); - } - - /** - * Called by BrowserActivity to add a new window to the tab picker. - * This does not happen dynamically, this only happens during view - * setup. - * - * @param v Webview of the tab to add - * @param name Web page title - * @param url URL of the webpage - */ - public void add(TabControl.Tab t) { - mAdapter.add(t); - } - - /** - * Called by BrowserActivity when a window has been removed from the - * tab list. - * - * @param index Window to remove, from 0 to MAX_TABS-1 - */ - public void remove(int index) { - if (Config.DEBUG && (index < 0 || index >= TabControl.MAX_TABS)) { - throw new AssertionError(); - } - mAdapter.remove(index); - } - - /** - * Request focus to initially set to a particular tab. - * - * @param startingIndex This is a Tab index from 0 - MAX_TABS-1 and does not - * include the "New Tab" cell. - */ - public void setCurrentIndex(int startingIndex) { - if (!mAdapter.maxedOut()) { - startingIndex++; - } - setSelection(startingIndex); - } - - public Listener getListener() { - return mListener; - } - - public void setListener(Listener l) { - mListener = l; - } - - /** - * Return true if the ImageGrid is live. This means that tabs can be chosen - * and the menu can be invoked. - */ - public boolean isLive() { - return mIsLive; - } - - /** - * Do some internal cleanup of the ImageGrid's adapter. - */ - public void clear() { - mAdapter.clear(); - } - - /* (non-Javadoc) - * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long) - */ - public void onItemClick(AdapterView parent, View v, int position, long id) { - if (!mAdapter.maxedOut()) { - position--; - } - // Position will be -1 for the "New Tab" cell. - if (mListener != null) { - mListener.onClick(position); - } - } - - /* (non-Javadoc) - * @see android.view.View.OnCreateContextMenuListener#onCreateContextMenu(android.view.ContextMenu, android.view.View, java.lang.Object) - */ - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - // Do not create the context menu if there is no listener or the Tab - // overview is not "live." - if (mListener == null || !mIsLive) { - return; - } - AdapterView.AdapterContextMenuInfo info = - (AdapterView.AdapterContextMenuInfo) menuInfo; - boolean maxed = mAdapter.maxedOut(); - if (info.position > 0 || maxed) { - MenuInflater inflater = new MenuInflater(mContext); - inflater.inflate(R.menu.tabscontext, menu); - int position = info.position; - if (!maxed) { - position--; - } - menu.setHeaderTitle(mAdapter.mItems.get(position).getTitle()); - } - } - - // convert a context menu position to an actual tab position. Since context - // menus are not created for the "New Tab" cell, this will always return a - // valid tab position. - public int getContextMenuPosition(MenuItem menu) { - AdapterView.AdapterContextMenuInfo info = - (AdapterView.AdapterContextMenuInfo) menu.getMenuInfo(); - int pos = info.position; - if (!mAdapter.maxedOut()) { - pos--; - } - return pos; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - // Called when our orientation changes. Tell the adapter about the new - // size. Compute the individual tab height by taking the grid height - // and subtracting the SPACING. Then subtract the list padding twice - // (once for each tab on screen) and divide the remaining height by 2. - int tabHeight = (h - SPACING - - 2 * (getListPaddingTop() + getListPaddingBottom())) / 2; - mAdapter.heightChanged(tabHeight); - super.onSizeChanged(w, h, oldw, oldh); - } - - /** - * Listener to be notified by behavior of ImageGrid. - */ - public interface Listener { - /** - * Called when enter is pressed on the list. - * @param position The index of the selected image when - * enter is pressed. - */ - void onClick(int position); - - /** - * Called when remove is called on the grid. - */ - void remove(int position); - } - -} diff --git a/src/com/android/browser/KeyTracker.java b/src/com/android/browser/KeyTracker.java deleted file mode 100644 index 344e4f8..0000000 --- a/src/com/android/browser/KeyTracker.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2006 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.view.KeyEvent; -import android.view.ViewConfiguration; - -class KeyTracker { - - public enum Stage { - DOWN, //!< the key has just been pressed - SHORT_REPEAT, //!< repeated key, but duration is under the long-press threshold - LONG_REPEAT, //!< repeated key, but duration is over the long-press threshold - UP //!< the key is being released - } - - public enum State { - KEEP_TRACKING, //!< return this to continue to track the key - DONE_TRACKING, //!< return this if you handled the key, but need not track it anymore - NOT_TRACKING //!< return this if you will not handle this key - } - - public interface OnKeyTracker { - - /** Called whenever there is a key event [down, short/long repeat, up] - @param keyCode The current keyCode (see KeyEvent class) - @param msg The message associated with the keyCode - @maram stage The state the key press is in [down, short/long repeat, up] - @param duration The number of milliseconds since this key was initially pressed - @return your state after seeing the key. If you return DONE_TRACKING or NOT_TRACKING, - you will not be called again for the lifetime of this key event. - */ - public State onKeyTracker(int keyCode, KeyEvent event, Stage stage, int duration); - } - - public KeyTracker(OnKeyTracker tracker) { - mTracker = tracker; - } - - public boolean doKeyDown(int keyCode, KeyEvent event) { - long now = System.currentTimeMillis(); - Stage stage = null; - - // check if its a new/different key - if (mKeyCode != keyCode || event.getRepeatCount() == 0) { - mKeyCode = keyCode; - mStartMS = now; - stage = Stage.DOWN; - } - else if (mState == State.KEEP_TRACKING) { - stage = (now - mStartMS) >= LONG_PRESS_DURATION_MS ? Stage.LONG_REPEAT : Stage.SHORT_REPEAT; - } - - if (stage != null) { - mEvent = event; - callTracker(stage, now); - } - - return mState != State.NOT_TRACKING; - } - - public boolean doKeyUp(int keyCode, KeyEvent event) { - boolean handled = false; - - if (mState == State.KEEP_TRACKING && mKeyCode == keyCode) { - mEvent = event; - callTracker(Stage.UP, System.currentTimeMillis()); - handled = mState != State.NOT_TRACKING; - } - mKeyCode = NOT_A_KEYCODE; - return handled; - } - - private void callTracker(Stage stage, long now) { - mState = mTracker.onKeyTracker(mKeyCode, mEvent, stage, (int)(now - mStartMS)); - } - - private void dump() { - System.out.println(" key=" + mKeyCode + " dur=" + (System.currentTimeMillis() - mStartMS) + - " state=" + mState); - } - - private int mKeyCode = NOT_A_KEYCODE; - private KeyEvent mEvent; - private long mStartMS; - private State mState; - private OnKeyTracker mTracker; - - private static final int LONG_PRESS_DURATION_MS = - ViewConfiguration.getLongPressTimeout(); - private static final int NOT_A_KEYCODE = -123456; -} - diff --git a/src/com/android/browser/MostVisitedActivity.java b/src/com/android/browser/MostVisitedActivity.java deleted file mode 100644 index 704ee27..0000000 --- a/src/com/android/browser/MostVisitedActivity.java +++ /dev/null @@ -1,199 +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.app.ListActivity; -import android.content.Intent; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.os.Handler; -import android.provider.Browser; -import android.webkit.WebIconDatabase.IconListener; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.SimpleCursorAdapter; -import android.widget.TextView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; - -import java.util.Vector; - -public class MostVisitedActivity extends ListActivity { - - private MyAdapter mAdapter; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mAdapter = new MyAdapter(); - CombinedBookmarkHistoryActivity.getIconListenerSet(getContentResolver()) - .addListener(new IconReceiver()); - setListAdapter(mAdapter); - ListView list = getListView(); - LayoutInflater factory = LayoutInflater.from(this); - View v = factory.inflate(R.layout.empty_history, null); - addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT, - LayoutParams.FILL_PARENT)); - list.setEmptyView(v); - } - - private class IconReceiver implements IconListener { - public void onReceivedIcon(String url, Bitmap icon) { - setListAdapter(mAdapter); - } - } - - protected void onListItemClick(ListView l, View v, int position, long id) { - TextView tv = (TextView) v.findViewById(R.id.url); - String url = tv.getText().toString(); - loadUrl(url, false); - } - - private void loadUrl(String url, boolean newWindow) { - Intent intent = new Intent().setAction(url); - if (newWindow) { - Bundle b = new Bundle(); - b.putBoolean("new_window", true); - intent.putExtras(b); - } - setResultToParent(RESULT_OK, intent); - finish(); - } - - private class MyAdapter implements ListAdapter { - private Vector<DataSetObserver> mObservers; - private Cursor mCursor; - // These correspond with projection below. - private final int mUrlIndex = 0; - private final int mTitleIndex = 1; - private final int mBookmarkIndex = 2; - - MyAdapter() { - mObservers = new Vector<DataSetObserver>(); - String[] projection = new String[] { - Browser.BookmarkColumns.URL, - Browser.BookmarkColumns.TITLE, - Browser.BookmarkColumns.BOOKMARK }; - String whereClause = Browser.BookmarkColumns.VISITS + " != 0"; - String orderBy = Browser.BookmarkColumns.VISITS + " DESC"; - mCursor = managedQuery(Browser.BOOKMARKS_URI, projection, - whereClause, null, orderBy); - mCursor.registerContentObserver(new ChangeObserver()); - } - - private class ChangeObserver extends ContentObserver { - public ChangeObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - MyAdapter.this.refreshData(); - } - } - - void refreshData() { - mCursor.requery(); - for (DataSetObserver o : mObservers) { - o.onChanged(); - } - } - - public View getView(int position, View convertView, ViewGroup parent) { - HistoryItem item; - if (null == convertView) { - item = new HistoryItem(MostVisitedActivity.this); - } else { - item = (HistoryItem) convertView; - } - mCursor.moveToPosition(position); - item.setName(mCursor.getString(mTitleIndex)); - String url = mCursor.getString(mUrlIndex); - item.setUrl(url); - item.setFavicon(CombinedBookmarkHistoryActivity.getIconListenerSet( - getContentResolver()).getFavicon(url)); - item.setIsBookmark(1 == mCursor.getInt(mBookmarkIndex)); - return item; - } - - public boolean areAllItemsEnabled() { - return true; - } - - public boolean isEnabled(int position) { - return true; - } - - public int getCount() { - return mCursor.getCount(); - } - - public Object getItem(int position) { - return null; - } - - public long getItemId(int position) { - return position; - } - - // Always a HistoryItem - public int getItemViewType(int position) { - return 0; - } - - public int getViewTypeCount() { - return 1; - } - - public boolean hasStableIds() { - return true; - } - - public void registerDataSetObserver(DataSetObserver observer) { - mObservers.add(observer); - } - - public void unregisterDataSetObserver(DataSetObserver observer) { - mObservers.remove(observer); - } - - public boolean isEmpty() { - return getCount() == 0; - } - } - - // This Activity is generally a sub-Activity of CombinedHistoryActivity. In - // that situation, we need to pass our result code up to our parent. - // However, if someone calls this Activity directly, then this has no - // parent, and it needs to set it on itself. - private void setResultToParent(int resultCode, Intent data) { - Activity a = getParent() == null ? this : getParent(); - a.setResult(resultCode, data); - } -} - diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java deleted file mode 100644 index 69610bf..0000000 --- a/src/com/android/browser/TabControl.java +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Copyright (C) 2007 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.net.http.SslError; -import android.os.Bundle; -import android.os.Message; -import android.util.Config; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.webkit.HttpAuthHandler; -import android.webkit.JsPromptResult; -import android.webkit.JsResult; -import android.webkit.SslErrorHandler; -import android.webkit.WebBackForwardList; -import android.webkit.WebChromeClient; -import android.webkit.WebHistoryItem; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.FrameLayout; -import android.widget.ImageButton; - -import java.io.File; -import java.util.ArrayList; -import java.util.Vector; - -class TabControl { - // Log Tag - private static final String LOGTAG = "TabControl"; - // Maximum number of tabs. - static final int MAX_TABS = 8; - // Static instance of an empty callback. - private static final WebViewClient mEmptyClient = - new WebViewClient(); - // Instance of BackgroundChromeClient for background tabs. - private final BackgroundChromeClient mBackgroundChromeClient = - new BackgroundChromeClient(); - // Private array of WebViews that are used as tabs. - private ArrayList<Tab> mTabs = new ArrayList<Tab>(MAX_TABS); - // Queue of most recently viewed tabs. - private ArrayList<Tab> mTabQueue = new ArrayList<Tab>(MAX_TABS); - // Current position in mTabs. - private int mCurrentTab = -1; - // A private instance of BrowserActivity to interface with when adding and - // switching between tabs. - private final BrowserActivity mActivity; - // Inflation service for making subwindows. - private final LayoutInflater mInflateService; - // Subclass of WebViewClient used in subwindows to notify the main - // WebViewClient of certain WebView activities. - private class SubWindowClient extends WebViewClient { - // The main WebViewClient. - private final WebViewClient mClient; - - SubWindowClient(WebViewClient client) { - mClient = client; - } - @Override - public void doUpdateVisitedHistory(WebView view, String url, - boolean isReload) { - mClient.doUpdateVisitedHistory(view, url, isReload); - } - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - return mClient.shouldOverrideUrlLoading(view, url); - } - @Override - public void onReceivedSslError(WebView view, SslErrorHandler handler, - SslError error) { - mClient.onReceivedSslError(view, handler, error); - } - @Override - public void onReceivedHttpAuthRequest(WebView view, - HttpAuthHandler handler, String host, String realm) { - mClient.onReceivedHttpAuthRequest(view, handler, host, realm); - } - @Override - public void onFormResubmission(WebView view, Message dontResend, - Message resend) { - mClient.onFormResubmission(view, dontResend, resend); - } - @Override - public void onReceivedError(WebView view, int errorCode, - String description, String failingUrl) { - mClient.onReceivedError(view, errorCode, description, failingUrl); - } - } - // Subclass of WebChromeClient to display javascript dialogs. - private class SubWindowChromeClient extends WebChromeClient { - // This subwindow's tab. - private final Tab mTab; - // The main WebChromeClient. - private final WebChromeClient mClient; - - SubWindowChromeClient(Tab t, WebChromeClient client) { - mTab = t; - mClient = client; - } - @Override - public void onProgressChanged(WebView view, int newProgress) { - mClient.onProgressChanged(view, newProgress); - } - @Override - public boolean onCreateWindow(WebView view, boolean dialog, - boolean userGesture, android.os.Message resultMsg) { - return mClient.onCreateWindow(view, dialog, userGesture, resultMsg); - } - @Override - public void onCloseWindow(WebView window) { - if (Config.DEBUG && window != mTab.mSubView) { - throw new AssertionError("Can't close the window"); - } - mActivity.dismissSubWindow(mTab); - } - } - // Background WebChromeClient for focusing tabs - private class BackgroundChromeClient extends WebChromeClient { - @Override - public void onRequestFocus(WebView view) { - Tab t = getTabFromView(view); - if (t != getCurrentTab()) { - mActivity.showTab(t); - } - } - } - - /** - * Private class for maintaining Tabs with a main WebView and a subwindow. - */ - public class Tab { - // Main WebView - private WebView mMainView; - // Subwindow WebView - private WebView mSubView; - // Subwindow container - private View mSubViewContainer; - // Subwindow callback - private SubWindowClient mSubViewClient; - // Subwindow chrome callback - private SubWindowChromeClient mSubViewChromeClient; - // Saved bundle for when we are running low on memory. It contains the - // information needed to restore the WebView if the user goes back to - // the tab. - private Bundle mSavedState; - // Extra saved information for displaying the tab in the picker. - private String mUrl; - private String mTitle; - - // Parent Tab. This is the Tab that created this Tab, or null - // if the Tab was created by the UI - private Tab mParentTab; - // 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; - - private Boolean mCloseOnExit; - - // Construct a new tab - private Tab(WebView w, boolean closeOnExit) { - mMainView = w; - mCloseOnExit = closeOnExit; - } - - /** - * Return the top window of this tab; either the subwindow if it is not - * null or the main window. - * @return The top window of this tab. - */ - public WebView getTopWindow() { - if (mSubView != null) { - return mSubView; - } - return mMainView; - } - - /** - * Return the main window of this tab. Note: if a tab is freed in the - * background, this can return null. It is only guaranteed to be - * non-null for the current tab. - * @return The main WebView of this tab. - */ - public WebView getWebView() { - return mMainView; - } - - /** - * Return the subwindow of this tab or null if there is no subwindow. - * @return The subwindow of this tab or null. - */ - public WebView getSubWebView() { - return mSubView; - } - - /** - * Return the subwindow container of this tab or null if there is no - * subwindow. - * @return The subwindow's container View. - */ - public View getSubWebViewContainer() { - return mSubViewContainer; - } - - /** - * Get the url of this tab. Valid after calling populatePickerData, but - * before calling wipePickerData, or if the webview has been destroyed. - * - * @return The WebView's url or null. - */ - public String getUrl() { - return mUrl; - } - - /** - * Get the title of this tab. Valid after calling populatePickerData, - * but before calling wipePickerData, or if the webview has been - * destroyed. If the url has no title, use the url instead. - * - * @return The WebView's title (or url) or null. - */ - public String getTitle() { - return mTitle; - } - - private void setParentTab(Tab parent) { - mParentTab = 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 (most likely due to removing the parent tab) we must - // update the parent tab index in the saved Bundle. - if (mSavedState != null) { - if (parent == null) { - mSavedState.remove(PARENTTAB); - } else { - mSavedState.putInt(PARENTTAB, getTabIndex(parent)); - } - } - } - - /** - * 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 - */ - public void addChildTab(Tab child) { - if (mChildTabs == null) { - mChildTabs = new Vector<Tab>(); - } - mChildTabs.add(child); - child.setParentTab(this); - } - - private void removeFromTree() { - // detach the children - if (mChildTabs != null) { - for(Tab t : mChildTabs) { - t.setParentTab(null); - } - } - - // Find myself in my parent list - if (mParentTab != null) { - mParentTab.mChildTabs.remove(this); - } - } - - /** - * 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. - */ - public boolean closeOnExit() { - return mCloseOnExit; - } - }; - - // Directory to store thumbnails for each WebView. - private final File mThumbnailDir; - - /** - * Construct a new TabControl object that interfaces with the given - * BrowserActivity instance. - * @param activity A BrowserActivity instance that TabControl will interface - * with. - */ - TabControl(BrowserActivity activity) { - mActivity = activity; - mInflateService = - ((LayoutInflater) activity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE)); - mThumbnailDir = activity.getDir("thumbnails", 0); - } - - File getThumbnailDir() { - return mThumbnailDir; - } - - BrowserActivity getBrowserActivity() { - return mActivity; - } - - /** - * Return the current tab's main WebView. This will always return the main - * WebView for a given tab and not a subwindow. - * @return The current tab's WebView. - */ - WebView getCurrentWebView() { - Tab t = getTab(mCurrentTab); - if (t == null) { - return null; - } - return t.mMainView; - } - - /** - * Return the current tab's top-level WebView. This can return a subwindow - * if one exists. - * @return The top-level WebView of the current tab. - */ - WebView getCurrentTopWebView() { - Tab t = getTab(mCurrentTab); - if (t == null) { - return null; - } - return t.mSubView != null ? t.mSubView : t.mMainView; - } - - /** - * Return the current tab's subwindow if it exists. - * @return The subwindow of the current tab or null if it doesn't exist. - */ - WebView getCurrentSubWindow() { - Tab t = getTab(mCurrentTab); - if (t == null) { - return null; - } - return t.mSubView; - } - - /** - * Return the tab at the specified index. - * @return The Tab for the specified index or null if the tab does not - * exist. - */ - Tab getTab(int index) { - if (index >= 0 && index < mTabs.size()) { - return mTabs.get(index); - } - return null; - } - - /** - * Return the current tab. - * @return The current tab. - */ - Tab getCurrentTab() { - return getTab(mCurrentTab); - } - - /** - * Return the current tab index. - * @return The current tab index - */ - int getCurrentIndex() { - return mCurrentTab; - } - - /** - * Given a Tab, find it's index - * @param Tab to find - * @return index of Tab or -1 if not found - */ - int getTabIndex(Tab tab) { - return mTabs.indexOf(tab); - } - - /** - * Create a new tab and display the new tab immediately. - * @return The newly createTab or null if we have reached the maximum - * number of open tabs. - */ - Tab createNewTab(boolean closeOnExit) { - int size = mTabs.size(); - // Return false if we have maxed out on tabs - if (MAX_TABS == size) { - return null; - } - // Create a new WebView - WebView w = new WebView(mActivity); - w.setMapTrackballToArrowKeys(false); // use trackball directly - // Add this WebView to the settings observer list and update the - // settings - final BrowserSettings s = BrowserSettings.getInstance(); - s.addObserver(w.getSettings()).update(s, null); - // Create a new tab and add it to the tab list - Tab t = new Tab(w, closeOnExit); - mTabs.add(t); - return t; - } - - /** - * Remove the tab from the list. If the tab is the current tab shown, the - * last created tab will be shown. - * @param t The tab to be removed. - */ - boolean removeTab(Tab t) { - if (t == null) { - return false; - } - // Only remove the tab if it is the current one. - if (getCurrentTab() == t) { - putTabInBackground(t); - } - - // Only destroy the WebView if it still exists. - if (t.mMainView != null) { - // Take down the sub window. - dismissSubWindow(t); - // Remove the WebView's settings from the BrowserSettings list of - // observers. - BrowserSettings.getInstance().deleteObserver( - t.mMainView.getSettings()); - // Destroy the main view and subview - t.mMainView.destroy(); - t.mMainView = null; - } - // clear it's references to parent and children - t.removeFromTree(); - - // Remove it from our list of tabs. - mTabs.remove(t); - - // The tab indices have shifted, update all the saved state so we point - // to the correct index. - for (Tab tab : mTabs) { - if (tab.mChildTabs != null) { - for (Tab child : tab.mChildTabs) { - child.setParentTab(tab); - } - } - } - - - // This tab may have been pushed in to the background and then closed. - // If the saved state contains a picture file, delete the file. - if (t.mSavedState != null) { - if (t.mSavedState.containsKey("picture")) { - new File(t.mSavedState.getString("picture")).delete(); - } - } - - // Remove it from the queue of viewed tabs. - mTabQueue.remove(t); - mCurrentTab = -1; - return true; - } - - /** - * Clear the back/forward list for all the current tabs. - */ - void clearHistory() { - int size = getTabCount(); - for (int i = 0; i < size; i++) { - Tab t = mTabs.get(i); - // TODO: if a tab is freed due to low memory, its history is not - // cleared here. - if (t.mMainView != null) { - t.mMainView.clearHistory(); - } - if (t.mSubView != null) { - t.mSubView.clearHistory(); - } - } - } - - /** - * Destroy all the tabs and subwindows - */ - void destroy() { - BrowserSettings s = BrowserSettings.getInstance(); - for (Tab t : mTabs) { - if (t.mMainView != null) { - dismissSubWindow(t); - s.deleteObserver(t.mMainView.getSettings()); - t.mMainView.destroy(); - t.mMainView = null; - } - } - mTabs.clear(); - mTabQueue.clear(); - } - - /** - * Returns the number of tabs created. - * @return The number of tabs created. - */ - int getTabCount() { - return mTabs.size(); - } - - // Used for saving and restoring each Tab - private static final String WEBVIEW = "webview"; - private static final String NUMTABS = "numTabs"; - private static final String CURRTAB = "currentTab"; - private static final String CURRURL = "currentUrl"; - private static final String CURRTITLE = "currentTitle"; - private static final String CLOSEONEXIT = "closeonexit"; - private static final String PARENTTAB = "parentTab"; - - /** - * Save the state of all the Tabs. - * @param outState The Bundle to save the state to. - */ - void saveState(Bundle outState) { - final int numTabs = getTabCount(); - outState.putInt(NUMTABS, numTabs); - final int index = getCurrentIndex(); - outState.putInt(CURRTAB, (index >= 0 && index < numTabs) ? index : 0); - for (int i = 0; i < numTabs; i++) { - final Tab t = getTab(i); - if (saveState(t)) { - outState.putBundle(WEBVIEW + i, t.mSavedState); - } - } - } - - /** - * Restore the state of all the tabs. - * @param inState The saved state of all the tabs. - * @return True if there were previous tabs that were restored. False if - * there was no saved state or restoring the state failed. - */ - boolean restoreState(Bundle inState) { - final int numTabs = (inState == null) - ? -1 : inState.getInt(NUMTABS, -1); - if (numTabs == -1) { - return false; - } else { - final int currentTab = inState.getInt(CURRTAB, -1); - for (int i = 0; i < numTabs; i++) { - if (i == currentTab) { - Tab t = createNewTab(false); - // Me must set the current tab before restoring the state - // so that all the client classes are set. - setCurrentTab(t); - if (!restoreState(inState.getBundle(WEBVIEW + i), t)) { - Log.w(LOGTAG, "Fail in restoreState, load home page."); - t.mMainView.loadUrl(BrowserSettings.getInstance() - .getHomePage()); - } - } else { - // Create a new tab and don't restore the state yet, add it - // to the tab list - Tab t = new Tab(null, false); - t.mSavedState = inState.getBundle(WEBVIEW + i); - if (t.mSavedState != null) { - t.mUrl = t.mSavedState.getString(CURRURL); - t.mTitle = t.mSavedState.getString(CURRTITLE); - } - mTabs.add(t); - mTabQueue.add(t); - } - } - // 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(WEBVIEW + i); - final Tab t = getTab(i); - if (b != null && t != null) { - final int parentIndex = b.getInt(PARENTTAB, -1); - if (parentIndex != -1) { - final Tab parent = getTab(parentIndex); - if (parent != null) { - parent.addChildTab(t); - } - } - } - } - } - return true; - } - - /** - * Free the memory in this order, 1) free the background tab; 2) free the - * WebView cache; - */ - void freeMemory() { - // free the least frequently used background tab - Tab t = getLeastUsedTab(); - if (t != null) { - Log.w(LOGTAG, "Free a tab in the browser"); - freeTab(t); - // force a gc - System.gc(); - return; - } - - // free the WebView cache - Log.w(LOGTAG, "Free WebView cache"); - WebView view = getCurrentWebView(); - view.clearCache(false); - // force a gc - System.gc(); - } - - private Tab getLeastUsedTab() { - // Don't do anything if we only have 1 tab. - if (getTabCount() == 1) { - return null; - } - - // Rip through the queue starting at the beginning and teardown the - // next available tab. - Tab t = null; - int i = 0; - final int queueSize = mTabQueue.size(); - if (queueSize == 0) { - return null; - } - do { - t = mTabQueue.get(i++); - } while (i < queueSize && t != null && t.mMainView == null); - - // Don't do anything if the last remaining tab is the current one. - if (t == getCurrentTab()) { - return null; - } - - return t; - } - - private void freeTab(Tab t) { - // Store the WebView's state. - saveState(t); - - // Tear down the tab. - dismissSubWindow(t); - // Remove the WebView's settings from the BrowserSettings list of - // observers. - BrowserSettings.getInstance().deleteObserver(t.mMainView.getSettings()); - t.mMainView.destroy(); - t.mMainView = null; - } - - /** - * Create a new subwindow unless a subwindow already exists. - * @return True if a new subwindow was created. False if one already exists. - */ - void createSubWindow() { - Tab t = getTab(mCurrentTab); - if (t != null && t.mSubView == null) { - final View v = mInflateService.inflate(R.layout.browser_subwindow, null); - final WebView w = (WebView) v.findViewById(R.id.webview); - w.setMapTrackballToArrowKeys(false); // use trackball directly - final SubWindowClient subClient = - new SubWindowClient(mActivity.getWebViewClient()); - final SubWindowChromeClient subChromeClient = - new SubWindowChromeClient(t, - mActivity.getWebChromeClient()); - w.setWebViewClient(subClient); - w.setWebChromeClient(subChromeClient); - w.setDownloadListener(mActivity); - w.setOnCreateContextMenuListener(mActivity); - final BrowserSettings s = BrowserSettings.getInstance(); - s.addObserver(w.getSettings()).update(s, null); - t.mSubView = w; - t.mSubViewClient = subClient; - t.mSubViewChromeClient = subChromeClient; - // FIXME: I really hate having to know the name of the view - // containing the webview. - t.mSubViewContainer = v.findViewById(R.id.subwindow_container); - final ImageButton cancel = - (ImageButton) v.findViewById(R.id.subwindow_close); - cancel.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - subChromeClient.onCloseWindow(w); - } - }); - } - } - - /** - * Show the tab that contains the given WebView. - * @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); - if (t.mSubView == view || t.mMainView == view) { - return t; - } - } - return null; - } - - /** - * Put the current tab in the background and set newTab as the current tab. - * @param newTab The new tab. If newTab is null, the current tab is not - * set. - */ - boolean setCurrentTab(Tab newTab) { - Tab current = getTab(mCurrentTab); - if (current == newTab) { - return true; - } - if (current != null) { - // Remove the current WebView and the container of the subwindow - putTabInBackground(current); - } - - if (newTab == null) { - return false; - } - - // Move the newTab to the end of the queue - int index = mTabQueue.indexOf(newTab); - if (index != -1) { - mTabQueue.remove(index); - } - mTabQueue.add(newTab); - - WebView mainView; - WebView subView; - - // Display the new current tab - mCurrentTab = mTabs.indexOf(newTab); - mainView = newTab.mMainView; - boolean needRestore = (mainView == null); - if (needRestore) { - // Same work as in createNewTab() except don't do new Tab() - newTab.mMainView = mainView = new WebView(mActivity); - mainView.setMapTrackballToArrowKeys(false); // use t-ball directly - - // Add this WebView to the settings observer list and update the - // settings - final BrowserSettings s = BrowserSettings.getInstance(); - s.addObserver(mainView.getSettings()).update(s, null); - } - mainView.setWebViewClient(mActivity.getWebViewClient()); - mainView.setWebChromeClient(mActivity.getWebChromeClient()); - mainView.setOnCreateContextMenuListener(mActivity); - mainView.setDownloadListener(mActivity); - // Add the subwindow if it exists - if (newTab.mSubViewContainer != null) { - subView = newTab.mSubView; - subView.setWebViewClient(newTab.mSubViewClient); - subView.setWebChromeClient(newTab.mSubViewChromeClient); - subView.setOnCreateContextMenuListener(mActivity); - subView.setDownloadListener(mActivity); - } - if (needRestore) { - // Have to finish setCurrentTab work before calling restoreState - if (!restoreState(newTab.mSavedState, newTab)) { - mainView.loadUrl(BrowserSettings.getInstance().getHomePage()); - } - } - return true; - } - - /* - * Put the tab in the background using all the empty/background clients. - */ - private void putTabInBackground(Tab t) { - WebView mainView = t.mMainView; - // Set an empty callback so that default actions are not triggered. - mainView.setWebViewClient(mEmptyClient); - mainView.setWebChromeClient(mBackgroundChromeClient); - mainView.setOnCreateContextMenuListener(null); - // Leave the DownloadManager attached so that downloads can start in - // a non-active window. This can happen when going to a site that does - // a redirect after a period of time. The user could have switched to - // another tab while waiting for the download to start. - mainView.setDownloadListener(mActivity); - WebView subView = t.mSubView; - if (subView != null) { - // Set an empty callback so that default actions are not triggered. - subView.setWebViewClient(mEmptyClient); - subView.setWebChromeClient(mBackgroundChromeClient); - subView.setOnCreateContextMenuListener(null); - subView.setDownloadListener(mActivity); - } - } - - /* - * Dismiss the subwindow for the given tab. - */ - void dismissSubWindow(Tab t) { - if (t != null && t.mSubView != null) { - BrowserSettings.getInstance().deleteObserver( - t.mSubView.getSettings()); - t.mSubView.destroy(); - t.mSubView = null; - t.mSubViewContainer = null; - } - } - - /** - * Ensure that Tab t has a title, url, and favicon. - * @param t Tab to populate. - */ - /* package */ void populatePickerData(Tab t) { - if (t == null || t.mMainView == null) { - return; - } - // FIXME: The only place we cared about subwindow was for - // bookmarking (i.e. not when saving state). Was this deliberate? - final WebBackForwardList list = t.mMainView.copyBackForwardList(); - final WebHistoryItem item = - list != null ? list.getCurrentItem() : null; - populatePickerData(t, item); - } - - // Populate the picker data - private void populatePickerData(Tab t, WebHistoryItem item) { - if (item != null) { - t.mUrl = item.getUrl(); - t.mTitle = item.getTitle(); - if (t.mTitle == null) { - t.mTitle = t.mUrl; - } - } - } - - /** - * Clean up the data for all tabs. - */ - /* package */ void wipeAllPickerData() { - int size = getTabCount(); - for (int i = 0; i < size; i++) { - final Tab t = getTab(i); - if (t != null && t.mSavedState == null) { - t.mUrl = null; - t.mTitle = null; - } - } - } - - /* - * Save the state for an individual tab. - */ - private boolean saveState(Tab t) { - if (t != null) { - final WebView w = t.mMainView; - // If the WebView is null it means we ran low on memory and we - // already stored the saved state in mSavedState. - if (w == null) { - return true; - } - final Bundle b = new Bundle(); - final WebBackForwardList list = w.saveState(b); - if (list != null) { - final File f = new File(mThumbnailDir, w.hashCode() - + "_pic.save"); - if (w.savePicture(b, f)) { - b.putString("picture", f.getPath()); - } - } - - // Store some extra info for displaying the tab in the picker. - final WebHistoryItem item = - list != null ? list.getCurrentItem() : null; - populatePickerData(t, item); - if (t.mUrl != null) { - b.putString(CURRURL, t.mUrl); - } - if (t.mTitle != null) { - b.putString(CURRTITLE, t.mTitle); - } - b.putBoolean(CLOSEONEXIT, t.mCloseOnExit); - - // Remember the parent tab so the relationship can be restored. - if (t.mParentTab != null) { - b.putInt(PARENTTAB, getTabIndex(t.mParentTab)); - } - - // Remember the saved state. - t.mSavedState = b; - return true; - } - return false; - } - - /* - * Restore the state of the tab. - */ - private boolean restoreState(Bundle b, Tab t) { - if (b == null) { - return false; - } - final WebView w = t.mMainView; - final WebBackForwardList list = w.restoreState(b); - if (list == null) { - return false; - } - if (b.containsKey("picture")) { - final File f = new File(b.getString("picture")); - w.restorePicture(b, f); - f.delete(); - } - t.mSavedState = null; - t.mUrl = null; - t.mTitle = null; - t.mCloseOnExit = b.getBoolean(CLOSEONEXIT); - return true; - } -} |