summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2011-06-29 11:31:24 -0700
committerJohn Reck <jreck@google.com>2011-06-29 13:28:03 -0700
commitdb22ec4ee014900988062d910bc810172a07df56 (patch)
tree317dd31937a995619e36882d3b2571adf55a7916
parent749b93662b6c3152899d91dbd80139224dc46961 (diff)
downloadandroid_packages_apps_Gello-db22ec4ee014900988062d910bc810172a07df56.tar.gz
android_packages_apps_Gello-db22ec4ee014900988062d910bc810172a07df56.tar.bz2
android_packages_apps_Gello-db22ec4ee014900988062d910bc810172a07df56.zip
Fix IntentHandler behavior
Bug: 4473779 Plus, TESTS! Huzzah! Change-Id: I043e100d99d4653b7fb7885217d7fb305930a137
-rw-r--r--src/com/android/browser/BookmarkUtils.java13
-rw-r--r--src/com/android/browser/Controller.java2
-rw-r--r--src/com/android/browser/IntentHandler.java56
-rw-r--r--src/com/android/browser/Tab.java14
-rw-r--r--src/com/android/browser/TabControl.java28
-rw-r--r--tests/src/com/android/browser/IntentHandlerTests.java164
6 files changed, 221 insertions, 56 deletions
diff --git a/src/com/android/browser/BookmarkUtils.java b/src/com/android/browser/BookmarkUtils.java
index 491c16c1..23765f4d 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 9a015b2d..1f376d25 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 54711d94..088a788d 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 c78b562e..e672e2bb 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 1367ba2c..2eb24e95 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 00000000..2bdadaeb
--- /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();
+ }
+}