OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.test; |
| 6 |
| 7 import android.app.Activity; |
| 8 import android.app.ActivityManager; |
| 9 import android.app.ActivityManager.AppTask; |
| 10 import android.app.Instrumentation; |
| 11 import android.content.ComponentName; |
| 12 import android.content.Context; |
| 13 import android.content.Intent; |
| 14 import android.content.pm.PackageManager; |
| 15 import android.net.Uri; |
| 16 import android.os.AsyncTask; |
| 17 import android.os.PowerManager; |
| 18 import android.provider.Browser; |
| 19 import android.text.TextUtils; |
| 20 import android.util.Log; |
| 21 import android.view.KeyEvent; |
| 22 import android.view.View; |
| 23 import android.widget.ListView; |
| 24 |
| 25 import com.google.android.apps.chrome.R; |
| 26 |
| 27 import junit.framework.Assert; |
| 28 |
| 29 import org.chromium.base.PerfTraceEvent; |
| 30 import org.chromium.base.ThreadUtils; |
| 31 import org.chromium.base.annotations.SuppressFBWarnings; |
| 32 import org.chromium.base.test.BaseActivityInstrumentationTestCase; |
| 33 import org.chromium.base.test.util.CommandLineFlags; |
| 34 import org.chromium.base.test.util.PerfTest; |
| 35 import org.chromium.chrome.browser.ChromeActivity; |
| 36 import org.chromium.chrome.browser.ChromeMobileApplication; |
| 37 import org.chromium.chrome.browser.ChromeSwitches; |
| 38 import org.chromium.chrome.browser.ChromeTabbedActivity; |
| 39 import org.chromium.chrome.browser.DeferredStartupHandler; |
| 40 import org.chromium.chrome.browser.EmptyTabObserver; |
| 41 import org.chromium.chrome.browser.Tab; |
| 42 import org.chromium.chrome.browser.document.ChromeLauncherActivity; |
| 43 import org.chromium.chrome.browser.document.DocumentActivity; |
| 44 import org.chromium.chrome.browser.document.DocumentMetricIds; |
| 45 import org.chromium.chrome.browser.document.DocumentUtils; |
| 46 import org.chromium.chrome.browser.document.IncognitoDocumentActivity; |
| 47 import org.chromium.chrome.browser.infobar.InfoBar; |
| 48 import org.chromium.chrome.browser.ntp.NewTabPage; |
| 49 import org.chromium.chrome.browser.omaha.OmahaClient; |
| 50 import org.chromium.chrome.browser.omnibox.AutocompleteController; |
| 51 import org.chromium.chrome.browser.omnibox.LocationBarLayout; |
| 52 import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultIt
em; |
| 53 import org.chromium.chrome.browser.omnibox.OmniboxSuggestion; |
| 54 import org.chromium.chrome.browser.omnibox.UrlBar; |
| 55 import org.chromium.chrome.browser.preferences.NetworkPredictionOptions; |
| 56 import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
| 57 import org.chromium.chrome.browser.preferences.Preferences; |
| 58 import org.chromium.chrome.browser.preferences.PreferencesLauncher; |
| 59 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
| 60 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 61 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 62 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
| 63 import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
| 64 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
| 65 import org.chromium.chrome.browser.util.FeatureUtilities; |
| 66 import org.chromium.chrome.test.util.ActivityUtils; |
| 67 import org.chromium.chrome.test.util.ApplicationData; |
| 68 import org.chromium.chrome.test.util.ChromeTabUtils; |
| 69 import org.chromium.chrome.test.util.MenuUtils; |
| 70 import org.chromium.chrome.test.util.NewTabPageTestUtils; |
| 71 import org.chromium.chrome.test.util.OmniboxTestUtils; |
| 72 import org.chromium.chrome.test.util.TestHttpServerClient; |
| 73 import org.chromium.content.browser.test.util.CallbackHelper; |
| 74 import org.chromium.content.browser.test.util.Criteria; |
| 75 import org.chromium.content.browser.test.util.CriteriaHelper; |
| 76 import org.chromium.content.browser.test.util.JavaScriptUtils; |
| 77 import org.chromium.content.browser.test.util.KeyUtils; |
| 78 import org.chromium.content.browser.test.util.RenderProcessLimit; |
| 79 import org.chromium.content.browser.test.util.TestTouchUtils; |
| 80 import org.chromium.content.browser.test.util.TouchCommon; |
| 81 import org.chromium.content_public.browser.LoadUrlParams; |
| 82 import org.chromium.ui.base.PageTransition; |
| 83 |
| 84 import java.io.File; |
| 85 import java.lang.reflect.Method; |
| 86 import java.util.LinkedList; |
| 87 import java.util.List; |
| 88 import java.util.concurrent.Callable; |
| 89 import java.util.concurrent.ExecutionException; |
| 90 import java.util.concurrent.Semaphore; |
| 91 import java.util.concurrent.TimeUnit; |
| 92 import java.util.concurrent.TimeoutException; |
| 93 import java.util.concurrent.atomic.AtomicBoolean; |
| 94 import java.util.concurrent.atomic.AtomicInteger; |
| 95 |
| 96 /** |
| 97 * Base class for all Chrome instrumentation tests. |
| 98 * All tests must inherit from this class and define their own test methods |
| 99 * See ChromeTabbedActivityTestBase.java for example. |
| 100 * @param <T> A {@link ChromeActivity} class |
| 101 */ |
| 102 @CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) |
| 103 public abstract class ChromeActivityTestCaseBase<T extends ChromeActivity> |
| 104 extends BaseActivityInstrumentationTestCase<T> { |
| 105 |
| 106 private static final String TAG = "ChromeActivityTestCaseBase"; |
| 107 |
| 108 // The number of ms to wait for the rendering activity to be started. |
| 109 protected static final int ACTIVITY_START_TIMEOUT_MS = 1000; |
| 110 |
| 111 private static final String PERF_NORUN_TAG = "--NORUN--"; |
| 112 |
| 113 private static final String PERF_ANNOTATION_FORMAT = "**PERFANNOTATION(%s):"
; |
| 114 |
| 115 private static final String MEMORY_TRACE_GRAPH_SUFFIX = " - browser PSS"; |
| 116 |
| 117 private static final String PERF_OUTPUT_FILE = "PerfTestData.txt"; |
| 118 |
| 119 private static final long OMNIBOX_FIND_SUGGESTION_TIMEOUT_MS = 10 * 1000; |
| 120 |
| 121 public ChromeActivityTestCaseBase(Class<T> activityClass) { |
| 122 super(activityClass); |
| 123 } |
| 124 |
| 125 protected boolean mSkipClearAppData = false; |
| 126 private PowerManager.WakeLock mWakeLock = null; |
| 127 protected boolean mSkipCheckHttpServer = false; |
| 128 |
| 129 @Override |
| 130 protected void setUp() throws Exception { |
| 131 super.setUp(); |
| 132 |
| 133 setActivityInitialTouchMode(false); |
| 134 if (!mSkipClearAppData) { |
| 135 // We shouldn't clear the data at the end of test, it is needed for
debugging. |
| 136 assertTrue("Unable to clear the app data", clearAppData()); |
| 137 if (FeatureUtilities.isDocumentMode(getInstrumentation().getTargetCo
ntext())) { |
| 138 closeAllChromeActivityAppTasks(); |
| 139 } |
| 140 } |
| 141 // Make sure the screen is on during test runs. |
| 142 PowerManager pm = (PowerManager) getInstrumentation().getTargetContext() |
| 143 .getSystemService(Context.POWER_SERVICE); |
| 144 mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK |
| 145 | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_REL
EASE, TAG); |
| 146 mWakeLock.acquire(); |
| 147 |
| 148 // Disable Omaha related activities. |
| 149 OmahaClient.setEnableCommunication(false); |
| 150 OmahaClient.setEnableUpdateDetection(false); |
| 151 |
| 152 if (!mSkipCheckHttpServer) { |
| 153 TestHttpServerClient.checkServerIsUp(); |
| 154 } |
| 155 startMainActivity(); |
| 156 } |
| 157 |
| 158 @Override |
| 159 protected void tearDown() throws Exception { |
| 160 assertNotNull("Uninitialized wake lock", mWakeLock); |
| 161 mWakeLock.release(); |
| 162 super.tearDown(); |
| 163 } |
| 164 |
| 165 /** |
| 166 * Called to start the Main Activity, the subclass should implemented with i
t desired start |
| 167 * method. |
| 168 * TODO: Make startMainActivityFromLauncher the default. |
| 169 */ |
| 170 public abstract void startMainActivity() throws InterruptedException; |
| 171 |
| 172 /** |
| 173 * Matches testString against baseString. |
| 174 * Returns 0 if there is no match, 1 if an exact match and 2 if a fuzzy matc
h. |
| 175 */ |
| 176 protected static int matchUrl(String baseString, String testString) { |
| 177 if (baseString.equals(testString)) { |
| 178 return 1; |
| 179 } |
| 180 if (baseString.contains(testString)) { |
| 181 return 2; |
| 182 } |
| 183 return 0; |
| 184 } |
| 185 |
| 186 /** |
| 187 * Invokes {@link Instrumentation#startActivitySync(Intent)} and sets the |
| 188 * test case's activity to the result. See the documentation for |
| 189 * {@link Instrumentation#startActivitySync(Intent)} on the timing of the |
| 190 * return, but generally speaking the activity's "onCreate" has completed |
| 191 * and the activity's main looper has become idle. |
| 192 */ |
| 193 protected void startActivityCompletely(Intent intent) { |
| 194 final Class<?> activityClazz = |
| 195 FeatureUtilities.isDocumentMode(getInstrumentation().getTargetCo
ntext()) |
| 196 ? DocumentActivity.class : ChromeTabbedActivity.class; |
| 197 Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonito
r( |
| 198 activityClazz.getName(), null, false); |
| 199 Activity activity = getInstrumentation().startActivitySync(intent); |
| 200 assertNotNull("Main activity did not start", activity); |
| 201 ChromeActivity chromeActivity = (ChromeActivity) |
| 202 monitor.waitForActivityWithTimeout(ACTIVITY_START_TIMEOUT_MS); |
| 203 assertNotNull("ChromeActivity did not start", chromeActivity); |
| 204 setActivity(chromeActivity); |
| 205 Log.d(TAG, "startActivityCompletely <<"); |
| 206 } |
| 207 |
| 208 /** |
| 209 * Clear all files and folders in the Chrome application directory except 'l
ib'. |
| 210 * |
| 211 * The 'cache' directory is recreated as an empty directory. |
| 212 * |
| 213 * @return Whether clearing the application data was successful. |
| 214 */ |
| 215 protected boolean clearAppData() throws InterruptedException { |
| 216 return ApplicationData.clearAppData(getInstrumentation().getTargetContex
t()); |
| 217 } |
| 218 |
| 219 /** |
| 220 * Closes all Chrome activity app tasks. This is for cleaning up Chrome task
s in the recent, |
| 221 * those are not necessarily associated with a live activity. |
| 222 */ |
| 223 private void closeAllChromeActivityAppTasks() throws ClassNotFoundException
{ |
| 224 ActivityManager am = (ActivityManager) getInstrumentation().getTargetCon
text() |
| 225 .getSystemService(Context.ACTIVITY_SERVICE); |
| 226 PackageManager pm = getInstrumentation().getTargetContext().getPackageMa
nager(); |
| 227 List<AppTask> taskList = am.getAppTasks(); |
| 228 for (AppTask task : taskList) { |
| 229 String className = DocumentUtils.getTaskClassName(task, pm); |
| 230 if (ChromeActivity.class.isAssignableFrom(Class.forName(className)))
{ |
| 231 task.finishAndRemoveTask(); |
| 232 } |
| 233 } |
| 234 } |
| 235 |
| 236 /** |
| 237 * Lets tests specify whether they want prerendering turned on. |
| 238 * It is on by default. Since in some places different code paths are used f
or the same feature |
| 239 * depending of whether instant is on or off (ex: infobars), it is necessary
for some tests to |
| 240 * test with and without instant. |
| 241 * |
| 242 * @param enabled whether prerender should be on. |
| 243 */ |
| 244 protected void setAllowPrerender(final boolean enabled) { |
| 245 getInstrumentation().runOnMainSync(new Runnable() { |
| 246 @Override |
| 247 public void run() { |
| 248 PrefServiceBridge.getInstance().setNetworkPredictionOptions(enab
led |
| 249 ? NetworkPredictionOptions.NETWORK_PREDICTION_ALWAYS |
| 250 : NetworkPredictionOptions.NETWORK_PREDICTION_NEVER); |
| 251 } |
| 252 }); |
| 253 } |
| 254 |
| 255 /** |
| 256 * Starts (synchronously) a drag motion. Normally followed by dragTo() and d
ragEnd(). |
| 257 * |
| 258 * @param x |
| 259 * @param y |
| 260 * @param downTime (in ms) |
| 261 * @see TestTouchUtils |
| 262 */ |
| 263 protected void dragStart(float x, float y, long downTime) { |
| 264 TouchCommon.dragStart(getActivity(), x, y, downTime); |
| 265 } |
| 266 |
| 267 /** |
| 268 * Drags / moves (synchronously) to the specified coordinates. Normally prec
eeded by |
| 269 * dragStart() and followed by dragEnd() |
| 270 * |
| 271 * @param fromX |
| 272 * @param toX |
| 273 * @param fromY |
| 274 * @param toY |
| 275 * @param stepCount |
| 276 * @param downTime (in ms) |
| 277 * @see TestTouchUtils |
| 278 */ |
| 279 protected void dragTo(float fromX, float toX, float fromY, |
| 280 float toY, int stepCount, long downTime) { |
| 281 TouchCommon.dragTo(getActivity(), fromX, toX, fromY, toY, stepCount, dow
nTime); |
| 282 } |
| 283 |
| 284 /** |
| 285 * Finishes (synchronously) a drag / move at the specified coordinate. |
| 286 * Normally preceeded by dragStart() and dragTo(). |
| 287 * |
| 288 * @param x |
| 289 * @param y |
| 290 * @param downTime (in ms) |
| 291 * @see TestTouchUtils |
| 292 */ |
| 293 protected void dragEnd(float x, float y, long downTime) { |
| 294 TouchCommon.dragEnd(getActivity(), x, y, downTime); |
| 295 } |
| 296 |
| 297 /** |
| 298 * Sends (synchronously) a single click to an absolute screen coordinates. |
| 299 * |
| 300 * @param x screen absolute |
| 301 * @param y screen absolute |
| 302 * @see TestTouchUtils |
| 303 */ |
| 304 public void singleClick(float x, float y) { |
| 305 TouchCommon.singleClick(getActivity(), x, y); |
| 306 } |
| 307 |
| 308 /** |
| 309 * Sends (synchronously) a single click to the View at the specified coordin
ates. |
| 310 * |
| 311 * <p> |
| 312 * Differs from |
| 313 * {@link TestTouchUtils#singleClickView(android.app.Instrumentation, View,
int, int)} |
| 314 * as this does not rely on injecting events into the different activity. I
njecting events has |
| 315 * been unreliable for us and simulating the touch events in this manner is
just as effective. |
| 316 * |
| 317 * @param v The view to be clicked. |
| 318 * @param x Relative x location to v |
| 319 * @param y Relative y location to v |
| 320 */ |
| 321 public void singleClickView(View v, int x, int y) { |
| 322 TouchCommon.singleClickView(v, x, y); |
| 323 } |
| 324 |
| 325 /** |
| 326 * Sends (synchronously) a single click to the center of the View. |
| 327 * |
| 328 * <p> |
| 329 * Differs from |
| 330 * {@link TestTouchUtils#singleClickView(android.app.Instrumentation, View)} |
| 331 * as this does not rely on injecting events into the different activity. I
njecting events has |
| 332 * been unreliable for us and simulating the touch events in this manner is
just as effective. |
| 333 * |
| 334 * @param v The view to be clicked. |
| 335 */ |
| 336 public void singleClickView(View v) { |
| 337 TouchCommon.singleClickView(v); |
| 338 } |
| 339 |
| 340 /** |
| 341 * Waits for {@link AsyncTask}'s that have been queued to finish. Note, this |
| 342 * only waits for tasks that have been started using the default |
| 343 * {@link java.util.concurrent.Executor}, which executes tasks serially. |
| 344 * |
| 345 * @param timeout how long to wait for tasks to complete |
| 346 */ |
| 347 public void waitForAsyncTasks(long timeout) throws InterruptedException { |
| 348 final Semaphore s = new Semaphore(0); |
| 349 new AsyncTask<Void, Void, Void>() { |
| 350 @Override |
| 351 protected Void doInBackground(Void... arg0) { |
| 352 s.release(); |
| 353 return null; |
| 354 } |
| 355 }.execute(); |
| 356 assertTrue(s.tryAcquire(timeout, TimeUnit.MILLISECONDS)); |
| 357 } |
| 358 |
| 359 /** |
| 360 * Navigates to a URL directly without going through the UrlBar. This bypass
es the page |
| 361 * preloading mechanism of the UrlBar. |
| 362 * @param url The url to load in the current tab. |
| 363 * @return FULL_PRERENDERED_PAGE_LOAD or PARTIAL_PRERENDERED_PAGE_LOAD if th
e page has been |
| 364 * prerendered. DEFAULT_PAGE_LOAD if it had not. |
| 365 */ |
| 366 public int loadUrl(final String url) throws IllegalArgumentException, Interr
uptedException { |
| 367 return loadUrlInTab(url, PageTransition.TYPED | PageTransition.FROM_ADDR
ESS_BAR, |
| 368 getActivity().getActivityTab()); |
| 369 } |
| 370 |
| 371 /** |
| 372 * @param url The url of the page to load. |
| 373 * @param pageTransition The type of transition. see |
| 374 * {@link org.chromium.content.browser.PageTransition} |
| 375 * for valid values. |
| 376 * @param tab The tab to load the url into. |
| 377 * @return FULL_PRERENDERED_PAGE_LOAD or PARTIAL_PRERENDERED_P
AGE_LOAD if the |
| 378 * page has been prerendered. DEFAULT_PAGE_LOAD if it
had not. |
| 379 */ |
| 380 public int loadUrlInTab(final String url, final int pageTransition, final Ta
b tab) |
| 381 throws InterruptedException { |
| 382 assertNotNull("Cannot load the url in a null tab", tab); |
| 383 final AtomicInteger result = new AtomicInteger(); |
| 384 |
| 385 ChromeTabUtils.waitForTabPageLoaded(tab, new Runnable() { |
| 386 @Override |
| 387 public void run() { |
| 388 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 389 @Override |
| 390 public void run() { |
| 391 result.set(tab.loadUrl( |
| 392 new LoadUrlParams(url, pageTransition))); |
| 393 } |
| 394 }); |
| 395 } |
| 396 }); |
| 397 getInstrumentation().waitForIdleSync(); |
| 398 return result.get(); |
| 399 } |
| 400 |
| 401 /** |
| 402 * Load a url in a new tab. The {@link Tab} will pretend to be created from
a link. |
| 403 * @param url The url of the page to load. |
| 404 */ |
| 405 public void loadUrlInNewTab(final String url) throws InterruptedException { |
| 406 // TODO(mariakhomenko): There is no current tab creator in document mode
, will need |
| 407 // additional logic here for Document tests. |
| 408 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext()))
{ |
| 409 fail("Document mode not yet supported."); |
| 410 } |
| 411 try { |
| 412 Tab tab = ThreadUtils.runOnUiThreadBlocking(new Callable<Tab>() { |
| 413 @Override |
| 414 public Tab call() throws Exception { |
| 415 return getActivity().getCurrentTabCreator() |
| 416 .launchUrl(url, TabLaunchType.FROM_LINK); |
| 417 } |
| 418 }); |
| 419 |
| 420 ChromeTabUtils.waitForTabPageLoaded(tab, url); |
| 421 getInstrumentation().waitForIdleSync(); |
| 422 } catch (ExecutionException e) { |
| 423 fail("Failed to create new tab"); |
| 424 } |
| 425 } |
| 426 |
| 427 /** |
| 428 * Load a url in a new tab. The {@link Tab} will pretend to be created from
a link. |
| 429 * @param url The url of the page to load. |
| 430 * @param incognito Whether the new tab should be incognito. |
| 431 */ |
| 432 public void loadUrlInNewTab(final String url, final boolean incognito) |
| 433 throws InterruptedException { |
| 434 Tab tab = null; |
| 435 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext()))
{ |
| 436 Runnable activityTrigger = new Runnable() { |
| 437 @Override |
| 438 public void run() { |
| 439 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 440 @Override |
| 441 public void run() { |
| 442 ChromeLauncherActivity.launchDocumentInstance(getAct
ivity(), incognito, |
| 443 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUN
D, url, |
| 444 DocumentMetricIds.STARTED_BY_UNKNOWN, |
| 445 PageTransition.AUTO_TOPLEVEL, |
| 446 false, null); |
| 447 } |
| 448 }); |
| 449 } |
| 450 }; |
| 451 final DocumentActivity activity = ActivityUtils.waitForActivity( |
| 452 getInstrumentation(), |
| 453 incognito ? IncognitoDocumentActivity.class : DocumentActivi
ty.class, |
| 454 activityTrigger); |
| 455 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
| 456 @Override |
| 457 public boolean isSatisfied() { |
| 458 return activity.getActivityTab() != null; |
| 459 } |
| 460 }); |
| 461 tab = activity.getActivityTab(); |
| 462 } else { |
| 463 try { |
| 464 tab = ThreadUtils.runOnUiThreadBlocking(new Callable<Tab>() { |
| 465 @Override |
| 466 public Tab call() throws Exception { |
| 467 return getActivity().getTabCreator(incognito) |
| 468 .launchUrl(url, TabLaunchType.FROM_LINK); |
| 469 } |
| 470 }); |
| 471 } catch (ExecutionException e) { |
| 472 fail("Failed to create new tab"); |
| 473 } |
| 474 } |
| 475 ChromeTabUtils.waitForTabPageLoaded(tab, url); |
| 476 getInstrumentation().waitForIdleSync(); |
| 477 } |
| 478 |
| 479 /** |
| 480 * Simulates starting Main Activity from launcher, blocks until it is starte
d. |
| 481 */ |
| 482 protected void startMainActivityFromLauncher() throws InterruptedException { |
| 483 startMainActivityWithURL(null); |
| 484 } |
| 485 |
| 486 /** |
| 487 * Starts the Main activity on the specified URL. Passing a null URL ensures
the default page is |
| 488 * loaded, which is the NTP with a new profile . |
| 489 */ |
| 490 protected void startMainActivityWithURL(String url) throws InterruptedExcept
ion { |
| 491 // Only launch Chrome. |
| 492 Intent intent = new Intent( |
| 493 TextUtils.isEmpty(url) ? Intent.ACTION_MAIN : Intent.ACTION_VIEW
); |
| 494 intent.addCategory(Intent.CATEGORY_LAUNCHER); |
| 495 startMainActivityFromIntent(intent, url); |
| 496 } |
| 497 |
| 498 /** |
| 499 * Starts the Main activity and open a blank page. |
| 500 * This is faster and less flakyness-prone than starting on the NTP. |
| 501 */ |
| 502 protected void startMainActivityOnBlankPage() throws InterruptedException { |
| 503 startMainActivityWithURL("about:blank"); |
| 504 } |
| 505 |
| 506 /** |
| 507 * Starts the Main activity as if it was started from an external applicatio
n, on the specified |
| 508 * URL. |
| 509 */ |
| 510 protected void startMainActivityFromExternalApp(String url, String appId) |
| 511 throws InterruptedException { |
| 512 Intent intent = new Intent(Intent.ACTION_VIEW); |
| 513 if (appId != null) { |
| 514 intent.putExtra(Browser.EXTRA_APPLICATION_ID, appId); |
| 515 } |
| 516 startMainActivityFromIntent(intent, url); |
| 517 } |
| 518 |
| 519 /** |
| 520 * Starts the Main activity using the passed intent, and using the specified
URL. |
| 521 * This method waits for DEFERRED_STARTUP to fire as well as a subsequent |
| 522 * idle-sync of the main looper thread, and the initial tab must either |
| 523 * complete its load or it must crash before this method will return. |
| 524 */ |
| 525 protected void startMainActivityFromIntent(Intent intent, String url) |
| 526 throws InterruptedException { |
| 527 prepareUrlIntent(intent, url); |
| 528 |
| 529 final boolean isDocumentMode = |
| 530 FeatureUtilities.isDocumentMode(getInstrumentation().getContext(
)); |
| 531 |
| 532 startActivityCompletely(intent); |
| 533 |
| 534 assertTrue("Tab never selected/initialized.", |
| 535 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
| 536 @Override |
| 537 public boolean isSatisfied() { |
| 538 return getActivity().getActivityTab() != null; |
| 539 } |
| 540 })); |
| 541 Tab tab = getActivity().getActivityTab(); |
| 542 |
| 543 ChromeTabUtils.waitForTabPageLoaded(tab, (String) null); |
| 544 |
| 545 if (!isDocumentMode && tab != null && NewTabPage.isNTPUrl(tab.getUrl()))
{ |
| 546 boolean ntpReady = NewTabPageTestUtils.waitForNtpLoaded(tab); |
| 547 if (!ntpReady && tab.isShowingSadTab()) { |
| 548 fail("Renderer crashed before NTP finished loading. " |
| 549 + "Look at logcat for renderer stack dump."); |
| 550 } |
| 551 assertTrue("Initial NTP never fully loaded.", ntpReady); |
| 552 } |
| 553 |
| 554 assertTrue("Deferred startup never completed", |
| 555 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
| 556 @Override |
| 557 public boolean isSatisfied() { |
| 558 return DeferredStartupHandler.getInstance().isDeferredSt
artupComplete(); |
| 559 } |
| 560 })); |
| 561 |
| 562 assertNotNull(tab); |
| 563 assertNotNull(tab.getView()); |
| 564 getInstrumentation().waitForIdleSync(); |
| 565 } |
| 566 |
| 567 /** |
| 568 * Prepares a URL intent to start the activity. |
| 569 * @param intent the intent to be modified |
| 570 * @param url the URL to be used (may be null) |
| 571 */ |
| 572 protected Intent prepareUrlIntent(Intent intent, String url) { |
| 573 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| 574 intent.setComponent(new ComponentName(getInstrumentation().getTargetCont
ext(), |
| 575 ChromeLauncherActivity.class)); |
| 576 |
| 577 if (url != null) { |
| 578 intent.setData(Uri.parse(url)); |
| 579 } |
| 580 |
| 581 try { |
| 582 Method method = getClass().getMethod(getName(), (Class[]) null); |
| 583 if (method.isAnnotationPresent(RenderProcessLimit.class)) { |
| 584 RenderProcessLimit limit = method.getAnnotation(RenderProcessLim
it.class); |
| 585 intent.putExtra(ChromeTabbedActivity.INTENT_EXTRA_TEST_RENDER_PR
OCESS_LIMIT, |
| 586 limit.value()); |
| 587 } |
| 588 } catch (Exception ex) { |
| 589 // Ignore exception. |
| 590 } |
| 591 return intent; |
| 592 } |
| 593 |
| 594 /** |
| 595 * Open an incognito tab by invoking the 'new incognito' menu item. |
| 596 * Returns when receiving the 'PAGE_LOAD_FINISHED' notification. |
| 597 */ |
| 598 protected void newIncognitoTabFromMenu() throws InterruptedException { |
| 599 Tab tab = null; |
| 600 |
| 601 if (FeatureUtilities.isDocumentMode(getInstrumentation().getContext()))
{ |
| 602 final IncognitoDocumentActivity activity = ActivityUtils.waitForActi
vity( |
| 603 getInstrumentation(), IncognitoDocumentActivity.class, |
| 604 new Runnable() { |
| 605 @Override |
| 606 public void run() { |
| 607 MenuUtils.invokeCustomMenuActionSync( |
| 608 getInstrumentation(), getActivity(), |
| 609 R.id.new_incognito_tab_menu_id); |
| 610 } |
| 611 }); |
| 612 |
| 613 CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
| 614 @Override |
| 615 public boolean isSatisfied() { |
| 616 return activity.getActivityTab() != null; |
| 617 } |
| 618 }); |
| 619 |
| 620 tab = activity.getActivityTab(); |
| 621 } else { |
| 622 final CallbackHelper createdCallback = new CallbackHelper(); |
| 623 final CallbackHelper selectedCallback = new CallbackHelper(); |
| 624 |
| 625 TabModel incognitoTabModel = getActivity().getTabModelSelector().get
Model(true); |
| 626 TabModelObserver observer = new EmptyTabModelObserver() { |
| 627 @Override |
| 628 public void didAddTab(Tab tab, TabLaunchType type) { |
| 629 createdCallback.notifyCalled(); |
| 630 } |
| 631 |
| 632 @Override |
| 633 public void didSelectTab(Tab tab, TabSelectionType type, int las
tId) { |
| 634 selectedCallback.notifyCalled(); |
| 635 } |
| 636 }; |
| 637 incognitoTabModel.addObserver(observer); |
| 638 |
| 639 MenuUtils.invokeCustomMenuActionSync(getInstrumentation(), getActivi
ty(), |
| 640 R.id.new_incognito_tab_menu_id); |
| 641 |
| 642 try { |
| 643 createdCallback.waitForCallback(0); |
| 644 } catch (TimeoutException ex) { |
| 645 fail("Never received tab created event"); |
| 646 } |
| 647 try { |
| 648 selectedCallback.waitForCallback(0); |
| 649 } catch (TimeoutException ex) { |
| 650 fail("Never received tab selected event"); |
| 651 } |
| 652 incognitoTabModel.removeObserver(observer); |
| 653 |
| 654 tab = getActivity().getActivityTab(); |
| 655 } |
| 656 |
| 657 ChromeTabUtils.waitForTabPageLoaded(tab, (String) null); |
| 658 Assert.assertTrue("NTP never fully loaded.", |
| 659 NewTabPageTestUtils.waitForNtpLoaded(tab)); |
| 660 getInstrumentation().waitForIdleSync(); |
| 661 Log.d(TAG, "newIncognitoTabFromMenu <<"); |
| 662 } |
| 663 |
| 664 /** |
| 665 * New multiple incognito tabs by invoking the 'new incognito' menu item n t
imes. |
| 666 * @param n The number of tabs you want to create. |
| 667 */ |
| 668 protected void newIncognitoTabsFromMenu(int n) |
| 669 throws InterruptedException { |
| 670 while (n > 0) { |
| 671 newIncognitoTabFromMenu(); |
| 672 --n; |
| 673 } |
| 674 } |
| 675 |
| 676 /** |
| 677 * @return The number of incognito tabs currently open. |
| 678 */ |
| 679 protected int incognitoTabsCount() { |
| 680 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer
>() { |
| 681 @Override |
| 682 public Integer call() { |
| 683 TabModelSelector tabModelSelector; |
| 684 if (FeatureUtilities.isDocumentMode(getInstrumentation().getCont
ext())) { |
| 685 tabModelSelector = ChromeMobileApplication.getDocumentTabMod
elSelector(); |
| 686 } else { |
| 687 tabModelSelector = getActivity().getTabModelSelector(); |
| 688 } |
| 689 return tabModelSelector.getModel(true).getCount(); |
| 690 } |
| 691 }); |
| 692 } |
| 693 |
| 694 /** |
| 695 * Types the passed text in the omnibox to trigger a navigation. You can pas
s a URL or a search |
| 696 * term. |
| 697 * <p> |
| 698 * Note that this code triggers suggestions and prerendering. Unless you ar
e testing these |
| 699 * features specifically, you should use loadUrl() which is less prone to fl
akyness. |
| 700 * @param url The Url to navigate to. |
| 701 * @return the url in the UrlBar. |
| 702 * @throws InterruptedException |
| 703 */ |
| 704 public String typeInOmniboxAndNavigate(final String url) throws InterruptedE
xception { |
| 705 final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
| 706 assertNotNull("urlBar is null", urlBar); |
| 707 getInstrumentation().runOnMainSync(new Runnable() { |
| 708 @Override |
| 709 public void run() { |
| 710 urlBar.requestFocus(); |
| 711 urlBar.setText(url); |
| 712 } |
| 713 }); |
| 714 final LocationBarLayout locationBar = |
| 715 (LocationBarLayout) getActivity().findViewById(R.id.location_bar
); |
| 716 assertTrue("Omnibox Suggestions never shown.", |
| 717 OmniboxTestUtils.waitForOmniboxSuggestions(locationBar)); |
| 718 |
| 719 Tab currentTab = getActivity().getActivityTab(); |
| 720 final CallbackHelper loadedCallback = new CallbackHelper(); |
| 721 final AtomicBoolean tabCrashReceived = new AtomicBoolean(); |
| 722 currentTab.addObserver(new EmptyTabObserver() { |
| 723 @Override |
| 724 public void onPageLoadFinished(Tab tab) { |
| 725 loadedCallback.notifyCalled(); |
| 726 tab.removeObserver(this); |
| 727 } |
| 728 |
| 729 @Override |
| 730 public void onCrash(Tab tab, boolean sadTabShown) { |
| 731 tabCrashReceived.set(true); |
| 732 tab.removeObserver(this); |
| 733 } |
| 734 }); |
| 735 |
| 736 // Loads the url. |
| 737 KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCO
DE_ENTER); |
| 738 |
| 739 boolean pageLoadReceived = true; |
| 740 try { |
| 741 loadedCallback.waitForCallback(0); |
| 742 } catch (TimeoutException ex) { |
| 743 pageLoadReceived = false; |
| 744 } |
| 745 |
| 746 assertTrue("Neither PAGE_LOAD_FINISHED nor a TAB_CRASHED event was recei
ved", |
| 747 pageLoadReceived || tabCrashReceived.get()); |
| 748 getInstrumentation().waitForIdleSync(); |
| 749 |
| 750 // The title has been set before the page notification was broadcast, so
it is safe to |
| 751 // access the title. |
| 752 return urlBar.getText().toString(); |
| 753 } |
| 754 |
| 755 /** |
| 756 * Looks up the Omnibox in the view hierarchy and types the specified |
| 757 * text into it, requesting focus and using an inter-character delay of |
| 758 * 200ms. |
| 759 * |
| 760 * @param oneCharAtATime Whether to type text one character at a time or all
at once. |
| 761 * |
| 762 * @throws InterruptedException |
| 763 */ |
| 764 public void typeInOmnibox(final String text, final boolean oneCharAtATime) |
| 765 throws InterruptedException { |
| 766 final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); |
| 767 assertNotNull(urlBar); |
| 768 |
| 769 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 770 @Override |
| 771 public void run() { |
| 772 urlBar.requestFocus(); |
| 773 if (!oneCharAtATime) { |
| 774 urlBar.setText(text); |
| 775 } |
| 776 } |
| 777 }); |
| 778 |
| 779 if (oneCharAtATime) { |
| 780 final Instrumentation instrumentation = getInstrumentation(); |
| 781 for (int i = 0; i < text.length(); ++i) { |
| 782 instrumentation.sendStringSync(text.substring(i, i + 1)); |
| 783 // Let's put some delay between key strokes to simulate a user p
ressing the keys. |
| 784 Thread.sleep(20); |
| 785 } |
| 786 } |
| 787 } |
| 788 |
| 789 /** |
| 790 * Searches for a given suggestion after typing given text in the Omnibox. |
| 791 * |
| 792 * @param inputText Input text to type into the Omnibox. |
| 793 * @param displayText Suggestion text expected to be found. Passing in null
ignores this field. |
| 794 * @param url URL expected to be found. Passing in null ignores this field. |
| 795 * @param type Type of suggestion expected to be found. Passing in null igno
res this field. |
| 796 * |
| 797 * @throws InterruptedException |
| 798 */ |
| 799 protected OmniboxSuggestion findOmniboxSuggestion(String inputText, String d
isplayText, |
| 800 String url, OmniboxSuggestion.Type type) throws InterruptedException
{ |
| 801 long endTime = System.currentTimeMillis() + OMNIBOX_FIND_SUGGESTION_TIME
OUT_MS; |
| 802 |
| 803 // Multiple suggestion events may occur before the one we're interested
in is received. |
| 804 final CallbackHelper onSuggestionsReceivedHelper = new CallbackHelper(); |
| 805 final LocationBarLayout locationBar = |
| 806 (LocationBarLayout) getActivity().findViewById(R.id.location_bar
); |
| 807 locationBar.setAutocompleteController(new AutocompleteController(locatio
nBar) { |
| 808 @Override |
| 809 public void onSuggestionsReceived( |
| 810 List<OmniboxSuggestion> suggestions, |
| 811 String inlineAutocompleteText, |
| 812 long currentNativeAutocompleteResult) { |
| 813 super.onSuggestionsReceived( |
| 814 suggestions, inlineAutocompleteText, currentNativeAutoco
mpleteResult); |
| 815 onSuggestionsReceivedHelper.notifyCalled(); |
| 816 } |
| 817 }); |
| 818 |
| 819 try { |
| 820 typeInOmnibox(inputText, false); |
| 821 |
| 822 while (true) { |
| 823 try { |
| 824 int callbackCount = onSuggestionsReceivedHelper.getCallCount
(); |
| 825 onSuggestionsReceivedHelper.waitForCallback( |
| 826 callbackCount, 1, |
| 827 endTime - System.currentTimeMillis(), TimeUnit.MILLI
SECONDS); |
| 828 } catch (TimeoutException exception) { |
| 829 return null; |
| 830 } |
| 831 |
| 832 // Wait for suggestions to show up. |
| 833 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { |
| 834 @Override |
| 835 public boolean isSatisfied() { |
| 836 return ((LocationBarLayout) getActivity().findViewById( |
| 837 R.id.location_bar)).getSuggestionList() != null; |
| 838 } |
| 839 }, 3000, 10)); |
| 840 final ListView suggestionListView = locationBar.getSuggestionLis
t(); |
| 841 OmniboxResultItem popupItem = (OmniboxResultItem) suggestionList
View |
| 842 .getItemAtPosition(0); |
| 843 OmniboxSuggestion suggestion = popupItem.getSuggestion(); |
| 844 if (suggestionListView.getCount() == 1 |
| 845 && suggestion.getDisplayText().equals(inputText) |
| 846 && !suggestion.getDisplayText().equals(displayText)) { |
| 847 // If there is only one suggestion and it's the same as inpu
tText, |
| 848 // wait for other suggestions before looking for the one we
want. |
| 849 CriteriaHelper.pollForCriteria(new Criteria() { |
| 850 @Override |
| 851 public boolean isSatisfied() { |
| 852 return suggestionListView.getCount() > 1; |
| 853 } |
| 854 }, 3000, 10); |
| 855 } |
| 856 int count = suggestionListView.getCount(); |
| 857 for (int i = 0; i < count; i++) { |
| 858 popupItem = (OmniboxResultItem) suggestionListView.getItemAt
Position(i); |
| 859 suggestion = popupItem.getSuggestion(); |
| 860 if (type != null && suggestion.getType() != type) { |
| 861 continue; |
| 862 } |
| 863 if (displayText != null && !suggestion.getDisplayText().equa
ls(displayText)) { |
| 864 continue; |
| 865 } |
| 866 if (url != null && !suggestion.getUrl().equals(url)) { |
| 867 continue; |
| 868 } |
| 869 return suggestion; |
| 870 } |
| 871 } |
| 872 } finally { |
| 873 locationBar.setAutocompleteController(new AutocompleteController(loc
ationBar)); |
| 874 } |
| 875 } |
| 876 |
| 877 /** |
| 878 * Returns the infobars being displayed by the current tab, or null if they
don't exist. |
| 879 */ |
| 880 protected List<InfoBar> getInfoBars() { |
| 881 Tab currentTab = getActivity().getActivityTab(); |
| 882 if (currentTab == null) { |
| 883 return null; |
| 884 } |
| 885 |
| 886 if (currentTab.getInfoBarContainer() != null) { |
| 887 return currentTab.getInfoBarContainer().getInfoBars(); |
| 888 } else { |
| 889 return null; |
| 890 } |
| 891 } |
| 892 |
| 893 /** |
| 894 * Launches the preferences menu and starts the preferences activity named f
ragmentName. |
| 895 * Returns the activity that was started. |
| 896 */ |
| 897 protected Preferences startPreferences(String fragmentName) { |
| 898 Context context = getInstrumentation().getTargetContext(); |
| 899 Intent intent = PreferencesLauncher.createIntentForSettingsPage(context,
fragmentName); |
| 900 Activity activity = getInstrumentation().startActivitySync(intent); |
| 901 assertTrue(activity instanceof Preferences); |
| 902 return (Preferences) activity; |
| 903 } |
| 904 |
| 905 /** |
| 906 * Executes the given snippet of JavaScript code within the current tab. Ret
urns the result of |
| 907 * its execution in JSON format. |
| 908 * @throws InterruptedException |
| 909 */ |
| 910 protected String runJavaScriptCodeInCurrentTab(String code) throws Interrupt
edException, |
| 911 TimeoutException { |
| 912 return JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| 913 getActivity().getCurrentContentViewCore().getWebContents(), code
); |
| 914 } |
| 915 |
| 916 @Override |
| 917 protected void runTest() throws Throwable { |
| 918 boolean shouldRun = true; |
| 919 String perfTagAnalysisString = ""; |
| 920 try { |
| 921 shouldRun = RestrictedInstrumentationTestCase.shouldRunTest(this); |
| 922 perfTagAnalysisString = setupPotentialPerfTest(shouldRun); |
| 923 } catch (Exception e) { |
| 924 // eat the exception here; super.runTest() will catch it again and h
andle it properly |
| 925 } |
| 926 |
| 927 if (shouldRun) super.runTest(); |
| 928 |
| 929 endPerfTest(perfTagAnalysisString); |
| 930 } |
| 931 |
| 932 /** |
| 933 * Waits till the ContentViewCore receives the expected page scale factor |
| 934 * from the compositor and asserts that this happens. |
| 935 * |
| 936 * Upstream {@code ContentShellTestBase} has the same copy. Also, this is a
temporary solution |
| 937 * for waiting a page load. Please refer to the bug at the upstream function
. |
| 938 */ |
| 939 protected void assertWaitForPageScaleFactorMatch(final float expectedScale) |
| 940 throws InterruptedException { |
| 941 boolean scaleFactorMatch = CriteriaHelper.pollForCriteria(new Criteria()
{ |
| 942 @Override |
| 943 public boolean isSatisfied() { |
| 944 return getActivity().getCurrentContentViewCore().getScale() |
| 945 == expectedScale; |
| 946 } |
| 947 }); |
| 948 assertTrue("Expecting scale factor of: " + expectedScale + ", got: " |
| 949 + getActivity().getCurrentContentViewCore().getScale(), scal
eFactorMatch); |
| 950 } |
| 951 |
| 952 /** |
| 953 * This method creates a special string that tells the python test harness w
hat |
| 954 * trace calls to track for this particular test run. It can support multip
le trace calls for |
| 955 * each test and will make a new graph entry for all of them. It should be
noted that this |
| 956 * method eats all exceptions. This is so that it can never be the cause of
a test failure. |
| 957 * We still need to call this method even if we know the test will not run (
ie: willTestRun is |
| 958 * false). This is because this method lets the python test harness know no
t to expect any |
| 959 * perf output in this case. In the case that the autoTrace parameter is se
t for the current |
| 960 * test method, this will also start the PerfTrace facility automatically. |
| 961 * |
| 962 * @param willTestRun Whether or not this test will actually be run. |
| 963 * @return A specially formatted string that contains which JSON perf marker
s to look at. This |
| 964 * will be analyzed by the perf test harness. |
| 965 */ |
| 966 @SuppressFBWarnings({ |
| 967 "REC_CATCH_EXCEPTION", |
| 968 "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", |
| 969 }) |
| 970 private String setupPotentialPerfTest(boolean willTestRun) { |
| 971 File perfFile = getInstrumentation().getTargetContext().getFileStreamPat
h( |
| 972 PERF_OUTPUT_FILE); |
| 973 perfFile.delete(); |
| 974 PerfTraceEvent.setOutputFile(perfFile); |
| 975 |
| 976 String perfAnnotationString = ""; |
| 977 |
| 978 try { |
| 979 Method method = getClass().getMethod(getName(), (Class[]) null); |
| 980 PerfTest annotation = method.getAnnotation(PerfTest.class); |
| 981 if (annotation != null) { |
| 982 StringBuilder annotationData = new StringBuilder(); |
| 983 annotationData.append(String.format(PERF_ANNOTATION_FORMAT, meth
od.getName())); |
| 984 |
| 985 if (!willTestRun) { |
| 986 annotationData.append(PERF_NORUN_TAG); |
| 987 } else { |
| 988 // Grab the minimum number of trace calls we will track (if
names(), |
| 989 // graphNames(), and graphValues() do not have the same numb
er of elements, we |
| 990 // will track as many as we can given the data available. |
| 991 final int maxIndex = Math.min(annotation.traceNames().length
, Math.min( |
| 992 annotation.graphNames().length, annotation.seriesNam
es().length)); |
| 993 |
| 994 List<String> allNames = new LinkedList<String>(); |
| 995 for (int i = 0; i < maxIndex; ++i) { |
| 996 // Prune out all of ',' and ';' from the strings. Repla
ce them with '-'. |
| 997 String name = annotation.traceNames()[i].replaceAll("[,;
]", "-"); |
| 998 allNames.add(name); |
| 999 String graphName = annotation.graphNames()[i].replaceAll
("[,;]", "-"); |
| 1000 String seriesName = annotation.seriesNames()[i].replaceA
ll("[,;]", "-"); |
| 1001 if (annotation.traceTiming()) { |
| 1002 annotationData.append(name).append(",") |
| 1003 .append(graphName).append(",") |
| 1004 .append(seriesName).append(';'); |
| 1005 } |
| 1006 |
| 1007 // If memory tracing is enabled, add an additional graph
for each one |
| 1008 // defined to track timing perf that will track the corr
esponding memory |
| 1009 // usage. |
| 1010 // Keep the series name the same, but just append a memo
ry identifying |
| 1011 // prefix to the graph. |
| 1012 if (annotation.traceMemory()) { |
| 1013 String memName = PerfTraceEvent.makeMemoryTraceNameF
romTimingName(name); |
| 1014 String memGraphName = PerfTraceEvent.makeSafeTraceNa
me( |
| 1015 graphName, MEMORY_TRACE_GRAPH_SUFFIX); |
| 1016 annotationData.append(memName).append(",") |
| 1017 .append(memGraphName).append(",") |
| 1018 .append(seriesName).append(';'); |
| 1019 allNames.add(memName); |
| 1020 } |
| 1021 } |
| 1022 // We only record perf trace events for the names explicitly
listed. |
| 1023 PerfTraceEvent.setFilter(allNames); |
| 1024 |
| 1025 // Figure out if we should automatically start or stop the t
race. |
| 1026 if (annotation.autoTrace()) { |
| 1027 PerfTraceEvent.setEnabled(true); |
| 1028 } |
| 1029 PerfTraceEvent.setTimingTrackingEnabled(annotation.traceTimi
ng()); |
| 1030 PerfTraceEvent.setMemoryTrackingEnabled(annotation.traceMemo
ry()); |
| 1031 } |
| 1032 |
| 1033 perfAnnotationString = annotationData.toString(); |
| 1034 } |
| 1035 } catch (Exception ex) { |
| 1036 // Eat exception here. |
| 1037 } |
| 1038 |
| 1039 return perfAnnotationString; |
| 1040 } |
| 1041 |
| 1042 /** |
| 1043 * This handles cleaning up the performance component of this test if it was
a UI Perf test. |
| 1044 * This includes potentially shutting down PerfTraceEvent. This method eats
all exceptions so |
| 1045 * that it can never be the cause of a test failure. The test harness will
wait for |
| 1046 * {@code perfTagAnalysisString} to show up in the logcat before processing
the JSON perf file, |
| 1047 * giving this method the chance to flush and dump the performance data befo
re the harness reads |
| 1048 * it. |
| 1049 * |
| 1050 * @param perfTagAnalysisString A specially formatted string that tells the
perf test harness |
| 1051 * which perf tags to analyze. |
| 1052 */ |
| 1053 private void endPerfTest(String perfTagAnalysisString) { |
| 1054 try { |
| 1055 Method method = getClass().getMethod(getName(), (Class[]) null); |
| 1056 PerfTest annotation = method.getAnnotation(PerfTest.class); |
| 1057 if (annotation != null) { |
| 1058 if (PerfTraceEvent.enabled()) { |
| 1059 PerfTraceEvent.setEnabled(false); |
| 1060 } |
| 1061 |
| 1062 System.out.println(perfTagAnalysisString); |
| 1063 } |
| 1064 } catch (Exception ex) { |
| 1065 // Eat exception here. |
| 1066 } |
| 1067 } |
| 1068 } |
OLD | NEW |