| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser; | 5 package org.chromium.chrome.browser; |
| 6 | 6 |
| 7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
| 8 import android.content.pm.ApplicationInfo; | 8 import android.content.pm.ApplicationInfo; |
| 9 import android.content.pm.PackageManager; | 9 import android.content.pm.PackageManager; |
| 10 import android.graphics.Rect; | 10 import android.graphics.Rect; |
| 11 import android.os.Build; | 11 import android.os.Build; |
| 12 import android.os.Bundle; | 12 import android.os.Bundle; |
| 13 import android.os.Handler; | 13 import android.os.Handler; |
| 14 import android.os.HandlerThread; | 14 import android.os.HandlerThread; |
| 15 import android.os.Message; | 15 import android.os.Message; |
| 16 import android.support.test.filters.MediumTest; | 16 import android.support.test.filters.MediumTest; |
| 17 import android.view.View; | 17 import android.view.View; |
| 18 import android.view.ViewGroup; | 18 import android.view.ViewGroup; |
| 19 | 19 |
| 20 import org.junit.After; |
| 21 import org.junit.Assert; |
| 22 import org.junit.Before; |
| 23 import org.junit.Rule; |
| 24 import org.junit.Test; |
| 25 import org.junit.runner.RunWith; |
| 26 |
| 20 import org.chromium.base.ThreadUtils; | 27 import org.chromium.base.ThreadUtils; |
| 21 import org.chromium.base.test.util.CallbackHelper; | 28 import org.chromium.base.test.util.CallbackHelper; |
| 29 import org.chromium.base.test.util.CommandLineFlags; |
| 22 import org.chromium.base.test.util.Feature; | 30 import org.chromium.base.test.util.Feature; |
| 23 import org.chromium.base.test.util.RetryOnFailure; | 31 import org.chromium.base.test.util.RetryOnFailure; |
| 24 import org.chromium.chrome.test.ChromeActivityTestCaseBase; | 32 import org.chromium.chrome.test.ChromeActivityTestRule; |
| 33 import org.chromium.chrome.test.ChromeJUnit4ClassRunner; |
| 25 | 34 |
| 26 import java.lang.reflect.Method; | 35 import java.lang.reflect.Method; |
| 27 import java.util.concurrent.TimeoutException; | 36 import java.util.concurrent.TimeoutException; |
| 28 | 37 |
| 29 /** | 38 /** |
| 30 * Tests for the SmartClipProvider. | 39 * Tests for the SmartClipProvider. |
| 31 */ | 40 */ |
| 32 public class SmartClipProviderTest | 41 @RunWith(ChromeJUnit4ClassRunner.class) |
| 33 extends ChromeActivityTestCaseBase<ChromeActivity> implements Handler.Ca
llback { | 42 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, |
| 43 ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG}) |
| 44 public class SmartClipProviderTest implements Handler.Callback { |
| 34 // This is a key for meta-data in the package manifest. It should NOT | 45 // This is a key for meta-data in the package manifest. It should NOT |
| 35 // change, as OEMs will use it when they look for the SmartClipProvider | 46 // change, as OEMs will use it when they look for the SmartClipProvider |
| 36 // interface. | 47 // interface. |
| 48 |
| 49 @Rule |
| 50 public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = |
| 51 new ChromeActivityTestRule<>(ChromeActivity.class); |
| 52 |
| 37 private static final String SMART_CLIP_PROVIDER_KEY = | 53 private static final String SMART_CLIP_PROVIDER_KEY = |
| 38 "org.chromium.content.browser.SMART_CLIP_PROVIDER"; | 54 "org.chromium.content.browser.SMART_CLIP_PROVIDER"; |
| 39 | 55 |
| 40 private static class MyCallbackHelper extends CallbackHelper { | 56 private static class MyCallbackHelper extends CallbackHelper { |
| 41 public String getTitle() { | 57 public String getTitle() { |
| 42 return mTitle; | 58 return mTitle; |
| 43 } | 59 } |
| 44 | 60 |
| 45 public String getUrl() { | 61 public String getUrl() { |
| 46 return mUrl; | 62 return mUrl; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 75 } | 91 } |
| 76 | 92 |
| 77 private ChromeActivity mActivity; | 93 private ChromeActivity mActivity; |
| 78 private MyCallbackHelper mCallbackHelper; | 94 private MyCallbackHelper mCallbackHelper; |
| 79 private HandlerThread mHandlerThread; | 95 private HandlerThread mHandlerThread; |
| 80 private Handler mHandler; | 96 private Handler mHandler; |
| 81 private Class<?> mSmartClipProviderClass; | 97 private Class<?> mSmartClipProviderClass; |
| 82 private Method mSetSmartClipResultHandlerMethod; | 98 private Method mSetSmartClipResultHandlerMethod; |
| 83 private Method mExtractSmartClipDataMethod; | 99 private Method mExtractSmartClipDataMethod; |
| 84 | 100 |
| 85 public SmartClipProviderTest() { | 101 @Before |
| 86 super(ChromeActivity.class); | |
| 87 } | |
| 88 | |
| 89 @Override | |
| 90 public void startMainActivity() throws InterruptedException { | |
| 91 startMainActivityOnBlankPage(); | |
| 92 } | |
| 93 | |
| 94 @Override | |
| 95 public void setUp() throws Exception { | 102 public void setUp() throws Exception { |
| 96 super.setUp(); | 103 mActivityTestRule.startMainActivityOnBlankPage(); |
| 97 mActivity = getActivity(); | 104 mActivity = mActivityTestRule.getActivity(); |
| 98 mCallbackHelper = new MyCallbackHelper(); | 105 mCallbackHelper = new MyCallbackHelper(); |
| 99 mHandlerThread = new HandlerThread("ContentViewTest thread"); | 106 mHandlerThread = new HandlerThread("ContentViewTest thread"); |
| 100 mHandlerThread.start(); | 107 mHandlerThread.start(); |
| 101 mHandler = new Handler(mHandlerThread.getLooper(), this); | 108 mHandler = new Handler(mHandlerThread.getLooper(), this); |
| 102 | 109 |
| 103 mSmartClipProviderClass = getSmartClipProviderClass(); | 110 mSmartClipProviderClass = getSmartClipProviderClass(); |
| 104 assertNotNull(mSmartClipProviderClass); | 111 Assert.assertNotNull(mSmartClipProviderClass); |
| 105 mSetSmartClipResultHandlerMethod = mSmartClipProviderClass.getDeclaredMe
thod( | 112 mSetSmartClipResultHandlerMethod = mSmartClipProviderClass.getDeclaredMe
thod( |
| 106 "setSmartClipResultHandler", new Class[] { Handler.class }); | 113 "setSmartClipResultHandler", new Class[] { Handler.class }); |
| 107 mExtractSmartClipDataMethod = mSmartClipProviderClass.getDeclaredMethod( | 114 mExtractSmartClipDataMethod = mSmartClipProviderClass.getDeclaredMethod( |
| 108 "extractSmartClipData", | 115 "extractSmartClipData", |
| 109 new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.
TYPE }); | 116 new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.
TYPE }); |
| 110 } | 117 } |
| 111 | 118 |
| 119 @After |
| 112 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) | 120 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) |
| 113 @Override | |
| 114 public void tearDown() throws Exception { | 121 public void tearDown() throws Exception { |
| 115 try { | 122 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { |
| 116 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { | 123 mHandlerThread.quitSafely(); |
| 117 mHandlerThread.quitSafely(); | 124 } else { |
| 118 } else { | 125 mHandlerThread.quit(); |
| 119 mHandlerThread.quit(); | |
| 120 } | |
| 121 } finally { | |
| 122 super.tearDown(); | |
| 123 } | 126 } |
| 124 } | 127 } |
| 125 | 128 |
| 126 // Implements Handler.Callback | 129 // Implements Handler.Callback |
| 127 @Override | 130 @Override |
| 128 public boolean handleMessage(Message msg) { | 131 public boolean handleMessage(Message msg) { |
| 129 Bundle bundle = msg.getData(); | 132 Bundle bundle = msg.getData(); |
| 130 assertNotNull(bundle); | 133 Assert.assertNotNull(bundle); |
| 131 String url = bundle.getString("url"); | 134 String url = bundle.getString("url"); |
| 132 String title = bundle.getString("title"); | 135 String title = bundle.getString("title"); |
| 133 String text = bundle.getString("text"); | 136 String text = bundle.getString("text"); |
| 134 String html = bundle.getString("html"); | 137 String html = bundle.getString("html"); |
| 135 Rect rect = bundle.getParcelable("rect"); | 138 Rect rect = bundle.getParcelable("rect"); |
| 136 // We don't care about other values for now. | 139 // We don't care about other values for now. |
| 137 mCallbackHelper.notifyCalled(title, url, text, html, rect); | 140 mCallbackHelper.notifyCalled(title, url, text, html, rect); |
| 138 return true; | 141 return true; |
| 139 } | 142 } |
| 140 | 143 |
| 141 // Create SmartClipProvider interface from package meta-data. | 144 // Create SmartClipProvider interface from package meta-data. |
| 142 private Class<?> getSmartClipProviderClass() throws Exception { | 145 private Class<?> getSmartClipProviderClass() throws Exception { |
| 143 ApplicationInfo ai = mActivity.getPackageManager().getApplicationInfo( | 146 ApplicationInfo ai = mActivity.getPackageManager().getApplicationInfo( |
| 144 mActivity.getPackageName(), PackageManager.GET_META_DATA); | 147 mActivity.getPackageName(), PackageManager.GET_META_DATA); |
| 145 Bundle bundle = ai.metaData; | 148 Bundle bundle = ai.metaData; |
| 146 String className = bundle.getString(SMART_CLIP_PROVIDER_KEY); | 149 String className = bundle.getString(SMART_CLIP_PROVIDER_KEY); |
| 147 assertNotNull(className); | 150 Assert.assertNotNull(className); |
| 148 return Class.forName(className); | 151 return Class.forName(className); |
| 149 } | 152 } |
| 150 | 153 |
| 151 // Returns the first smart clip provider under the root view using DFS. | 154 // Returns the first smart clip provider under the root view using DFS. |
| 152 private Object findSmartClipProvider(View v) { | 155 private Object findSmartClipProvider(View v) { |
| 153 if (mSmartClipProviderClass.isInstance(v)) { | 156 if (mSmartClipProviderClass.isInstance(v)) { |
| 154 return v; | 157 return v; |
| 155 } else if (v instanceof ViewGroup) { | 158 } else if (v instanceof ViewGroup) { |
| 156 ViewGroup viewGroup = (ViewGroup) v; | 159 ViewGroup viewGroup = (ViewGroup) v; |
| 157 int count = viewGroup.getChildCount(); | 160 int count = viewGroup.getChildCount(); |
| 158 for (int i = 0; i < count; ++i) { | 161 for (int i = 0; i < count; ++i) { |
| 159 View c = viewGroup.getChildAt(i); | 162 View c = viewGroup.getChildAt(i); |
| 160 Object found = findSmartClipProvider(c); | 163 Object found = findSmartClipProvider(c); |
| 161 if (found != null) return found; | 164 if (found != null) return found; |
| 162 } | 165 } |
| 163 } | 166 } |
| 164 return null; | 167 return null; |
| 165 } | 168 } |
| 166 | 169 |
| 170 @Test |
| 167 @MediumTest | 171 @MediumTest |
| 168 @Feature({"SmartClip"}) | 172 @Feature({"SmartClip"}) |
| 169 @RetryOnFailure | 173 @RetryOnFailure |
| 170 public void testSmartClipDataCallback() throws InterruptedException, Timeout
Exception { | 174 public void testSmartClipDataCallback() throws InterruptedException, Timeout
Exception { |
| 171 final Rect rect = new Rect(10, 20, 110, 190); | 175 final Rect rect = new Rect(10, 20, 110, 190); |
| 172 ThreadUtils.runOnUiThreadBlocking(new Runnable() { | 176 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 173 @Override | 177 @Override |
| 174 public void run() { | 178 public void run() { |
| 175 // This emulates what OEM will be doing when they want to call | 179 // This emulates what OEM will be doing when they want to call |
| 176 // functions on SmartClipProvider through view hierarchy. | 180 // functions on SmartClipProvider through view hierarchy. |
| 177 | 181 |
| 178 Object scp = | 182 Object scp = findSmartClipProvider( |
| 179 findSmartClipProvider(getActivity().findViewById(android
.R.id.content)); | 183 mActivityTestRule.getActivity().findViewById(android.R.i
d.content)); |
| 180 assertNotNull(scp); | 184 Assert.assertNotNull(scp); |
| 181 try { | 185 try { |
| 182 mSetSmartClipResultHandlerMethod.invoke(scp, mHandler); | 186 mSetSmartClipResultHandlerMethod.invoke(scp, mHandler); |
| 183 mExtractSmartClipDataMethod.invoke( | 187 mExtractSmartClipDataMethod.invoke( |
| 184 scp, rect.left, rect.top, rect.width(), rect.height(
)); | 188 scp, rect.left, rect.top, rect.width(), rect.height(
)); |
| 185 } catch (Exception e) { | 189 } catch (Exception e) { |
| 186 e.printStackTrace(); | 190 e.printStackTrace(); |
| 187 fail(); | 191 Assert.fail(); |
| 188 } | 192 } |
| 189 } | 193 } |
| 190 }); | 194 }); |
| 191 mCallbackHelper.waitForCallback(0, 1); // call count: 0 --> 1 | 195 mCallbackHelper.waitForCallback(0, 1); // call count: 0 --> 1 |
| 192 assertEquals("about:blank", mCallbackHelper.getTitle()); | 196 Assert.assertEquals("about:blank", mCallbackHelper.getTitle()); |
| 193 assertEquals("about:blank", mCallbackHelper.getUrl()); | 197 Assert.assertEquals("about:blank", mCallbackHelper.getUrl()); |
| 194 assertNotNull(mCallbackHelper.getText()); | 198 Assert.assertNotNull(mCallbackHelper.getText()); |
| 195 assertNotNull(mCallbackHelper.getHtml()); | 199 Assert.assertNotNull(mCallbackHelper.getHtml()); |
| 196 assertNotNull(mCallbackHelper.getRect()); | 200 Assert.assertNotNull(mCallbackHelper.getRect()); |
| 197 assertEquals(rect.left, mCallbackHelper.getRect().left); | 201 Assert.assertEquals(rect.left, mCallbackHelper.getRect().left); |
| 198 assertEquals(rect.top, mCallbackHelper.getRect().top); | 202 Assert.assertEquals(rect.top, mCallbackHelper.getRect().top); |
| 199 assertEquals(rect.width(), mCallbackHelper.getRect().width()); | 203 Assert.assertEquals(rect.width(), mCallbackHelper.getRect().width()); |
| 200 assertEquals(rect.height(), mCallbackHelper.getRect().height()); | 204 Assert.assertEquals(rect.height(), mCallbackHelper.getRect().height()); |
| 201 } | 205 } |
| 202 | 206 |
| 207 @Test |
| 203 @MediumTest | 208 @MediumTest |
| 204 @Feature({"SmartClip"}) | 209 @Feature({"SmartClip"}) |
| 205 @RetryOnFailure | 210 @RetryOnFailure |
| 206 public void testSmartClipNoHandlerDoesntCrash() throws InterruptedException,
TimeoutException { | 211 public void testSmartClipNoHandlerDoesntCrash() throws InterruptedException,
TimeoutException { |
| 207 ThreadUtils.runOnUiThreadBlocking(new Runnable() { | 212 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 208 @Override | 213 @Override |
| 209 public void run() { | 214 public void run() { |
| 210 Object scp = | 215 Object scp = findSmartClipProvider( |
| 211 findSmartClipProvider(getActivity().findViewById(android
.R.id.content)); | 216 mActivityTestRule.getActivity().findViewById(android.R.i
d.content)); |
| 212 assertNotNull(scp); | 217 Assert.assertNotNull(scp); |
| 213 try { | 218 try { |
| 214 // Galaxy Note 4 has a bug where it doesn't always set the h
andler first; in | 219 // Galaxy Note 4 has a bug where it doesn't always set the h
andler first; in |
| 215 // that case, we shouldn't crash: http://crbug.com/710147 | 220 // that case, we shouldn't crash: http://crbug.com/710147 |
| 216 mExtractSmartClipDataMethod.invoke(scp, 10, 20, 100, 70); | 221 mExtractSmartClipDataMethod.invoke(scp, 10, 20, 100, 70); |
| 217 | 222 |
| 218 // Add a wait for a valid callback to make sure we have time
to | 223 // Add a wait for a valid callback to make sure we have time
to |
| 219 // hit the crash from the above call if any. | 224 // hit the crash from the above call if any. |
| 220 mSetSmartClipResultHandlerMethod.invoke(scp, mHandler); | 225 mSetSmartClipResultHandlerMethod.invoke(scp, mHandler); |
| 221 mExtractSmartClipDataMethod.invoke(scp, 10, 20, 100, 70); | 226 mExtractSmartClipDataMethod.invoke(scp, 10, 20, 100, 70); |
| 222 } catch (Exception e) { | 227 } catch (Exception e) { |
| 223 e.printStackTrace(); | 228 e.printStackTrace(); |
| 224 fail(); | 229 Assert.fail(); |
| 225 } | 230 } |
| 226 } | 231 } |
| 227 }); | 232 }); |
| 228 mCallbackHelper.waitForCallback(0, 1); // call count: 0 --> 1 | 233 mCallbackHelper.waitForCallback(0, 1); // call count: 0 --> 1 |
| 229 } | 234 } |
| 230 } | 235 } |
| OLD | NEW |