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