diff options
author | John Reck <jreck@google.com> | 2011-06-29 13:44:44 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-06-29 13:44:44 -0700 |
commit | 253b8553264dd3da9c7688d8c04d7f1f1b2bd399 (patch) | |
tree | 62af261c4367a86cc44afbd41573c2991fdedd3e | |
parent | 9b0a25cd743153261376ca4d7abcb8b56854c695 (diff) | |
parent | db22ec4ee014900988062d910bc810172a07df56 (diff) | |
download | packages_apps_browser-253b8553264dd3da9c7688d8c04d7f1f1b2bd399.zip packages_apps_browser-253b8553264dd3da9c7688d8c04d7f1f1b2bd399.tar.gz packages_apps_browser-253b8553264dd3da9c7688d8c04d7f1f1b2bd399.tar.bz2 |
Merge "Fix IntentHandler behavior"
-rw-r--r-- | src/com/android/browser/BookmarkUtils.java | 13 | ||||
-rw-r--r-- | src/com/android/browser/Controller.java | 2 | ||||
-rw-r--r-- | src/com/android/browser/IntentHandler.java | 56 | ||||
-rw-r--r-- | src/com/android/browser/Tab.java | 14 | ||||
-rw-r--r-- | src/com/android/browser/TabControl.java | 28 | ||||
-rw-r--r-- | tests/src/com/android/browser/IntentHandlerTests.java | 164 |
6 files changed, 221 insertions, 56 deletions
diff --git a/src/com/android/browser/BookmarkUtils.java b/src/com/android/browser/BookmarkUtils.java index 491c16c..23765f4 100644 --- a/src/com/android/browser/BookmarkUtils.java +++ b/src/com/android/browser/BookmarkUtils.java @@ -115,10 +115,7 @@ public class BookmarkUtils { static Intent createAddToHomeIntent(Context context, String url, String title, Bitmap touchIcon, Bitmap favicon) { Intent i = new Intent(INSTALL_SHORTCUT); - Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - long urlHash = url.hashCode(); - long uniqueId = (urlHash << 32) | shortcutIntent.hashCode(); - shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID, Long.toString(uniqueId)); + Intent shortcutIntent = createShortcutIntent(url); i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, touchIcon, favicon, @@ -129,6 +126,14 @@ public class BookmarkUtils { return i; } + static Intent createShortcutIntent(String url) { + Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + long urlHash = url.hashCode(); + long uniqueId = (urlHash << 32) | shortcutIntent.hashCode(); + shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID, Long.toString(uniqueId)); + return shortcutIntent; + } + private static Bitmap getIconBackground(Context context, BookmarkIconType type, int density) { if (type == BookmarkIconType.ICON_HOME_SHORTCUT) { // Want to create a shortcut icon on the homescreen, so the icon diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java index 7abda69..447e61b 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -338,6 +338,8 @@ public class Controller // TabControl.restoreState() will create a new tab even if // restoring the state fails. setActiveTab(mTabControl.getCurrentTab()); + // Handle the intent + mIntentHandler.onNewIntent(intent); } // clear up the thumbnail directory, which is no longer used; // ideally this should only be run once after an upgrade from diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java index 54711d9..088a788 100644 --- a/src/com/android/browser/IntentHandler.java +++ b/src/com/android/browser/IntentHandler.java @@ -139,6 +139,15 @@ public class IntentHandler { mController.openTab(urlData); return; } + /* + * TODO: Don't allow javascript URIs + * 0) If this is a javascript: URI, *always* open a new tab + * 1) If this is a voice search, re-use tab for appId + * If there is no appId, use current tab + * 2) If the URL is already opened, switch to that tab + * 3-phone) Reuse tab with same appId + * 3-tablet) Open new tab + */ final String appId = intent .getStringExtra(Browser.EXTRA_APPLICATION_ID); if (!TextUtils.isEmpty(urlData.mUrl) && @@ -151,38 +160,33 @@ public class IntentHandler { // 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)) - && !mActivity.getPackageName().equals(appId) - && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { - if (activateVoiceSearch) { + && !mActivity.getPackageName().equals(appId)) { + if (activateVoiceSearch || !BrowserActivity.isTablet(mActivity)) { Tab appTab = mTabControl.getTabFromAppId(appId); if (appTab != null) { mController.reuseTab(appTab, urlData); return; - } else { - Tab tab = mController.openTab(urlData); - if (tab != null) { - tab.setAppId(appId); - } } + } + // No matching application tab, try to find a regular tab + // with a matching url. + Tab appTab = mTabControl.findTabWithUrl(urlData.mUrl); + if (appTab != null) { + // Transfer ownership + appTab.setAppId(appId); + if (current != appTab) { + mController.switchToTab(appTab); + } + // Otherwise, we are already viewing the correct tab. } else { - // No matching application tab, try to find a regular tab - // with a matching url. - Tab appTab = mTabControl.findUnusedTabWithUrl(urlData.mUrl); - if (appTab != null) { - if (current != appTab) { - mController.switchToTab(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. - Tab tab = mController.openTab(urlData); - if (tab != null) { - tab.setAppId(appId); - } + // 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. + Tab tab = mController.openTab(urlData); + if (tab != null) { + tab.setAppId(appId); } } } else { diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java index c78b562..e672e2b 100644 --- a/src/com/android/browser/Tab.java +++ b/src/com/android/browser/Tab.java @@ -152,6 +152,7 @@ class Tab { // All the state needed for a page protected static class PageState { String mUrl; + String mOriginalUrl; String mTitle; LockIcon mLockIcon; Bitmap mFavicon; @@ -159,10 +160,10 @@ class Tab { PageState(Context c, boolean incognito) { if (incognito) { - mUrl = "browser:incognito"; + mOriginalUrl = mUrl = "browser:incognito"; mTitle = c.getString(R.string.new_incognito_tab); } else { - mUrl = ""; + mOriginalUrl = mUrl = ""; mTitle = c.getString(R.string.new_tab); } mFavicon = BitmapFactory.decodeResource( @@ -171,7 +172,7 @@ class Tab { } PageState(Context c, boolean incognito, String url, Bitmap favicon) { - mUrl = url; + mOriginalUrl = mUrl = url; mTitle = null; if (URLUtil.isHttpsUrl(url)) { mLockIcon = LockIcon.LOCK_ICON_SECURE; @@ -562,6 +563,7 @@ class Tab { if (mCurrentState.mUrl == null) { mCurrentState.mUrl = url != null ? url : ""; } + mCurrentState.mOriginalUrl = view.getOriginalUrl(); mCurrentState.mTitle = view.getTitle(); mCurrentState.mFavicon = view.getFavicon(); if (!URLUtil.isHttpsUrl(mCurrentState.mUrl)) { @@ -1677,10 +1679,10 @@ class Tab { } String getOriginalUrl() { - if (mMainView == null) { - return ""; + if (mCurrentState.mOriginalUrl == null) { + return getUrl(); } - return UrlUtils.filteredUrl(mMainView.getOriginalUrl()); + return UrlUtils.filteredUrl(mCurrentState.mOriginalUrl); } /** diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java index 1367ba2..2eb24e9 100644 --- a/src/com/android/browser/TabControl.java +++ b/src/com/android/browser/TabControl.java @@ -551,40 +551,28 @@ class TabControl { } } - // This method checks if a non-app tab (one created within the browser) - // matches the given url. + // This method checks if a tab matches the given url. private boolean tabMatchesUrl(Tab t, String url) { - if (t.getAppId() != null) { - return false; - } - WebView webview = t.getWebView(); - if (webview == null) { - return false; - } else if (url.equals(webview.getUrl()) - || url.equals(webview.getOriginalUrl())) { - return true; - } - return false; + return url.equals(t.getUrl()) || url.equals(t.getOriginalUrl()); } /** - * Return the tab that has no app id associated with it and the url of the - * tab matches the given url. + * Return the tab that matches the given url. * @param url The url to search for. */ - Tab findUnusedTabWithUrl(String url) { + Tab findTabWithUrl(String url) { if (url == null) { return null; } // Check the current tab first. - Tab t = getCurrentTab(); - if (t != null && tabMatchesUrl(t, url)) { - return t; + Tab currentTab = getCurrentTab(); + if (currentTab != null && tabMatchesUrl(currentTab, url)) { + return currentTab; } // Now check all the rest. for (Tab tab : mTabs) { if (tabMatchesUrl(tab, url)) { - return t; + return tab; } } return null; diff --git a/tests/src/com/android/browser/IntentHandlerTests.java b/tests/src/com/android/browser/IntentHandlerTests.java new file mode 100644 index 0000000..2bdadae --- /dev/null +++ b/tests/src/com/android/browser/IntentHandlerTests.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.provider.Browser; +import android.test.ActivityInstrumentationTestCase2; +import android.text.TextUtils; +import android.webkit.WebView; + +public class IntentHandlerTests extends ActivityInstrumentationTestCase2<BrowserActivity> { + + // How long to wait to receive onPageStarted + static final int START_LOAD_TIMEOUT = 20000; // ms + static final int POLL_INTERVAL = 50; // ms + boolean mHasStarted = false; + + public IntentHandlerTests() { + super(BrowserActivity.class); + } + + public void testSwitchToTabWithUrl() throws Throwable { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("http://google.com/")); + sendIntent(intent); + Controller controller = getActivity().getController(); + Tab tabGoogle = controller.getCurrentTab(); + assertNotNull("Current tab (google.com", tabGoogle); + assertEquals("http://google.com/", tabGoogle.getOriginalUrl()); + assertEquals(1, controller.getTabs().size()); + intent.setData(Uri.parse("http://maps.google.com/")); + sendIntent(intent); + Tab tabMaps = controller.getCurrentTab(); + assertNotSame(tabGoogle, tabMaps); + assertNotNull("Current tab (maps.google.com)", tabMaps); + assertEquals(2, controller.getTabs().size()); + intent.setData(Uri.parse("http://google.com/")); + sendIntent(intent); + assertEquals(tabGoogle, controller.getCurrentTab()); + assertEquals(2, controller.getTabs().size()); + } + + public void testShortcut() throws Throwable { + Intent intent = BookmarkUtils.createShortcutIntent("http://google.com/"); + sendIntent(intent); + Controller controller = getActivity().getController(); + Tab tabGoogle = controller.getCurrentTab(); + assertEquals("http://google.com/", tabGoogle.getOriginalUrl()); + assertEquals(1, controller.getTabs().size()); + sendIntent(intent); + assertEquals(1, controller.getTabs().size()); + assertEquals(tabGoogle, controller.getCurrentTab()); + directlyLoadUrl(tabGoogle, "http://maps.google.com/"); + sendIntent(intent); + if (BrowserActivity.isTablet(getActivity())) { + assertEquals(2, controller.getTabs().size()); + assertNotSame(tabGoogle, controller.getCurrentTab()); + assertEquals("http://maps.google.com/", tabGoogle.getOriginalUrl()); + Tab currentTab = controller.getCurrentTab(); + assertEquals("http://google.com/", currentTab.getOriginalUrl()); + } else { + assertEquals(1, controller.getTabs().size()); + assertEquals(tabGoogle, controller.getCurrentTab()); + assertEquals("http://google.com/", tabGoogle.getOriginalUrl()); + } + } + + public void testApplication() throws Throwable { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("http://google.com/")); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, getClass().getName()); + sendIntent(intent); + Controller controller = getActivity().getController(); + Tab tabGoogle = controller.getCurrentTab(); + assertNotNull("Current tab (google.com", tabGoogle); + assertEquals("http://google.com/", tabGoogle.getOriginalUrl()); + assertEquals(1, controller.getTabs().size()); + intent.setData(Uri.parse("http://maps.google.com/")); + sendIntent(intent); + Tab tabMaps = controller.getCurrentTab(); + assertEquals("http://maps.google.com/", tabMaps.getOriginalUrl()); + if (BrowserActivity.isTablet(getActivity())) { + assertEquals(2, controller.getTabs().size()); + assertNotSame(tabGoogle, tabMaps); + assertEquals("http://google.com/", tabGoogle.getOriginalUrl()); + } else { + assertEquals(1, controller.getTabs().size()); + assertEquals(tabGoogle, tabMaps); + } + } + + /** + * Simulate clicking a link by loading a URL directly on the WebView, + * bypassing Tab, Controller, etc.. + * @throws Throwable + */ + private void directlyLoadUrl(final Tab tab, final String url) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + WebView web = tab.getWebView(); + web.loadUrl(url); + } + }); + waitForLoadStart(tab, url); + } + + void waitForLoadStart(final Tab tab, final String url) throws InterruptedException { + long start = System.currentTimeMillis(); + while (!TextUtils.equals(tab.getOriginalUrl(), url)) { + if (start + START_LOAD_TIMEOUT < System.currentTimeMillis()) { + throw new RuntimeException("Didn't receive onPageStarted!"); + } + Thread.sleep(POLL_INTERVAL); + } + } + + private void sendIntent(final Intent intent) throws Throwable { + sendIntent(intent, true); + } + + private void sendIntent(final Intent intent, boolean waitForLoadStart) throws Throwable { + if (!mHasStarted) { + // Prevent crash recovery from happening + intent.putExtra(Controller.NO_CRASH_RECOVERY, true); + setActivityIntent(intent); + getActivity(); + } else { + final Activity activity = getActivity(); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getInstrumentation().callActivityOnNewIntent(activity, intent); + } + }); + } + if (waitForLoadStart) { + String url = intent.getDataString(); + Tab tab = getActivity().getController().getCurrentTab(); + waitForLoadStart(tab, url); + } + } + + @Override + public BrowserActivity getActivity() { + mHasStarted = true; + return super.getActivity(); + } +} |