/WebVox/src/com/marvin/webvox/BrowserActivity.java
http://eyes-free.googlecode.com/ · Java · 1668 lines · 1094 code · 158 blank · 416 comment · 277 complexity · 7061e778ccf953fd7c2ebe0b8df697e4 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * 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.marvin.webvox;
- import com.marvin.webvox.R;
- //import com.google.android.googleapps.IGoogleLoginService;
- //import com.google.android.googlelogin.GoogleLoginServiceConstants;
- import android.app.Activity;
- 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.ContentUris;
- 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.PackageInfo;
- 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.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.DrawFilter;
- import android.graphics.Paint;
- import android.graphics.PaintFlagsDrawFilter;
- import android.graphics.Picture;
- import android.graphics.PixelFormat;
- import android.graphics.Rect;
- import android.graphics.drawable.Drawable;
- import android.hardware.SensorListener;
- import android.hardware.SensorManager;
- import android.net.ConnectivityManager;
- import android.net.NetworkInfo;
- 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.provider.Browser;
- import android.provider.ContactsContract;
- import android.provider.ContactsContract.Intents.Insert;
- //import android.provider.Downloads;
- import android.provider.MediaStore;
- //import android.text.IClipboard;
- import android.speech.tts.TextToSpeech;
- import android.text.TextUtils;
- import android.text.format.DateFormat;
- //import android.text.util.Regex;
- import android.util.AttributeSet;
- 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.GeolocationPermissions;
- import android.webkit.HttpAuthHandler;
- //import android.webkit.PluginManager;
- import android.webkit.SslErrorHandler;
- import android.webkit.URLUtil;
- //import android.webkit.ValueCallback;
- import android.webkit.WebChromeClient;
- //import android.webkit.WebChromeClient.CustomViewCallback;
- import android.webkit.WebHistoryItem;
- import android.webkit.WebIconDatabase;
- import android.webkit.WebStorage;
- 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.ByteArrayOutputStream;
- 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.URISyntaxException;
- 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.LinkedList;
- import java.util.List;
- 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 View.OnCreateContextMenuListener,
- DownloadListener {
- /* Define some aliases to make these debugging flags easier to refer to.
- * This file imports android.provider.Browser, so we can't just refer to "Browser.DEBUG".
- */
- private final static boolean DEBUG = com.marvin.webvox.Browser.DEBUG;
- private final static boolean LOGV_ENABLED = com.marvin.webvox.Browser.LOGV_ENABLED;
- private final static boolean LOGD_ENABLED = com.marvin.webvox.Browser.LOGD_ENABLED;
- // private IGoogleLoginService mGls = null;
- private ServiceConnection mGlsConnection = null;
- private SensorManager mSensorManager = null;
- // These are single-character shortcuts for searching popular sources.
- private static final int SHORTCUT_INVALID = 0;
- private static final int SHORTCUT_GOOGLE_SEARCH = 1;
- private static final int SHORTCUT_WIKIPEDIA_SEARCH = 2;
- private static final int SHORTCUT_DICTIONARY_SEARCH = 3;
- private static final int SHORTCUT_GOOGLE_MOBILE_LOCAL_SEARCH = 4;
- /* 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;
- if (!homepage.startsWith("http://www.google.")) return;
- if (homepage.indexOf('?') == -1) 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 = homepage.replace("?", "/a/" + domain + "?");
- // }
- // } 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);
- }
- private static class ClearThumbnails extends AsyncTask<File, Void, Void> {
- @Override
- public Void doInBackground(File... files) {
- if (files != null) {
- for (File f : files) {
- if (!f.delete()) {
- Log.e(LOGTAG, f.getPath() + " was not deleted");
- }
- }
- }
- return null;
- }
- }
- /**
- * This layout holds everything you see below the status bar, including the
- * error console, the custom view container, and the webviews.
- */
- private FrameLayout mBrowserFrameLayout;
- @Override public void onCreate(Bundle icicle) {
- mTts = new TextToSpeech(this, null);
- scriptdb = new ScriptDatabase(this);
- scriptdb.onUpgrade(scriptdb.getWritableDatabase(), -10, 10);
-
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, this + " onStart");
- }
- super.onCreate(icicle);
- // test the browser in OpenGL
- // requestWindowFeature(Window.FEATURE_OPENGL);
- setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
- mResolver = getContentResolver();
- // If this was a web search request, pass it on to the default web
- // search provider and finish this activity.
- if (handleWebSearchIntent(getIntent())) {
- finish();
- return;
- }
- //
- // 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);
- // FrameLayout frameLayout = (FrameLayout) getWindow().getDecorView()
- // .findViewById(com.android.internal.R.id.content);
-
-
- mBrowserFrameLayout = (FrameLayout) LayoutInflater.from(this)
- .inflate(R.layout.custom_screen, null);
- mContentView = (FrameLayout) mBrowserFrameLayout.findViewById(
- R.id.main_content);
- mErrorConsoleContainer = (LinearLayout) mBrowserFrameLayout
- .findViewById(R.id.error_console);
- mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
- .findViewById(R.id.fullscreen_custom_content);
- //frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
-
- setContentView(mBrowserFrameLayout);
-
- mTitleBar = new TitleBar(this);
- // Create the tab control and our initial tab
- mTabControl = new TabControl(this);
- // Open the icon database and retain all the bookmark urls for favicons
- retainIconsOnStartup();
- // 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");
- /* 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 noConnectivity = intent.getBooleanExtra(
- ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- onNetworkToggle(!noConnectivity);
- }
- }
- };
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mPackageInstallationReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final String packageName = intent.getData()
- .getSchemeSpecificPart();
- final boolean replacing = intent.getBooleanExtra(
- Intent.EXTRA_REPLACING, false);
- if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
- // if it is replacing, refreshPlugins() when adding
- return;
- }
- PackageManager pm = BrowserActivity.this.getPackageManager();
- PackageInfo pkgInfo = null;
- try {
- pkgInfo = pm.getPackageInfo(packageName,
- PackageManager.GET_PERMISSIONS);
- } catch (PackageManager.NameNotFoundException e) {
- return;
- }
- if (pkgInfo != null) {
- String permissions[] = pkgInfo.requestedPermissions;
- if (permissions == null) {
- return;
- }
- boolean permissionOk = false;
- /*
- for (String permit : permissions) {
- if (PluginManager.PLUGIN_PERMISSION.equals(permit)) {
- permissionOk = true;
- break;
- }
- }
- if (permissionOk) {
- PluginManager.getInstance(BrowserActivity.this)
- .refreshPlugins(
- Intent.ACTION_PACKAGE_ADDED
- .equals(action));
- }
- */
- }
- }
- };
- registerReceiver(mPackageInstallationReceiver, filter);
- 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());
- // there is no quit on Android. But if we can't restore the state,
- // we can treat it as a new Browser, remove the old session cookies.
- CookieManager.getInstance().removeSessionCookie();
- 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.
- UrlData urlData = getUrlDataFromIntent(intent);
- final TabControl.Tab t = mTabControl.createNewTab(
- Intent.ACTION_VIEW.equals(intent.getAction()) &&
- intent.getData() != null,
- intent.getStringExtra(Browser.EXTRA_APPLICATION_ID), urlData.mUrl);
- mTabControl.setCurrentTab(t);
- 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();
- }
- if (urlData.isEmpty()) {
- if (mSettings.isLoginInitialized()) {
- webView.loadUrl(mSettings.getHomePage());
- } else {
- waitForCredentials();
- }
- } else {
- if (extra != null) {
- // urlData.setPostData(extra
- // .getByteArray(Browser.EXTRA_POST_DATA));
- }
- urlData.loadIn(webView);
- }
- } else {
- // TabControl.restoreState() will create a new tab even if
- // restoring the state fails.
- attachTabToContentView(mTabControl.getCurrentTab());
- }
- // Read JavaScript flags if it exists.
- String jsFlags = mSettings.getJsFlags();
- if (jsFlags.trim().length() != 0) {
- // mTabControl.getCurrentWebView().setJsFlags(jsFlags);
- }
- }
- @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)) {
- // If this was a search request (e.g. search query directly typed into the address bar),
- // pass it on to the default web search provider.
- if (handleWebSearchIntent(intent)) {
- return;
- }
- UrlData urlData = getUrlDataFromIntent(intent);
- if (urlData.isEmpty()) {
- urlData = new UrlData(mSettings.getHomePage());
- }
- // urlData.setPostData(intent
- // .getByteArrayExtra(Browser.EXTRA_POST_DATA));
- final String appId = intent
- .getStringExtra(Browser.EXTRA_APPLICATION_ID);
- if (Intent.ACTION_VIEW.equals(action)
- && !getPackageName().equals(appId)
- && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
- TabControl.Tab appTab = mTabControl.getTabFromId(appId);
- if (appTab != null) {
- Log.i(LOGTAG, "Reusing tab for " + appId);
- // Dismiss the subwindow if applicable.
- dismissSubWindow(appTab);
- // Since we might kill the WebView, remove it from the
- // content view first.
- removeTabFromContentView(appTab);
- // Recreate the main WebView after destroying the old one.
- // If the WebView has the same original url and is on that
- // page, it can be reused.
- boolean needsLoad =
- mTabControl.recreateWebView(appTab, urlData.mUrl);
- if (current != appTab) {
- switchToTab(mTabControl.getTabIndex(appTab));
- if (needsLoad) {
- urlData.loadIn(appTab.getWebView());
- }
- } else {
- // If the tab was the current tab, we have to attach
- // it to the view system again.
- attachTabToContentView(appTab);
- if (needsLoad) {
- urlData.loadIn(appTab.getWebView());
- }
- }
- return;
- } else {
- // No matching application tab, try to find a regular tab
- // with a matching url.
- appTab = mTabControl.findUnusedTabWithUrl(urlData.mUrl);
- if (appTab != null) {
- if (current != appTab) {
- switchToTab(mTabControl.getTabIndex(appTab));
- }
- // Otherwise, we are already viewing the correct tab.
- } else {
- // 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(urlData, true, appId);
- }
- }
- } else {
- if ("about:debug".equals(urlData.mUrl)) {
- mSettings.toggleDebugSettings();
- return;
- }
- // Get rid of the subwindow if it exists
- dismissSubWindow(current);
- urlData.loadIn(current.getWebView());
- }
- }
- }
- private int parseUrlShortcut(String url) {
- if (url == null) return SHORTCUT_INVALID;
- // FIXME: quick search, need to be customized by setting
- if (url.length() > 2 && url.charAt(1) == ' ') {
- switch (url.charAt(0)) {
- case 'g': return SHORTCUT_GOOGLE_SEARCH;
- case 'w': return SHORTCUT_WIKIPEDIA_SEARCH;
- case 'd': return SHORTCUT_DICTIONARY_SEARCH;
- case 'l': return SHORTCUT_GOOGLE_MOBILE_LOCAL_SEARCH;
- }
- }
- return SHORTCUT_INVALID;
- }
- /**
- * Launches the default web search activity with the query parameters if the given intent's data
- * are identified as plain search terms and not URLs/shortcuts.
- * @return true if the intent was handled and web search activity was launched, false if not.
- */
- private boolean handleWebSearchIntent(Intent intent) {
- if (intent == null) return false;
- String url = null;
- final String action = intent.getAction();
- if (Intent.ACTION_VIEW.equals(action)) {
- Uri data = intent.getData();
- if (data != null) url = data.toString();
- } 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);
- }
- return handleWebSearchRequest(url, intent.getBundleExtra(SearchManager.APP_DATA),
- intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
- }
- /**
- * Launches the default web search activity with the query parameters if the given url string
- * was identified as plain search terms and not URL/shortcut.
- * @return true if the request was handled and web search activity was launched, false if not.
- */
- private boolean handleWebSearchRequest(String inUrl, Bundle appData, String extraData) {
- if (inUrl == null) return false;
- // In general, we shouldn't modify URL from Intent.
- // But currently, we get the user-typed URL from search box as well.
- String url = fixUrl(inUrl).trim();
- // URLs and site specific search shortcuts are handled by the regular flow of control, so
- // return early.
- // if (Regex.WEB_URL_PATTERN.matcher(url).matches() ||
- if ( ACCEPTED_URI_SCHEMA.matcher(url).matches()
- || parseUrlShortcut(url) != SHORTCUT_INVALID) {
- return false;
- }
- Browser.updateVisitedHistory(mResolver, url, false);
- Browser.addSearchUrl(mResolver, url);
- Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.putExtra(SearchManager.QUERY, url);
- if (appData != null) {
- intent.putExtra(SearchManager.APP_DATA, appData);
- }
- if (extraData != null) {
- intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
- }
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName());
- startActivity(intent);
- return true;
- }
- private UrlData getUrlDataFromIntent(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;
- }
- }
- // if ("inline:".equals(url)) {
- // return new InlinedUrlData(
- // intent.getStringExtra(Browser.EXTRA_INLINE_CONTENT),
- // intent.getType(),
- // intent.getStringExtra(Browser.EXTRA_INLINE_ENCODING),
- // intent.getStringExtra(Browser.EXTRA_INLINE_FAILURL));
- // }
- } 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 new UrlData(url);
- }
- /* package */ static String fixUrl(String inUrl) {
- // FIXME: Converting the url to lower case
- // duplicates functionality in smartUrlFilter().
- // However, changing all current callers of fixUrl to
- // call smartUrlFilter in addition may have unwanted
- // consequences, and is deferred for now.
- int colon = inUrl.indexOf(':');
- boolean allLower = true;
- for (int index = 0; index < colon; index++) {
- char ch = inUrl.charAt(index);
- if (!Character.isLetter(ch)) {
- break;
- }
- allLower &= Character.isLowerCase(ch);
- if (index == colon - 1 && !allLower) {
- inUrl = inUrl.substring(0, colon).toLowerCase()
- + inUrl.substring(colon);
- }
- }
- 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 (LOGV_ENABLED) {
- Log.v(LOGTAG, "BrowserActivity.onResume: this=" + this);
- }
- if (!mActivityInPause) {
- Log.e(LOGTAG, "BrowserActivity is already resumed.");
- return;
- }
- mTabControl.resumeCurrentTab();
- mActivityInPause = false;
- resumeWebViewTimers();
- 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;
- }
- }
- /**
- * Since the actual title bar is embedded in the WebView, and removing it
- * would change its appearance, create a temporary title bar to go at
- * the top of the screen while the menu is open.
- */
- private TitleBar mFakeTitleBar;
- /**
- * Holder for the fake title bar. It will have a foreground shadow, as well
- * as a white background, so the fake title bar looks like the real one.
- */
- private ViewGroup mFakeTitleBarHolder;
- /**
- * Layout parameters for the fake title bar within mFakeTitleBarHolder
- */
- private FrameLayout.LayoutParams mFakeTitleBarParams
- = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- /**
- * Keeps track of whether the options menu is open. This is important in
- * determining whether to show or hide the title bar overlay.
- */
- private boolean mOptionsMenuOpen;
- /**
- * Only meaningful when mOptionsMenuOpen is true. This variable keeps track
- * of whether the configuration has changed. The first onMenuOpened call
- * after a configuration change is simply a reopening of the same menu
- * (i.e. mIconView did not change).
- */
- private boolean mConfigChanged;
- /**
- * Whether or not the options menu is in its smaller, icon menu form. When
- * true, we want the title bar overlay to be up. When false, we do not.
- * Only meaningful if mOptionsMenuOpen is true.
- */
- private boolean mIconView;
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- if (Window.FEATURE_OPTIONS_PANEL == featureId) {
- if (mOptionsMenuOpen) {
- if (mConfigChanged) {
- // We do not need to make any changes to the state of the
- // title bar, since the only thing that happened was a
- // change in orientation
- mConfigChanged = false;
- } else {
- if (mIconView) {
- // Switching the menu to expanded view, so hide the
- // title bar.
- hideFakeTitleBar();
- mIconView = false;
- } else {
- // Switching the menu back to icon view, so show the
- // title bar once again.
- showFakeTitleBar();
- mIconView = true;
- }
- }
- } else {
- // The options menu is closed, so open it, and show the title
- showFakeTitleBar();
- mOptionsMenuOpen = true;
- mConfigChanged = false;
- mIconView = true;
- }
- }
- return true;
- }
- /**
- * Special class used exclusively for the shadow drawn underneath the fake
- * title bar. The shadow does not need to be drawn if the WebView
- * underneath is scrolled to the top, because it will draw directly on top
- * of the embedded shadow.
- */
- private static class Shadow extends View {
- private WebView mWebView;
- public Shadow(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public void setWebView(WebView view) {
- mWebView = view;
- }
- @Override
- public void draw(Canvas canvas) {
- // In general onDraw is the method to override, but we care about
- // whether or not the background gets drawn, which happens in draw()
- if (mWebView == null || mWebView.getScrollY() > getHeight()) {
- super.draw(canvas);
- }
- // Need to invalidate so that if the scroll position changes, we
- // still draw as appropriate.
- invalidate();
- }
- }
- private void showFakeTitleBar() {
- final View decor = getWindow().peekDecorView();
- if (mFakeTitleBar == null && mActiveTabsPage == null
- && !mActivityInPause && decor != null
- && decor.getWindowToken() != null) {
- Rect visRect = new Rect();
- if (!mBrowserFrameLayout.getGlobalVisibleRect(visRect)) {
- if (LOGD_ENABLED) {
- Log.d(LOGTAG, "showFakeTitleBar visRect failed");
- }
- return;
- }
- final WebView webView = getTopWindow();
- mFakeTitleBar = new TitleBar(this);
- mFakeTitleBar.setTitleAndUrl(null, webView.getUrl());
- mFakeTitleBar.setProgress(webView.getProgress());
- mFakeTitleBar.setFavicon(webView.getFavicon());
- updateLockIconToLatest();
- WindowManager manager
- = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- // Add the title bar to the window manager so it can receive touches
- // while the menu is up
- WindowManager.LayoutParams params
- = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSLUCENT);
- params.gravity = Gravity.TOP;
- WebView mainView = mTabControl.getCurrentWebView();
- boolean atTop = mainView != null && mainView.getScrollY() == 0;
- params.windowAnimations = atTop ? 0 : R.style.TitleBar;
- // XXX : Without providing an offset, the fake title bar will be
- // placed underneath the status bar. Use the global visible rect
- // of mBrowserFrameLayout to determine the bottom of the status bar
- params.y = visRect.top;
- // Add a holder for the title bar. It also holds a shadow to show
- // below the title bar.
- if (mFakeTitleBarHolder == null) {
- mFakeTitleBarHolder = (ViewGroup) LayoutInflater.from(this)
- .inflate(R.layout.title_bar_bg, null);
- }
- Shadow shadow = (Shadow) mFakeTitleBarHolder.findViewById(
- R.id.shadow);
- shadow.setWebView(mainView);
- mFakeTitleBarHolder.addView(mFakeTitleBar, 0, mFakeTitleBarParams);
- manager.addView(mFakeTitleBarHolder, params);
- }
- }
- @Override
- public void onOptionsMenuClosed(Menu menu) {
- mOptionsMenuOpen = false;
- if (!mInLoad) {
- hideFakeTitleBar();
- } else if (!mIconView) {
- // The page is currently loading, and we are in expanded mode, so
- // we were not showing the menu. Show it once again. It will be
- // removed when the page finishes.
- showFakeTitleBar();
- }
- }
- private void hideFakeTitleBar() {
- if (mFakeTitleBar == null) return;
- WindowManager.LayoutParams params = (WindowManager.LayoutParams)
- mFakeTitleBarHolder.getLayoutParams();
- WebView mainView = mTabControl.getCurrentWebView();
- // Although we decided whether or not to animate based on the current
- // scroll position, the scroll position may have changed since the
- // fake title bar was displayed. Make sure it has the appropriate
- // animation/lack thereof before removing.
- params.windowAnimations = mainView != null && mainView.getScrollY() == 0
- ? 0 : R.style.TitleBar;
- WindowManager manager
- = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- manager.updateViewLayout(mFakeTitleBarHolder, params);
- mFakeTitleBarHolder.removeView(mFakeTitleBar);
- manager.removeView(mFakeTitleBarHolder);
- mFakeTitleBar = null;
- }
- /**
- * Special method for the fake title bar to call when displaying its context
- * menu, since it is in its own Window, and its parent does not show a
- * context menu.
- */
- /* package */ void showTitleBarContextMenu() {
- if (null == mTitleBar.getParent()) {
- return;
- }
- openContextMenu(mTitleBar);
- }
- /**
- * onSaveInstanceState(Bundle map)
- * onSaveInstanceState is called right before onStop(). The map contains
- * the saved state.
- */
- @Override protected void onSaveInstanceState(Bundle outState) {
- if (LOGV_ENABLED) {
- 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;
- }
- mTabControl.pauseCurrentTab();
- mActivityInPause = true;
- if (mTabControl.getCurrentIndex() >= 0 && !pauseWebViewTimers()) {
- 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;
- // FIXME: This removes the active tabs page and resets the menu to
- // MAIN_MENU. A better solution might be to do this work in onNewIntent
- // but then we would need to save it in onSaveInstanceState and restore
- // it in onCreate/onRestoreInstanceState
- if (mActiveTabsPage != null) {
- removeActiveTabPage(true);
- }
- cancelStopToast();
- // unregister network state listener
- unregisterReceiver(mNetworkStateIntentReceiver);
- WebView.disablePlatformNotifications();
- if (mSensorManager != null) {
- mSensorManager.unregisterListener(mSensorListener);
- }
- }
- @Override protected void onDestroy() {
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "BrowserActivity.onDestroy: this=" + this);
- }
- super.onDestroy();
- if (mTabControl == null) return;
- // Remove the current tab and sub window
- TabControl.Tab t = mTabControl.getCurrentTab();
- if (t != null) {
- 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);
- unregisterReceiver(mPackageInstallationReceiver);
- }
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- mConfigChanged = true;
- 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 = "";
- // 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();…