1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.server.wm.lifecycle; 18 19 import static android.server.wm.StateLogger.log; 20 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_CREATE; 21 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_DESTROY; 22 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED; 23 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE; 24 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE; 25 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_RESTART; 26 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_RESUME; 27 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_START; 28 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_STOP; 29 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_TOP_POSITION_GAINED; 30 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_TOP_POSITION_LOST; 31 32 import static org.junit.Assert.assertEquals; 33 import static org.junit.Assert.assertFalse; 34 import static org.junit.Assert.assertTrue; 35 import static org.junit.Assert.fail; 36 37 import android.app.Activity; 38 import android.content.Context; 39 import android.content.pm.PackageManager; 40 import android.server.wm.lifecycle.ActivityLifecycleClientTestBase.CallbackTrackingActivity; 41 import android.server.wm.lifecycle.ActivityLifecycleClientTestBase.ConfigChangeHandlingActivity; 42 import android.server.wm.lifecycle.LifecycleLog.ActivityCallback; 43 import android.util.Pair; 44 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.List; 48 49 /** Util class that verifies correct activity state transition sequences. */ 50 class LifecycleVerifier { 51 52 private static final Class CALLBACK_TRACKING_CLASS = CallbackTrackingActivity.class; 53 private static final Class CONFIG_CHANGE_HANDLING_CLASS = ConfigChangeHandlingActivity.class; 54 assertLaunchSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, LifecycleLog.ActivityCallback... expectedSubsequentEvents)55 static void assertLaunchSequence(Class<? extends Activity> activityClass, 56 LifecycleLog lifecycleLog, LifecycleLog.ActivityCallback... expectedSubsequentEvents) { 57 final List<LifecycleLog.ActivityCallback> observedTransitions = 58 lifecycleLog.getActivityLog(activityClass); 59 log("Observed sequence: " + observedTransitions); 60 final String errorMessage = errorDuringTransition(activityClass, "launch"); 61 62 final List<LifecycleLog.ActivityCallback> launchSequence = getLaunchSequence(activityClass); 63 final List<LifecycleLog.ActivityCallback> expectedTransitions; 64 expectedTransitions = new ArrayList<>(launchSequence.size() + 65 expectedSubsequentEvents.length); 66 expectedTransitions.addAll(launchSequence); 67 expectedTransitions.addAll(Arrays.asList(expectedSubsequentEvents)); 68 assertEquals(errorMessage, expectedTransitions, observedTransitions); 69 } 70 getLaunchSequence( Class<? extends Activity> activityClass)71 public static List<LifecycleLog.ActivityCallback> getLaunchSequence( 72 Class<? extends Activity> activityClass) { 73 return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass) 74 ? Arrays.asList(ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, 75 ON_TOP_POSITION_GAINED) 76 : Arrays.asList(ON_CREATE, ON_START, ON_RESUME); 77 } 78 getLaunchAndDestroySequence( Class<? extends Activity> activityClass)79 static List<ActivityCallback> getLaunchAndDestroySequence( 80 Class<? extends Activity> activityClass) { 81 final List<ActivityCallback> expectedTransitions = new ArrayList<>(); 82 expectedTransitions.addAll(getLaunchSequence(activityClass)); 83 expectedTransitions.addAll(getResumeToDestroySequence(activityClass)); 84 return expectedTransitions; 85 } 86 assertLaunchSequence(Class<? extends Activity> launchingActivity, Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog, boolean launchingIsTranslucent)87 static void assertLaunchSequence(Class<? extends Activity> launchingActivity, 88 Class<? extends Activity> existingActivity, LifecycleLog lifecycleLog, 89 boolean launchingIsTranslucent) { 90 final boolean includingCallbacks; 91 if (CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity) 92 && CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) { 93 includingCallbacks = true; 94 } else if (!CALLBACK_TRACKING_CLASS.isAssignableFrom(launchingActivity) 95 && !CALLBACK_TRACKING_CLASS.isAssignableFrom(existingActivity)) { 96 includingCallbacks = false; 97 } else { 98 throw new IllegalArgumentException("Mixed types of callback tracking not supported. " 99 + "Both activities must support or not support callback tracking " 100 + "simultaneously"); 101 } 102 103 104 final List<Pair<String, ActivityCallback>> observedTransitions = lifecycleLog.getLog(); 105 log("Observed sequence: " + observedTransitions); 106 final String errorMessage = errorDuringTransition(launchingActivity, "launch"); 107 108 final List<Pair<String, ActivityCallback>> expectedTransitions = new ArrayList<>(); 109 // First top position will be lost 110 if (includingCallbacks) { 111 expectedTransitions.add(transition(existingActivity, ON_TOP_POSITION_LOST)); 112 } 113 // Next the existing activity is paused and the next one is launched 114 expectedTransitions.add(transition(existingActivity, ON_PAUSE)); 115 expectedTransitions.add(transition(launchingActivity, ON_CREATE)); 116 expectedTransitions.add(transition(launchingActivity, ON_START)); 117 if (includingCallbacks) { 118 expectedTransitions.add(transition(launchingActivity, ON_POST_CREATE)); 119 } 120 expectedTransitions.add(transition(launchingActivity, ON_RESUME)); 121 if (includingCallbacks) { 122 expectedTransitions.add(transition(launchingActivity, ON_TOP_POSITION_GAINED)); 123 } 124 if (!launchingIsTranslucent) { 125 expectedTransitions.add(transition(existingActivity, ON_STOP)); 126 } 127 128 assertEquals(errorMessage, expectedTransitions, observedTransitions); 129 } 130 assertLaunchAndStopSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)131 static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass, 132 LifecycleLog lifecycleLog) { 133 assertLaunchAndStopSequence(activityClass, lifecycleLog, 134 false /* onTop */); 135 } 136 assertLaunchAndStopSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, boolean onTop)137 static void assertLaunchAndStopSequence(Class<? extends Activity> activityClass, 138 LifecycleLog lifecycleLog, boolean onTop) { 139 final List<ActivityCallback> observedTransitions = 140 lifecycleLog.getActivityLog(activityClass); 141 log("Observed sequence: " + observedTransitions); 142 final String errorMessage = errorDuringTransition(activityClass, "launch and stop"); 143 144 final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass); 145 146 final List<ActivityCallback> expectedTransitions = new ArrayList<>( 147 Arrays.asList(ON_CREATE, ON_START)); 148 if (includeCallbacks) { 149 expectedTransitions.add(ON_POST_CREATE); 150 } 151 expectedTransitions.add(ON_RESUME); 152 if (includeCallbacks && onTop) { 153 expectedTransitions.addAll(Arrays.asList(ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST)); 154 } 155 expectedTransitions.addAll(Arrays.asList(ON_PAUSE, ON_STOP)); 156 assertEquals(errorMessage, expectedTransitions, observedTransitions); 157 } 158 assertLaunchAndPauseSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)159 static void assertLaunchAndPauseSequence(Class<? extends Activity> activityClass, 160 LifecycleLog lifecycleLog) { 161 final List<ActivityCallback> observedTransitions = 162 lifecycleLog.getActivityLog(activityClass); 163 log("Observed sequence: " + observedTransitions); 164 final String errorMessage = errorDuringTransition(activityClass, "launch and pause"); 165 166 final List<ActivityCallback> expectedTransitions = 167 Arrays.asList(ON_CREATE, ON_START, ON_RESUME, ON_PAUSE); 168 assertEquals(errorMessage, expectedTransitions, observedTransitions); 169 } 170 assertRestartSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)171 static void assertRestartSequence(Class<? extends Activity> activityClass, 172 LifecycleLog lifecycleLog) { 173 final List<LifecycleLog.ActivityCallback> observedTransitions = 174 lifecycleLog.getActivityLog(activityClass); 175 log("Observed sequence: " + observedTransitions); 176 final String errorMessage = errorDuringTransition(activityClass, "restart"); 177 178 final List<LifecycleLog.ActivityCallback> expectedTransitions = 179 Arrays.asList(ON_RESTART, ON_START); 180 assertEquals(errorMessage, expectedTransitions, observedTransitions); 181 } 182 assertRestartAndResumeSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)183 static void assertRestartAndResumeSequence(Class<? extends Activity> activityClass, 184 LifecycleLog lifecycleLog) { 185 final List<LifecycleLog.ActivityCallback> observedTransitions = 186 lifecycleLog.getActivityLog(activityClass); 187 log("Observed sequence: " + observedTransitions); 188 final String errorMessage = errorDuringTransition(activityClass, "restart and pause"); 189 190 final List<LifecycleLog.ActivityCallback> expectedTransitions = 191 Arrays.asList(ON_RESTART, ON_START, ON_RESUME); 192 assertEquals(errorMessage, expectedTransitions, observedTransitions); 193 } 194 195 /** 196 * TODO(b/192274045): In Automotive, we tolerate superfluous lifecycle events between the first 197 * lifecycle events and the last one until any discrepancy between ActivityManager and Keyguard 198 * state is resolved. 199 */ assertRestartAndResumeSubSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)200 static void assertRestartAndResumeSubSequence(Class<? extends Activity> activityClass, 201 LifecycleLog lifecycleLog) { 202 final List<LifecycleLog.ActivityCallback> observedTransitions = 203 lifecycleLog.getActivityLog(activityClass); 204 log("Observed sequence: " + observedTransitions); 205 206 final List<Pair<String, ActivityCallback>> expectedTransitions = 207 Arrays.asList(transition(activityClass, ON_RESTART), 208 transition(activityClass, ON_START), transition(activityClass, ON_RESUME)); 209 210 assertOrder(lifecycleLog, expectedTransitions, "restart and resume"); 211 } 212 assertRecreateAndResumeSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)213 static void assertRecreateAndResumeSequence(Class<? extends Activity> activityClass, 214 LifecycleLog lifecycleLog) { 215 final List<LifecycleLog.ActivityCallback> observedTransitions = 216 lifecycleLog.getActivityLog(activityClass); 217 log("Observed sequence: " + observedTransitions); 218 final String errorMessage = errorDuringTransition(activityClass, "recreateA and pause"); 219 220 final List<LifecycleLog.ActivityCallback> expectedTransitions = 221 Arrays.asList(ON_DESTROY, ON_CREATE, ON_START, ON_RESUME); 222 assertEquals(errorMessage, expectedTransitions, observedTransitions); 223 } 224 assertLaunchAndDestroySequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)225 static void assertLaunchAndDestroySequence(Class<? extends Activity> activityClass, 226 LifecycleLog lifecycleLog) { 227 final List<LifecycleLog.ActivityCallback> observedTransitions = 228 lifecycleLog.getActivityLog(activityClass); 229 log("Observed sequence: " + observedTransitions); 230 final String errorMessage = errorDuringTransition(activityClass, "launch and destroy"); 231 232 final List<LifecycleLog.ActivityCallback> expectedTransitions = Arrays.asList( 233 ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY); 234 assertEquals(errorMessage, expectedTransitions, observedTransitions); 235 } 236 assertResumeToDestroySequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)237 static void assertResumeToDestroySequence(Class<? extends Activity> activityClass, 238 LifecycleLog lifecycleLog) { 239 final List<LifecycleLog.ActivityCallback> observedTransitions = 240 lifecycleLog.getActivityLog(activityClass); 241 log("Observed sequence: " + observedTransitions); 242 final String errorMessage = errorDuringTransition(activityClass, "launch and destroy"); 243 244 final List<LifecycleLog.ActivityCallback> expectedTransitions = 245 getResumeToDestroySequence(activityClass); 246 assertEquals(errorMessage, expectedTransitions, observedTransitions); 247 } 248 getResumeToDestroySequence( Class<? extends Activity> activityClass)249 static List<LifecycleLog.ActivityCallback> getResumeToDestroySequence( 250 Class<? extends Activity> activityClass) { 251 return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass) 252 ? Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY) 253 : Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY); 254 } 255 assertResumeToStopSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)256 static void assertResumeToStopSequence(Class<? extends Activity> activityClass, 257 LifecycleLog lifecycleLog) { 258 final List<LifecycleLog.ActivityCallback> observedTransitions = 259 lifecycleLog.getActivityLog(activityClass); 260 log("Observed sequence: " + observedTransitions); 261 final String errorMessage = errorDuringTransition(activityClass, "resumed to stopped"); 262 final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass); 263 264 final List<LifecycleLog.ActivityCallback> expectedTransitions = new ArrayList<>(); 265 if (includeCallbacks) { 266 expectedTransitions.add(ON_TOP_POSITION_LOST); 267 } 268 expectedTransitions.add(ON_PAUSE); 269 expectedTransitions.add(ON_STOP); 270 271 assertEquals(errorMessage, expectedTransitions, observedTransitions); 272 } 273 assertStopToResumeSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)274 static void assertStopToResumeSequence(Class<? extends Activity> activityClass, 275 LifecycleLog lifecycleLog) { 276 final List<LifecycleLog.ActivityCallback> observedTransitions = 277 lifecycleLog.getActivityLog(activityClass); 278 log("Observed sequence: " + observedTransitions); 279 final String errorMessage = errorDuringTransition(activityClass, "stopped to resumed"); 280 final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass); 281 282 final List<LifecycleLog.ActivityCallback> expectedTransitions = new ArrayList<>( 283 Arrays.asList(ON_RESTART, ON_START, ON_RESUME)); 284 if (includeCallbacks) { 285 expectedTransitions.add(ON_TOP_POSITION_GAINED); 286 } 287 288 assertEquals(errorMessage, expectedTransitions, observedTransitions); 289 } 290 291 /** 292 * TODO(b/192274045): In Automotive, we tolerate superfluous lifecycle events between the first 293 * lifecycle events and the last one until any discrepancy between ActivityManager and Keyguard 294 * state is resolved. 295 */ assertStopToResumeSubSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog)296 static void assertStopToResumeSubSequence(Class<? extends Activity> activityClass, 297 LifecycleLog lifecycleLog) { 298 final List<LifecycleLog.ActivityCallback> observedTransitions = 299 lifecycleLog.getActivityLog(activityClass); 300 log("Observed sequence: " + observedTransitions); 301 final boolean includeCallbacks = CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass); 302 303 final List<Pair<String, ActivityCallback>> expectedTransitions = new ArrayList<>( 304 Arrays.asList(transition(activityClass, ON_RESTART), 305 transition(activityClass, ON_START), transition(activityClass, ON_RESUME))); 306 if (includeCallbacks) { 307 expectedTransitions.add(transition(activityClass, ON_TOP_POSITION_GAINED)); 308 } 309 310 assertOrder(lifecycleLog, expectedTransitions, "stop and resume"); 311 } 312 assertRelaunchSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, LifecycleLog.ActivityCallback startState)313 static void assertRelaunchSequence(Class<? extends Activity> activityClass, 314 LifecycleLog lifecycleLog, LifecycleLog.ActivityCallback startState) { 315 final List<LifecycleLog.ActivityCallback> expectedTransitions = getRelaunchSequence(startState); 316 assertSequence(activityClass, lifecycleLog, expectedTransitions, "relaunch"); 317 } 318 getRelaunchSequence( LifecycleLog.ActivityCallback startState)319 static List<LifecycleLog.ActivityCallback> getRelaunchSequence( 320 LifecycleLog.ActivityCallback startState) { 321 final List<LifecycleLog.ActivityCallback> expectedTransitions; 322 if (startState == ON_PAUSE) { 323 expectedTransitions = Arrays.asList( 324 ON_STOP, ON_DESTROY, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE); 325 } else if (startState == ON_STOP) { 326 expectedTransitions = Arrays.asList( 327 ON_DESTROY, ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP); 328 } else if (startState == ON_RESUME) { 329 expectedTransitions = Arrays.asList( 330 ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE, ON_START, ON_RESUME); 331 } else if (startState == ON_TOP_POSITION_GAINED) { 332 // Looks like we're tracking the callbacks here 333 expectedTransitions = Arrays.asList( 334 ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE, 335 ON_START, ON_POST_CREATE, ON_RESUME, ON_TOP_POSITION_GAINED); 336 } else { 337 throw new IllegalArgumentException("Start state not supported: " + startState); 338 } 339 return expectedTransitions; 340 } 341 getSplitScreenTransitionSequence( Class<? extends Activity> activityClass)342 static List<LifecycleLog.ActivityCallback> getSplitScreenTransitionSequence( 343 Class<? extends Activity> activityClass) { 344 // Minimized-dock is not a policy requirement and but SysUI-specific concept, so we here 345 // don't expect a trailing ON_PAUSE. 346 return CALLBACK_TRACKING_CLASS.isAssignableFrom(activityClass) 347 ? CONFIG_CHANGE_HANDLING_CLASS.isAssignableFrom(activityClass) 348 ? Arrays.asList(ON_MULTI_WINDOW_MODE_CHANGED, ON_TOP_POSITION_LOST) 349 : Arrays.asList(ON_TOP_POSITION_LOST, ON_PAUSE, ON_STOP, ON_DESTROY, 350 ON_CREATE, ON_START, ON_POST_CREATE, ON_RESUME, 351 ON_TOP_POSITION_GAINED, ON_TOP_POSITION_LOST) 352 : Arrays.asList(ON_PAUSE, ON_STOP, ON_DESTROY, ON_CREATE, ON_START, ON_RESUME); 353 } 354 355 // TODO(b/149338177): Remove this workaround once test passes with TestTaskOrganizer not to 356 // depend on minimized dock feature which is not policy requirement, but SysUI-specific. 357 /** 358 * Returns the result of appending "leave from minimized dock" transitions to given transitions 359 * to "consume" these activity callbacks. 360 */ appendMinimizedDockTransitionTrail( List<ActivityCallback> transitions)361 static List<ActivityCallback> appendMinimizedDockTransitionTrail( 362 List<ActivityCallback> transitions) { 363 final List<LifecycleLog.ActivityCallback> newTransitions = 364 new ArrayList<LifecycleLog.ActivityCallback>(transitions); 365 newTransitions.addAll(Arrays.asList(ON_PAUSE, ON_RESUME)); 366 367 return newTransitions; 368 } 369 assertSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, List<ActivityCallback> expectedTransitions, String transition)370 static void assertSequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, 371 List<ActivityCallback> expectedTransitions, String transition) { 372 final List<ActivityCallback> observedTransitions = 373 lifecycleLog.getActivityLog(activityClass); 374 log("Observed sequence: " + observedTransitions); 375 final String errorMessage = errorDuringTransition(activityClass, transition); 376 377 assertEquals(errorMessage, expectedTransitions, observedTransitions); 378 } 379 380 /** 381 * Assert that the observed transitions of a particular activity happened in expected order. 382 * There may be more observed transitions than in the expected array, only their order matters. 383 * 384 * Use this method when there is no need to verify the entire sequence, only that some 385 * transitions happened after another. 386 */ assertOrder(LifecycleLog lifecycleLog, Class<? extends Activity> activityClass, List<ActivityCallback> expectedTransitionsOrder, String transition)387 static void assertOrder(LifecycleLog lifecycleLog, Class<? extends Activity> activityClass, 388 List<ActivityCallback> expectedTransitionsOrder, String transition) { 389 List<Pair<String, ActivityCallback>> expectedTransitions = new ArrayList<>(); 390 for (ActivityCallback callback : expectedTransitionsOrder) { 391 expectedTransitions.add(transition(activityClass, callback)); 392 } 393 assertOrder(lifecycleLog, expectedTransitions, transition); 394 } 395 396 /** 397 * Assert that the observed transitions happened in expected order. There may be more observed 398 * transitions than in the expected array, only their order matters. 399 * 400 * Use this method when there is no need to verify the entire sequence, only that some 401 * transitions happened after another. 402 */ assertOrder(LifecycleLog lifecycleLog, List<Pair<String, ActivityCallback>> expectedTransitionsOrder, String transition)403 static void assertOrder(LifecycleLog lifecycleLog, 404 List<Pair<String, ActivityCallback>> expectedTransitionsOrder, 405 String transition) { 406 final List<Pair<String, ActivityCallback>> observedTransitions = lifecycleLog.getLog(); 407 int nextObservedPosition = 0; 408 for (Pair<String, ActivityCallback> expectedTransition 409 : expectedTransitionsOrder) { 410 while (nextObservedPosition < observedTransitions.size() 411 && !observedTransitions.get(nextObservedPosition).equals(expectedTransition)) 412 { 413 nextObservedPosition++; 414 } 415 if (nextObservedPosition == observedTransitions.size()) { 416 fail("Transition wasn't observed in the expected position: " + expectedTransition 417 + " during transition: " + transition); 418 } 419 } 420 } 421 422 /** 423 * Assert that a transition was observer, no particular order. 424 */ assertTransitionObserved(LifecycleLog lifecycleLog, Pair<String, ActivityCallback> expectedTransition, String transition)425 static void assertTransitionObserved(LifecycleLog lifecycleLog, 426 Pair<String, ActivityCallback> expectedTransition, String transition) { 427 assertTrue("Transition " + expectedTransition + " must be observed during " + transition, 428 lifecycleLog.getLog().contains(expectedTransition)); 429 } 430 431 /** 432 * Assert that a transition was not observer, no particular order. 433 */ assertTransitionNotObserved(LifecycleLog lifecycleLog, Pair<String, ActivityCallback> expectedTransition, String transition)434 static void assertTransitionNotObserved(LifecycleLog lifecycleLog, 435 Pair<String, ActivityCallback> expectedTransition, String transition) { 436 assertFalse("Transition " + expectedTransition + " must not be observed during " 437 + transition, lifecycleLog.getLog().contains(expectedTransition)); 438 } 439 assertEmptySequence(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, String transition)440 static void assertEmptySequence(Class<? extends Activity> activityClass, 441 LifecycleLog lifecycleLog, String transition) { 442 assertSequence(activityClass, lifecycleLog, new ArrayList<>(), transition); 443 } 444 445 /** Assert that a lifecycle sequence matches one of the possible variants. */ assertSequenceMatchesOneOf(Class<? extends Activity> activityClass, LifecycleLog lifecycleLog, List<List<ActivityCallback>> expectedTransitions, String transition)446 static void assertSequenceMatchesOneOf(Class<? extends Activity> activityClass, 447 LifecycleLog lifecycleLog, List<List<ActivityCallback>> expectedTransitions, 448 String transition) { 449 final List<ActivityCallback> observedTransitions = 450 lifecycleLog.getActivityLog(activityClass); 451 log("Observed sequence: " + observedTransitions); 452 final String errorMessage = errorDuringTransition(activityClass, transition); 453 454 boolean oneOfExpectedSequencesObserved = false; 455 for (List<ActivityCallback> transitionVariant : expectedTransitions) { 456 if (transitionVariant.equals(observedTransitions)) { 457 oneOfExpectedSequencesObserved = true; 458 break; 459 } 460 } 461 assertTrue(errorMessage + "\nObserved transitions: " + observedTransitions 462 + "\nExpected one of: " + expectedTransitions, 463 oneOfExpectedSequencesObserved); 464 } 465 466 /** Assert the entire sequence for all involved activities. */ assertEntireSequence( List<Pair<String, ActivityCallback>> expectedTransitions, LifecycleLog lifecycleLog, String message)467 static void assertEntireSequence( 468 List<Pair<String, ActivityCallback>> expectedTransitions, 469 LifecycleLog lifecycleLog, String message) { 470 final List<Pair<String, ActivityCallback>> observedTransitions = lifecycleLog.getLog(); 471 assertEquals(message, expectedTransitions, observedTransitions); 472 } 473 transition(Class<? extends Activity> activityClass, ActivityCallback state)474 static Pair<String, ActivityCallback> transition(Class<? extends Activity> activityClass, 475 ActivityCallback state) { 476 return new Pair<>(activityClass.getCanonicalName(), state); 477 } 478 errorDuringTransition(Class<? extends Activity> activityClass, String transition)479 private static String errorDuringTransition(Class<? extends Activity> activityClass, 480 String transition) { 481 return "Failed verification during moving activity: " + activityClass.getCanonicalName() 482 + " through transition: " + transition; 483 } 484 } 485