OSDN Git Service

Treat voice searches from within the browser differently
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserActivity.java
index 55e5177..1f969af 100644 (file)
@@ -214,6 +214,8 @@ public class BrowserActivity extends Activity
                 .findViewById(R.id.fullscreen_custom_content);
         frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
         mTitleBar = new TitleBar(this);
+        // mTitleBar will be always shown in the fully loaded mode
+        mTitleBar.setProgress(100);
         mFakeTitleBar = new TitleBar(this);
 
         // Create the tab control and our initial tab
@@ -363,6 +365,11 @@ public class BrowserActivity extends Activity
         }
         // Work out which packages are installed on the system.
         getInstalledPackages();
+
+        // Start watching the default geolocation permissions
+        mSystemAllowGeolocationOrigins
+                = new SystemAllowGeolocationOrigins(getApplicationContext());
+        mSystemAllowGeolocationOrigins.start();
     }
 
     /**
@@ -407,6 +414,9 @@ public class BrowserActivity extends Activity
             // just resume the browser
             return;
         }
+        // In case the SearchDialog is open.
+        ((SearchManager) getSystemService(Context.SEARCH_SERVICE))
+                .stopSearch();
         boolean activateVoiceSearch = RecognizerResultsIntent
                 .ACTION_VOICE_SEARCH_RESULTS.equals(action);
         if (Intent.ACTION_VIEW.equals(action)
@@ -450,7 +460,10 @@ public class BrowserActivity extends Activity
 
             final String appId = intent
                     .getStringExtra(Browser.EXTRA_APPLICATION_ID);
-            if ((Intent.ACTION_VIEW.equals(action) || activateVoiceSearch)
+            if ((Intent.ACTION_VIEW.equals(action)
+                    // If a voice search has no appId, it means that it came
+                    // from the browser.  In that case, reuse the current tab.
+                    || (activateVoiceSearch && appId != null))
                     && !getPackageName().equals(appId)
                     && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
                 Tab appTab = mTabControl.getTabFromId(appId);
@@ -465,11 +478,7 @@ public class BrowserActivity extends Activity
                     // 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 there is a voice intent in the UrlData, then
-                            // recreateWebView may return false, but we still
-                            // need to force a load.
-                            || urlData.mVoiceIntent != null;
+                            mTabControl.recreateWebView(appTab, urlData);
 
                     if (current != appTab) {
                         switchToTab(mTabControl.getTabIndex(appTab));
@@ -596,8 +605,15 @@ public class BrowserActivity extends Activity
             return false;
         }
 
-        Browser.updateVisitedHistory(mResolver, url, false);
-        Browser.addSearchUrl(mResolver, url);
+        final ContentResolver cr = mResolver;
+        final String newUrl = url;
+        new AsyncTask<Void, Void, Void>() {
+            protected Void doInBackground(Void... unused) {
+                Browser.updateVisitedHistory(cr, newUrl, false);
+                Browser.addSearchUrl(cr, newUrl);
+                return null;
+            }
+        }.execute();
 
         Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
@@ -650,7 +666,14 @@ public class BrowserActivity extends Activity
                     // But currently, we get the user-typed URL from search box as well.
                     url = fixUrl(url);
                     url = smartUrlFilter(url);
-                    Browser.updateVisitedHistory(mResolver, url, false);
+                    final ContentResolver cr = mResolver;
+                    final String newUrl = url;
+                    new AsyncTask<Void, Void, Void>() {
+                        protected Void doInBackground(Void... unused) {
+                            Browser.updateVisitedHistory(cr, newUrl, false);
+                            return null;
+                        }
+                    }.execute();
                     String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&";
                     if (url.contains(searchSource)) {
                         String source = null;
@@ -746,19 +769,6 @@ public class BrowserActivity extends Activity
     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.MATCH_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.
      */
@@ -812,46 +822,12 @@ public class BrowserActivity extends Activity
         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.getParent() == 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");
-                }
+                && !mActivityInPause) {
+            WebView mainView = mTabControl.getCurrentWebView();
+            // if there is no current WebView, don't show the faked title bar;
+            if (mainView == null) {
                 return;
             }
 
@@ -864,28 +840,13 @@ public class BrowserActivity extends Activity
                     = new WindowManager.LayoutParams(
                     ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT,
-                    WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
+                    WindowManager.LayoutParams.TYPE_APPLICATION,
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                     PixelFormat.TRANSLUCENT);
             params.gravity = Gravity.TOP;
-            WebView mainView = mTabControl.getCurrentWebView();
-            boolean atTop = mainView != null && mainView.getScrollY() == 0;
+            boolean atTop = 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);
+            manager.addView(mFakeTitleBar, params);
         }
     }
 
@@ -905,7 +866,7 @@ public class BrowserActivity extends Activity
     private void hideFakeTitleBar() {
         if (mFakeTitleBar.getParent() == null) return;
         WindowManager.LayoutParams params = (WindowManager.LayoutParams)
-                mFakeTitleBarHolder.getLayoutParams();
+                mFakeTitleBar.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
@@ -915,9 +876,8 @@ public class BrowserActivity extends Activity
                 ? 0 : R.style.TitleBar;
         WindowManager manager
                     = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
-        manager.updateViewLayout(mFakeTitleBarHolder, params);
-        mFakeTitleBarHolder.removeView(mFakeTitleBar);
-        manager.removeView(mFakeTitleBarHolder);
+        manager.updateViewLayout(mFakeTitleBar, params);
+        manager.removeView(mFakeTitleBar);
     }
 
     /**
@@ -1020,6 +980,10 @@ public class BrowserActivity extends Activity
         WebIconDatabase.getInstance().close();
 
         unregisterReceiver(mPackageInstallationReceiver);
+
+        // Stop watching the default geolocation permissions
+        mSystemAllowGeolocationOrigins.stop();
+        mSystemAllowGeolocationOrigins = null;
     }
 
     @Override
@@ -1067,8 +1031,9 @@ public class BrowserActivity extends Activity
         mTabControl.freeMemory();
     }
 
-    private boolean resumeWebViewTimers() {
+    private void resumeWebViewTimers() {
         Tab tab = mTabControl.getCurrentTab();
+        if (tab == null) return; // monkey can trigger this
         boolean inLoad = tab.inLoad();
         if ((!mActivityInPause && !inLoad) || (mActivityInPause && inLoad)) {
             CookieSyncManager.getInstance().startSync();
@@ -1076,9 +1041,6 @@ public class BrowserActivity extends Activity
             if (w != null) {
                 w.resumeTimers();
             }
-            return true;
-        } else {
-            return false;
         }
     }
 
@@ -2421,7 +2383,7 @@ public class BrowserActivity extends Activity
             return null;
         }
         Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(this),
-                getDesiredThumbnailHeight(this), Bitmap.Config.ARGB_4444);
+                getDesiredThumbnailHeight(this), Bitmap.Config.RGB_565);
         Canvas canvas = new Canvas(bm);
         // May need to tweak these values to determine what is the
         // best scale factor
@@ -2663,7 +2625,6 @@ public class BrowserActivity extends Activity
     // -------------------------------------------------------------------------
 
     void onProgressChanged(WebView view, int newProgress) {
-        mTitleBar.setProgress(newProgress);
         mFakeTitleBar.setProgress(newProgress);
 
         if (newProgress == 100) {
@@ -2830,6 +2791,36 @@ public class BrowserActivity extends Activity
         onDownloadStartNoStream(url, userAgent, contentDisposition, mimetype, contentLength);
     }
 
+    // This is to work around the fact that java.net.URI throws Exceptions
+    // instead of just encoding URL's properly
+    // Helper method for onDownloadStartNoStream
+    private static String encodePath(String path) {
+        char[] chars = path.toCharArray();
+
+        boolean needed = false;
+        for (char c : chars) {
+            if (c == '[' || c == ']') {
+                needed = true;
+                break;
+            }
+        }
+        if (needed == false) {
+            return path;
+        }
+
+        StringBuilder sb = new StringBuilder("");
+        for (char c : chars) {
+            if (c == '[' || c == ']') {
+                sb.append('%');
+                sb.append(Integer.toHexString(c));
+            } else {
+                sb.append(c);
+            }
+        }
+
+        return sb.toString();
+    }
+
     /**
      * Notify the host application a download should be done, even if there
      * is a streaming viewer available for thise type.
@@ -2869,35 +2860,16 @@ public class BrowserActivity extends Activity
             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;
+        // java.net.URI is a lot stricter than KURL so we have to encode some
+        // extra characters. Fix for b 2538060 and b 1634719
+        WebAddress webAddress;
         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);
+            webAddress = new WebAddress(url);
+            webAddress.mPath = encodePath(webAddress.mPath);
         } catch (Exception e) {
-            Log.e(LOGTAG, "Could not parse url for download: " + url, e);
+            // This only happens for very bad urls, we want to chatch the
+            // exception here
+            Log.e(LOGTAG, "Exception trying to parse url:" + url);
             return;
         }
 
@@ -2906,7 +2878,7 @@ public class BrowserActivity extends Activity
         String cookies = CookieManager.getInstance().getCookie(url);
 
         ContentValues values = new ContentValues();
-        values.put(Downloads.Impl.COLUMN_URI, uri.toString());
+        values.put(Downloads.Impl.COLUMN_URI, webAddress.toString());
         values.put(Downloads.Impl.COLUMN_COOKIE_DATA, cookies);
         values.put(Downloads.Impl.COLUMN_USER_AGENT, userAgent);
         values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
@@ -2917,7 +2889,7 @@ public class BrowserActivity extends Activity
                 Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
         values.put(Downloads.Impl.COLUMN_MIME_TYPE, mimetype);
         values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, filename);
-        values.put(Downloads.Impl.COLUMN_DESCRIPTION, uri.getHost());
+        values.put(Downloads.Impl.COLUMN_DESCRIPTION, webAddress.mHost);
         if (contentLength > 0) {
             values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, contentLength);
         }
@@ -2929,7 +2901,8 @@ public class BrowserActivity extends Activity
             final Uri contentUri =
                     getContentResolver().insert(Downloads.Impl.CONTENT_URI, values);
         }
-
+        Toast.makeText(this, R.string.download_pending, Toast.LENGTH_SHORT)
+                .show();
     }
 
     // -------------------------------------------------------------------------
@@ -3395,7 +3368,7 @@ public class BrowserActivity extends Activity
     public void setHttpAuthUsernamePassword(String host, String realm,
                                             String username,
                                             String password) {
-        WebView w = mTabControl.getCurrentWebView();
+        WebView w = getTopWindow();
         if (w != null) {
             w.setHttpAuthUsernamePassword(host, realm, username, password);
         }
@@ -3788,7 +3761,7 @@ public class BrowserActivity extends Activity
     private boolean mIsNetworkUp;
     private boolean mDidStopLoad;
 
-    private boolean mActivityInPause = true;
+    /* package */ boolean mActivityInPause = true;
 
     private boolean mMenuIsDown;
 
@@ -3911,6 +3884,8 @@ public class BrowserActivity extends Activity
 
     private BroadcastReceiver mPackageInstallationReceiver;
 
+    private SystemAllowGeolocationOrigins mSystemAllowGeolocationOrigins;
+
     // activity requestCode
     final static int COMBO_PAGE                 = 1;
     final static int DOWNLOAD_PAGE              = 2;
@@ -3934,7 +3909,7 @@ public class BrowserActivity extends Activity
      * A UrlData class to abstract how the content will be set to WebView.
      * This base class uses loadUrl to show the content.
      */
-    private static class UrlData {
+    /* package */ static class UrlData {
         final String mUrl;
         final Map<String, String> mHeaders;
         final Intent mVoiceIntent;