OSDN Git Service

don't create the fake title bar when getGlobalVisible fails
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserActivity.java
index ff8a589..15f986e 100644 (file)
@@ -84,6 +84,7 @@ import android.text.IClipboard;
 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;
@@ -305,6 +306,13 @@ public class BrowserActivity extends Activity
 
         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
         //
@@ -412,12 +420,6 @@ public class BrowserActivity extends Activity
         };
         registerReceiver(mPackageInstallationReceiver, filter);
 
-        // If this was a web search request, pass it on to the default web search provider.
-        if (handleWebSearchIntent(getIntent())) {
-            moveTaskToBack(true);
-            return;
-        }
-
         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.
@@ -953,11 +955,48 @@ 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 == 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());
@@ -985,15 +1024,16 @@ public class BrowserActivity extends Activity
             // 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
-            Rect rectangle = new Rect();
-            mBrowserFrameLayout.getGlobalVisibleRect(rectangle);
-            params.y = rectangle.top;
+            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);
         }
@@ -1013,14 +1053,36 @@ public class BrowserActivity extends Activity
     }
     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 : com.android.internal.R.style.Animation_DropDownDown;
         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.
@@ -1085,6 +1147,9 @@ public class BrowserActivity extends Activity
             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) {
@@ -1297,15 +1362,20 @@ public class BrowserActivity extends Activity
         // options selector, so set mCanChord to true so we can access them.
         mCanChord = true;
         int id = item.getItemId();
-        final WebView webView = getTopWindow();
-        if (null == webView) {
-            return false;
-        }
-        final HashMap hrefMap = new HashMap();
-        hrefMap.put("webview", webView);
-        final Message msg = mHandler.obtainMessage(
-                FOCUS_NODE_HREF, id, 0, hrefMap);
         switch (id) {
+            // For the context menu from the title bar
+            case R.id.title_bar_share_page_url:
+            case R.id.title_bar_copy_page_url:
+                WebView mainView = mTabControl.getCurrentWebView();
+                if (null == mainView) {
+                    return false;
+                }
+                if (id == R.id.title_bar_share_page_url) {
+                    Browser.sendString(this, mainView.getUrl());
+                } else {
+                    copy(mainView.getUrl());
+                }
+                break;
             // -- Browser context menu
             case R.id.open_context_menu_id:
             case R.id.open_newtab_context_menu_id:
@@ -1313,6 +1383,14 @@ public class BrowserActivity extends Activity
             case R.id.save_link_context_menu_id:
             case R.id.share_link_context_menu_id:
             case R.id.copy_link_context_menu_id:
+                final WebView webView = getTopWindow();
+                if (null == webView) {
+                    return false;
+                }
+                final HashMap hrefMap = new HashMap();
+                hrefMap.put("webview", webView);
+                final Message msg = mHandler.obtainMessage(
+                        FOCUS_NODE_HREF, id, 0, hrefMap);
                 webView.requestFocusNodeHref(msg);
                 break;
 
@@ -1451,6 +1529,10 @@ public class BrowserActivity extends Activity
                 break;
 
             case R.id.goto_menu_id:
+                onSearchRequested();
+                break;
+
+            case R.id.bookmarks_menu_id:
                 bookmarksOrHistoryPicker(false);
                 break;
 
@@ -1534,7 +1616,8 @@ public class BrowserActivity extends Activity
                 break;
 
             case R.id.share_page_menu_id:
-                Browser.sendString(this, getTopWindow().getUrl());
+                Browser.sendString(this, getTopWindow().getUrl(),
+                        getText(R.string.choosertitle_sharevia).toString());
                 break;
 
             case R.id.dump_nav_menu_id:
@@ -2085,6 +2168,7 @@ public class BrowserActivity extends Activity
              * moveTaskToBack().
              */
             moveTaskToBack(true);
+            return;
         }
         WebView w = current.getWebView();
         if (w.canGoBack()) {
@@ -2204,6 +2288,7 @@ public class BrowserActivity extends Activity
     }
 
     /* package */ void stopLoading() {
+        mDidStopLoad = true;
         resetTitleAndRevertLockIcon();
         WebView w = getTopWindow();
         w.stopLoading();
@@ -2236,12 +2321,15 @@ public class BrowserActivity extends Activity
     private static final int CANCEL_CREDS_REQUEST    = 103;
     private static final int RELEASE_WAKELOCK        = 107;
 
+    private static final int UPDATE_BOOKMARK_THUMBNAIL = 108;
+
     // Private handler for handling javascript and saving passwords
     private Handler mHandler = new Handler() {
 
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case FOCUS_NODE_HREF:
+                {
                     String url = (String) msg.getData().get("url");
                     if (url == null || url.length() == 0) {
                         break;
@@ -2272,7 +2360,8 @@ public class BrowserActivity extends Activity
                             startActivity(intent);
                             break;
                         case R.id.share_link_context_menu_id:
-                            Browser.sendString(BrowserActivity.this, url);
+                            Browser.sendString(BrowserActivity.this, url,
+                                    getText(R.string.choosertitle_sharevia).toString());
                             break;
                         case R.id.copy_link_context_menu_id:
                             copy(url);
@@ -2283,6 +2372,7 @@ public class BrowserActivity extends Activity
                             break;
                     }
                     break;
+                }
 
                 case LOAD_URL:
                     loadURL(getTopWindow(), (String) msg.obj);
@@ -2301,6 +2391,13 @@ public class BrowserActivity extends Activity
                         mWakeLock.release();
                     }
                     break;
+
+                case UPDATE_BOOKMARK_THUMBNAIL:
+                    WebView view = (WebView) msg.obj;
+                    if (view != null) {
+                        updateScreenshot(view);
+                    }
+                    break;
             }
         }
     };
@@ -2311,9 +2408,10 @@ public class BrowserActivity extends Activity
         // FIXME: Would like to make sure there is actually something to
         // draw, but the API for that (WebViewCore.pictureReady()) is not
         // currently accessible here.
+
         ContentResolver cr = getContentResolver();
         final Cursor c = BrowserBookmarksAdapter.queryBookmarksForUrl(
-                cr, view.getOriginalUrl(), view.getUrl(), false);
+                cr, view.getOriginalUrl(), view.getUrl(), true);
         if (c != null) {
             boolean succeed = c.moveToFirst();
             ContentValues values = null;
@@ -2336,21 +2434,51 @@ public class BrowserActivity extends Activity
     }
 
     /**
-     * Constants for the size of the thumbnail created when taking a screenshot
+     * Values for the size of the thumbnail created when taking a screenshot.
+     * Lazily initialized.  Instead of using these directly, use
+     * getDesiredThumbnailWidth() or getDesiredThumbnailHeight().
+     */
+    private static int THUMBNAIL_WIDTH = 0;
+    private static int THUMBNAIL_HEIGHT = 0;
+
+    /**
+     * Return the desired width for thumbnail screenshots, which are stored in
+     * the database, and used on the bookmarks screen.
+     * @param context Context for finding out the density of the screen.
+     * @return int desired width for thumbnail screenshot.
+     */
+    /* package */ static int getDesiredThumbnailWidth(Context context) {
+        if (THUMBNAIL_WIDTH == 0) {
+            float density = context.getResources().getDisplayMetrics().density;
+            THUMBNAIL_WIDTH = (int) (90 * density);
+            THUMBNAIL_HEIGHT = (int) (80 * density);
+        }
+        return THUMBNAIL_WIDTH;
+    }
+
+    /**
+     * Return the desired height for thumbnail screenshots, which are stored in
+     * the database, and used on the bookmarks screen.
+     * @param context Context for finding out the density of the screen.
+     * @return int desired height for thumbnail screenshot.
      */
-    /* package */ static final int THUMBNAIL_WIDTH = 130;
-    /* package */ static final int THUMBNAIL_HEIGHT = 104;
+    /* package */ static int getDesiredThumbnailHeight(Context context) {
+        // To ensure that they are both initialized.
+        getDesiredThumbnailWidth(context);
+        return THUMBNAIL_HEIGHT;
+    }
 
     private Bitmap createScreenshot(WebView view) {
         Picture thumbnail = view.capturePicture();
-        Bitmap bm = Bitmap.createBitmap(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT,
-                Bitmap.Config.ARGB_4444);
+        Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(this),
+                getDesiredThumbnailHeight(this), Bitmap.Config.ARGB_4444);
         Canvas canvas = new Canvas(bm);
         // May need to tweak these values to determine what is the
         // best scale factor
-        int contentWidth = view.getContentWidth();
-        if (contentWidth > 0) {
-            float scaleFactor = (float) THUMBNAIL_WIDTH / (float) contentWidth;
+        int thumbnailWidth = thumbnail.getWidth();
+        if (thumbnailWidth > 0) {
+            float scaleFactor = (float) getDesiredThumbnailWidth(this) /
+                    (float)thumbnailWidth;
             canvas.scale(scaleFactor, scaleFactor);
         }
         thumbnail.draw(canvas);
@@ -2393,6 +2521,12 @@ public class BrowserActivity extends Activity
             resetLockIcon(url);
             setUrlTitle(url, null);
 
+            // We've started to load a new page. If there was a pending message
+            // to save a screenshot then we will now take the new page and
+            // save an incorrect screenshot. Therefore, remove any pending
+            // thumbnail messages from the queue.
+            mHandler.removeMessages(UPDATE_BOOKMARK_THUMBNAIL);
+
             // If we start a touch icon load and then load a new page, we don't
             // want to cancel the current touch icon loader. But, we do want to
             // create a new one when the touch icon url is known.
@@ -2453,6 +2587,7 @@ public class BrowserActivity extends Activity
             CookieSyncManager.getInstance().resetSync();
 
             mInLoad = true;
+            mDidStopLoad = false;
             showFakeTitleBar();
             updateInLoadMenuItems();
             if (!mIsNetworkUp) {
@@ -2469,9 +2604,15 @@ public class BrowserActivity extends Activity
             // load.
             resetTitleAndIcon(view);
 
+            if (!mDidStopLoad) {
+                // Only update the bookmark screenshot if the user did not
+                // cancel the load early.
+                Message updateScreenshot = Message.obtain(mHandler, UPDATE_BOOKMARK_THUMBNAIL, view);
+                mHandler.sendMessageDelayed(updateScreenshot, 500);
+            }
+
             // Update the lock icon image only once we are done loading
             updateLockIconToLatest();
-            updateScreenshot(view);
 
             // Performance probe
             if (false) {
@@ -3095,9 +3236,16 @@ public class BrowserActivity extends Activity
             }
 
             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.
+                // onProgressChanged() may continue to be called after the main
+                // frame has finished loading, as any remaining sub frames
+                // continue to load. We'll only get called once though with
+                // newProgress as 100 when everything is loaded.
+                // (onPageFinished is called once when the main frame completes
+                // loading regardless of the state of any sub frames so calls
+                // to onProgressChanges may continue after onPageFinished has
+                // executed)
+
+                // sync cookies and cache promptly here.
                 CookieSyncManager.getInstance().sync();
                 if (mInLoad) {
                     mInLoad = false;
@@ -4273,6 +4421,7 @@ public class BrowserActivity extends Activity
 
     private boolean mInLoad;
     private boolean mIsNetworkUp;
+    private boolean mDidStopLoad;
 
     private boolean mPageStarted;
     private boolean mActivityInPause = true;