• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 com.android.apptransition.tests;
18 
19 import android.app.ActivityManager;
20 import android.app.IActivityManager;
21 import android.app.Instrumentation;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.os.Bundle;
27 import android.os.ParcelFileDescriptor;
28 import android.os.RemoteException;
29 import android.support.test.InstrumentationRegistry;
30 import android.support.test.launcherhelper.ILauncherStrategy;
31 import android.support.test.launcherhelper.LauncherStrategyFactory;
32 import android.support.test.rule.logging.AtraceLogger;
33 import android.support.test.uiautomator.By;
34 import android.support.test.uiautomator.UiDevice;
35 import android.support.test.uiautomator.UiObject2;
36 import android.support.test.uiautomator.Until;
37 import android.util.Log;
38 
39 import java.io.BufferedReader;
40 import java.io.File;
41 import java.io.FileInputStream;
42 import java.io.InputStream;
43 import java.io.InputStreamReader;
44 import java.io.IOException;
45 import java.util.HashSet;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.LinkedHashMap;
49 import java.util.Map;
50 import java.util.Set;
51 
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 
56 public class AppTransitionTests {
57 
58     private static final String TAG = AppTransitionTests.class.getSimpleName();
59     private static final int JOIN_TIMEOUT = 10000;
60     private static final int DEFAULT_DROP_CACHE_DELAY = 2000;
61     private static final String DEFAULT_POST_LAUNCH_TIMEOUT = "5000";
62     private static final String DEFAULT_LAUNCH_COUNT = "10";
63     private static final String SUCCESS_MESSAGE = "Status: ok";
64     private static final String HOT_LAUNCH_MESSAGE = "Warning: Activity not started, its current"
65             + " task has been brought to the front";
66     private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
67     private static final String APP_LAUNCH_CMD = "am start -W -n";
68     private static final String FORCE_STOP = "am force-stop ";
69     private static final String PRE_LAUNCH_APPS = "pre_launch_apps";
70     private static final String LAUNCH_APPS = "launch_apps";
71     private static final String KEY_LAUNCH_ITERATIONS = "launch_iteration";
72     private static final String KEY_POST_LAUNCH_TIMEOUT = "postlaunch_timeout";
73     private static final String COLD_LAUNCH = "cold_launch";
74     private static final String HOT_LAUNCH = "hot_launch";
75     private static final String NOT_SURE = "not_sure";
76     private static final String ACTIVITY = "Activity";
77     private static final String NOT_SUCCESSFUL_MESSAGE = "App launch not successful";
78     private static final String KEY_TRACE_DIRECTORY = "trace_directory";
79     private static final String KEY_TRACE_CATEGORY = "trace_categories";
80     private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
81     private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
82     private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview,"
83             + "input,wm,disk,am,wm";
84     private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
85     private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
86     private static final String DELIMITER = ",";
87     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
88     private Context mContext;
89     private UiDevice mDevice;
90     private PackageManager mPackageManager;
91     private IActivityManager mActivityManager;
92     private ILauncherStrategy mLauncherStrategy = null;
93     private Map<String, Intent> mAppLaunchIntentsMapping = null;
94     private String mTraceDirectoryStr = null;
95     private Bundle mResult = new Bundle();
96     private Bundle mArgs;
97     private String mPreAppsList;
98     private int mLaunchIterations;
99     private int mPostLaunchTimeout;
100     private String[] mAppListArray;
101     private String[] mPreAppsListArray;
102     private File mRootTrace = null;
103     private File mRootTraceSubDir = null;
104     private int mTraceBufferSize = 0;
105     private int mTraceDumpInterval = 0;
106     private Set<String> mTraceCategoriesSet = null;
107     private AtraceLogger mAtraceLogger = null;
108     private String mComponentName = null;
109     private Map<String,String> mPreAppsComponentName = new HashMap<String, String>();
110 
111     @Before
setUp()112     public void setUp() throws Exception {
113         mPackageManager = getInstrumentation().getContext().getPackageManager();
114         mContext = getInstrumentation().getContext();
115         mArgs = InstrumentationRegistry.getArguments();
116         mActivityManager = ActivityManager.getService();
117         mDevice = UiDevice.getInstance(getInstrumentation());
118         mLauncherStrategy = LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy();
119         createLaunchIntentMappings();
120         String mAppsList = mArgs.getString(LAUNCH_APPS);
121         mPreAppsList = mArgs.getString(PRE_LAUNCH_APPS);
122         mLaunchIterations = Integer.parseInt(mArgs.getString(KEY_LAUNCH_ITERATIONS,
123                 DEFAULT_LAUNCH_COUNT));
124         mPostLaunchTimeout = Integer.parseInt(mArgs.getString(KEY_POST_LAUNCH_TIMEOUT,
125                 DEFAULT_POST_LAUNCH_TIMEOUT));
126         if (null == mAppsList && mAppsList.isEmpty()) {
127             throw new IllegalArgumentException("Need atleast one app to do the"
128                     + " app transition from launcher");
129         }
130         mAppsList = mAppsList.replaceAll("%"," ");
131         mAppListArray = mAppsList.split(DELIMITER);
132 
133         // Parse the trace parameters
134         mTraceDirectoryStr = mArgs.getString(KEY_TRACE_DIRECTORY);
135         if (isTracesEnabled()) {
136             String traceCategoriesStr = mArgs
137                     .getString(KEY_TRACE_CATEGORY, DEFAULT_TRACE_CATEGORIES);
138             mTraceBufferSize = Integer.parseInt(mArgs.getString(KEY_TRACE_BUFFERSIZE,
139                     DEFAULT_TRACE_BUFFER_SIZE));
140             mTraceDumpInterval = Integer.parseInt(mArgs.getString(KEY_TRACE_DUMPINTERVAL,
141                     DEFAULT_TRACE_DUMP_INTERVAL));
142             mTraceCategoriesSet = new HashSet<String>();
143             if (!traceCategoriesStr.isEmpty()) {
144                 String[] traceCategoriesSplit = traceCategoriesStr.split(DELIMITER);
145                 for (int i = 0; i < traceCategoriesSplit.length; i++) {
146                     mTraceCategoriesSet.add(traceCategoriesSplit[i]);
147                 }
148             }
149         }
150         mDevice.setOrientationNatural();
151         sleep(mPostLaunchTimeout);
152         cleanTestApps();
153     }
154 
155     @After
tearDown()156     public void tearDown() throws Exception{
157         cleanTestApps();
158         getInstrumentation().sendStatus(0, mResult);
159     }
160 
161     /**
162      * Cold launch given list of apps for given launch count from the launcher screen.
163      * @throws IOException if there are issues in writing atrace file
164      * @throws InterruptedException if there are interrupt during the sleep
165      * @throws RemoteException if press home is not successful
166      */
167     @Test
testColdLaunchFromLauncher()168     public void testColdLaunchFromLauncher() throws IOException, InterruptedException,
169             RemoteException {
170         if (isTracesEnabled()) {
171             createTraceDirectory("testColdLaunchFromLauncher");
172         }
173         // Perform cold app launch from launcher screen
174         for (int appCount = 0; appCount < mAppListArray.length; appCount++) {
175             String appName = mAppListArray[appCount];
176             // Additional launch to account for cold launch
177             if (setupAppLaunch(appName) == ILauncherStrategy.LAUNCH_FAILED_TIMESTAMP) {
178                 continue;
179             }
180             closeApps(new String[] {
181                     appName
182             });
183             getInstrumentation().getUiAutomation()
184                     .executeShellCommand(DROP_CACHE_SCRIPT);
185             sleep(DEFAULT_DROP_CACHE_DELAY);
186             for (int launchCount = 0; launchCount <= mLaunchIterations; launchCount++) {
187                 if (null != mAtraceLogger) {
188                     mAtraceLogger.atraceStart(mTraceCategoriesSet, mTraceBufferSize,
189                             mTraceDumpInterval, mRootTraceSubDir,
190                             String.format("%s-%d", appName, launchCount));
191                 }
192                 mLauncherStrategy.launch(appName, mComponentName.split("\\/")[0]);
193                 if (null != mAtraceLogger) {
194                     mAtraceLogger.atraceStop();
195                 }
196                 sleep(mPostLaunchTimeout);
197                 mDevice.pressHome();
198 		mDevice.waitForIdle();
199                 closeApps(new String[] {
200                         appName
201                 });
202                 sleep(mPostLaunchTimeout);
203                 getInstrumentation().getUiAutomation()
204                         .executeShellCommand(DROP_CACHE_SCRIPT);
205                 sleep(DEFAULT_DROP_CACHE_DELAY);
206             }
207             mComponentName = null;
208             // Update the result with the component name
209             updateResult(appName);
210         }
211     }
212 
213     /**
214      * Hot launch given list of apps for given launch count from the launcher screen. Same method can be
215      * used to test app to home transition delay information as well.
216      * @throws IOException if there are issues in writing atrace file
217      * @throws InterruptedException if there are interrupt during the sleep
218      * @throws RemoteException if press home is not successful
219      */
220     @Test
testHotLaunchFromLauncher()221     public void testHotLaunchFromLauncher() throws IOException, InterruptedException,
222             RemoteException {
223         if (isTracesEnabled()) {
224             createTraceDirectory("testHotLaunchFromLauncher");
225         }
226         for (int appCount = 0; appCount < mAppListArray.length; appCount++) {
227             String appName = mAppListArray[appCount];
228             // Additional launch to account for cold launch
229             if (setupAppLaunch(appName) == ILauncherStrategy.LAUNCH_FAILED_TIMESTAMP) {
230                 continue;
231             }
232             // Hot app launch for given (launch iterations + 1) times.
233             for (int launchCount = 0; launchCount <= (mLaunchIterations); launchCount++) {
234                 if (null != mAtraceLogger) {
235                     mAtraceLogger.atraceStart(mTraceCategoriesSet, mTraceBufferSize,
236                             mTraceDumpInterval, mRootTraceSubDir,
237                             String.format("%s-%d", appName, (launchCount)));
238                 }
239                 mLauncherStrategy.launch(appName, mComponentName.split("\\/")[0]);
240                 if (null != mAtraceLogger) {
241                     mAtraceLogger.atraceStop();
242                 }
243                 sleep(mPostLaunchTimeout);
244                 mDevice.pressHome();
245                 sleep(mPostLaunchTimeout);
246             }
247             mComponentName = null;
248             // Update the result with the component name
249             updateResult(appName);
250         }
251     }
252 
253     /**
254      * Launch an app and press recents for given list of apps for given launch counts.
255      * @throws IOException if there are issues in writing atrace file
256      * @throws InterruptedException if there are interrupt during the sleep
257      * @throws RemoteException if press recent apps is not successful
258      */
259     @Test
testAppToRecents()260     public void testAppToRecents() throws IOException, InterruptedException, RemoteException {
261         if (isTracesEnabled()) {
262             createTraceDirectory("testAppToRecents");
263         }
264         if (null == mPreAppsList && mPreAppsList.isEmpty()) {
265             throw new IllegalArgumentException("Need atleast few apps in the "
266                     + "recents before starting the test");
267         }
268         mPreAppsList = mPreAppsList.replaceAll("%"," ");
269         mPreAppsListArray = mPreAppsList.split(DELIMITER);
270         mPreAppsComponentName.clear();
271         populateRecentsList();
272         for (int appCount = 0; appCount < mAppListArray.length; appCount++) {
273             String appName = mAppListArray[appCount];
274             long appLaunchTime = -1L;
275             for (int launchCount = 0; launchCount <= mLaunchIterations; launchCount++) {
276                 mLauncherStrategy.launch(appName, mPreAppsComponentName.get(appName).split(
277                         "\\/")[0]);
278                 sleep(mPostLaunchTimeout);
279                 if (null != mAtraceLogger && launchCount > 0) {
280                     mAtraceLogger.atraceStart(mTraceCategoriesSet, mTraceBufferSize,
281                             mTraceDumpInterval, mRootTraceSubDir,
282                             String.format("%s-%d", appName, launchCount - 1));
283                 }
284                 pressUiRecentApps();
285                 sleep(mPostLaunchTimeout);
286                 if (null != mAtraceLogger && launchCount > 0) {
287                     mAtraceLogger.atraceStop();
288                 }
289                 mDevice.pressHome();
290                 sleep(mPostLaunchTimeout);
291             }
292             updateResult(appName);
293         }
294     }
295 
296     /**
297      * Hot launch an app from recents for given list of apps for given launch counts.
298      * @throws IOException if there are issues in writing atrace file
299      * @throws InterruptedException if there are interrupt during the sleep
300      * @throws RemoteException if press recent apps is not successful
301      */
302     @Test
testHotLaunchFromRecents()303     public void testHotLaunchFromRecents() throws IOException, InterruptedException,
304             RemoteException {
305         if (isTracesEnabled()) {
306             createTraceDirectory("testHotLaunchFromRecents");
307         }
308         if (null == mPreAppsList && mPreAppsList.isEmpty()) {
309             throw new IllegalArgumentException("Need atleast few apps in the"
310                     + " recents before starting the test");
311         }
312         mPreAppsList = mPreAppsList.replaceAll("%", " ");
313         mPreAppsListArray = mPreAppsList.split(DELIMITER);
314         mPreAppsComponentName.clear();
315         populateRecentsList();
316         for (int appCount = 0; appCount < mAppListArray.length; appCount++) {
317             String appName = mAppListArray[appCount];
318             // To bring the app to launch as first item from recents task.
319             mLauncherStrategy.launch(appName, mPreAppsComponentName.get(appName).split(
320                     "\\/")[0]);
321             sleep(mPostLaunchTimeout);
322             for (int launchCount = 0; launchCount <= mLaunchIterations; launchCount++) {
323                 if (null != mAtraceLogger) {
324                     mAtraceLogger.atraceStart(mTraceCategoriesSet, mTraceBufferSize,
325                             mTraceDumpInterval, mRootTraceSubDir,
326                             String.format("%s-%d", appName, (launchCount)));
327                 }
328                 openMostRecentTask();
329                 sleep(mPostLaunchTimeout);
330                 if (null != mAtraceLogger) {
331                     mAtraceLogger.atraceStop();
332                 }
333                 mDevice.pressHome();
334                 sleep(mPostLaunchTimeout);
335             }
336             updateResult(appName);
337         }
338     }
339 
340     /**
341      * Launch given app to account for the cold launch and track
342      * component name associated with the app.
343      * @throws RemoteException if press home is not successful
344      * @param appName
345      * @return
346      */
setupAppLaunch(String appName)347     public long setupAppLaunch(String appName) throws RemoteException {
348         long appLaunchTime = startApp(appName, NOT_SURE);
349         if (appLaunchTime == ILauncherStrategy.LAUNCH_FAILED_TIMESTAMP) {
350             return appLaunchTime;
351         }
352         sleep(mPostLaunchTimeout);
353         mDevice.pressHome();
354         sleep(mPostLaunchTimeout);
355         return appLaunchTime;
356     }
357 
358     /**
359      * Press on the recents icon
360      * @throws RemoteException if press recents is not successful
361      */
pressUiRecentApps()362     private void pressUiRecentApps() throws RemoteException {
363         mDevice.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")).click();
364     }
365 
366     /**
367      * To open the home screen.
368      * @throws RemoteException if press home is not successful
369      */
pressUiHome()370     private void pressUiHome() throws RemoteException {
371         mDevice.findObject(By.res(SYSTEMUI_PACKAGE, "home")).click();
372     }
373 
374     /**
375      * Open recents task and click on the most recent task.
376      * @throws RemoteException if press recents is not successful
377      */
openMostRecentTask()378     public void openMostRecentTask() throws RemoteException {
379         pressUiRecentApps();
380         UiObject2 recentsView = mDevice.wait(Until.findObject(
381                 By.res(SYSTEMUI_PACKAGE, "recents_view")), 5000);
382         List<UiObject2> recentsTasks = recentsView.getChildren().get(0)
383                 .getChildren();
384         UiObject2 mostRecentTask = recentsTasks.get(recentsTasks.size() - 1);
385         mostRecentTask.click();
386     }
387 
388     /**
389      * Create sub directory under the trace root directory to store the trace files captured during
390      * the app transition.
391      * @param subDirectoryName
392      */
createTraceDirectory(String subDirectoryName)393     private void createTraceDirectory(String subDirectoryName) throws IOException {
394         mRootTrace = new File(mTraceDirectoryStr);
395         if (!mRootTrace.exists() && !mRootTrace.mkdirs()) {
396             throw new IOException("Unable to create the trace directory");
397         }
398         mRootTraceSubDir = new File(mRootTrace, subDirectoryName);
399         if (!mRootTraceSubDir.exists() && !mRootTraceSubDir.mkdirs()) {
400             throw new IOException("Unable to create the trace sub directory");
401         }
402         mAtraceLogger = AtraceLogger.getAtraceLoggerInstance(getInstrumentation());
403     }
404 
405     /**
406      * Force stop the given list of apps, clear the cache and return to home screen.
407      * @throws RemoteException if press home is not successful
408      */
cleanTestApps()409     private void cleanTestApps() throws RemoteException {
410         if (null != mPreAppsListArray && mPreAppsListArray.length > 0) {
411             closeApps(mPreAppsListArray);
412         }
413         closeApps(mAppListArray);
414         getInstrumentation().getUiAutomation()
415                         .executeShellCommand(DROP_CACHE_SCRIPT);
416         sleep(DEFAULT_DROP_CACHE_DELAY);
417         mDevice.pressHome();
418         sleep(mPostLaunchTimeout);
419     }
420 
421     /**
422      * Populate the recents list with given list of apps.
423      * @throws RemoteException if press home is not successful
424      */
populateRecentsList()425     private void populateRecentsList() throws RemoteException {
426         for (int preAppCount = 0; preAppCount < mPreAppsListArray.length; preAppCount++) {
427             startApp(mPreAppsListArray[preAppCount], NOT_SURE);
428             mPreAppsComponentName.put(mPreAppsListArray[preAppCount], mComponentName);
429             sleep(mPostLaunchTimeout);
430             mDevice.pressHome();
431             sleep(mPostLaunchTimeout);
432         }
433         mComponentName = null;
434     }
435 
436 
437     /**
438      * To obtain the app name and corresponding intent to launch the app.
439      */
createLaunchIntentMappings()440     private void createLaunchIntentMappings() {
441         mAppLaunchIntentsMapping = new LinkedHashMap<String, Intent>();
442         PackageManager pm = getInstrumentation().getContext()
443                 .getPackageManager();
444         Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
445         intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
446         List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
447         resolveLoop(ris, intentToResolve, pm);
448     }
449 
resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm)450     private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
451         if (ris == null || ris.isEmpty()) {
452             Log.i(TAG, "Could not find any apps");
453         } else {
454             for (ResolveInfo ri : ris) {
455                 Intent startIntent = new Intent(intentToResolve);
456                 startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
457                         | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
458                 startIntent.setClassName(ri.activityInfo.packageName,
459                         ri.activityInfo.name);
460                 String appName = ri.loadLabel(pm).toString();
461                 if (appName != null) {
462                     mAppLaunchIntentsMapping.put(appName, startIntent);
463                 }
464             }
465         }
466     }
467 
468     /**
469      * Launch an app using the app name and return the app launch time. If app launch time is -1
470      * then app launch is not successful.
471      * @param appName Name of an app as listed in the launcher
472      * @param launchMode Cold or Hot launch
473      * @return
474      */
startApp(String appName, String launchMode)475     private long startApp(String appName, String launchMode) {
476         Log.i(TAG, "Starting " + appName);
477         Intent startIntent = mAppLaunchIntentsMapping.get(appName);
478         if (startIntent == null) {
479             return -1L;
480         }
481         AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, launchMode);
482         Thread t = new Thread(runnable);
483         t.start();
484         try {
485             t.join(JOIN_TIMEOUT);
486         } catch (InterruptedException e) {
487             // ignore
488         }
489         mComponentName = runnable.getCmpName();
490         return runnable.getResult();
491     }
492 
493     private class AppLaunchRunnable implements Runnable {
494         private Intent mLaunchIntent;
495         private String mLaunchMode;
496         private Long mResult = -1L;
497         private String mCmpName;
498 
AppLaunchRunnable(Intent intent, String launchMode)499         public AppLaunchRunnable(Intent intent, String launchMode) {
500             mLaunchIntent = intent;
501             mLaunchMode = launchMode;
502         }
503 
getResult()504         public Long getResult() {
505             return mResult;
506         }
507 
getCmpName()508         public String getCmpName() {
509             return mCmpName;
510         }
511 
512         @Override
run()513         public void run() {
514             String packageName = mLaunchIntent.getComponent().getPackageName();
515             String componentName = mLaunchIntent.getComponent().flattenToString();
516             String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
517             ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
518                     .executeShellCommand(launchCmd);
519             mResult = Long.parseLong(parseLaunchTime(parcelDesc));
520         }
521 
522         /**
523          * Returns launch time if app launch is successful otherwise "-1"
524          * @param parcelDesc
525          * @return
526          */
parseLaunchTime(ParcelFileDescriptor parcelDesc)527         private String parseLaunchTime(ParcelFileDescriptor parcelDesc) {
528             String launchTime = "-1";
529             boolean launchSuccess = false;
530             mCmpName = null;
531             try {
532                 InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
533                 StringBuilder appLaunchOuput = new StringBuilder();
534                 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
535                         inputStream));
536                 String line = null;
537                 int lineCount = 1;
538                 while ((line = bufferedReader.readLine()) != null) {
539                     if (lineCount == 2) {
540                         if ((mLaunchMode.contains(COLD_LAUNCH) || mLaunchMode.contains(NOT_SURE))
541                                 && line.contains(SUCCESS_MESSAGE)) {
542                             launchSuccess = true;
543                         } else if ((mLaunchMode.contains(HOT_LAUNCH) || mLaunchMode
544                                 .contains(NOT_SURE)) && line.contains(HOT_LAUNCH_MESSAGE)) {
545                             launchSuccess = true;
546                         }
547                     }
548                     if ((launchSuccess && (mLaunchMode.contains(COLD_LAUNCH)
549                             || mLaunchMode.contains(NOT_SURE)) && lineCount == 4) ||
550                             (launchSuccess && (mLaunchMode.contains(HOT_LAUNCH) ||
551                                     mLaunchMode.contains(NOT_SURE)) && lineCount == 5)) {
552                         String launchSplit[] = line.split(":");
553                         launchTime = launchSplit[1].trim();
554                     }
555                     // Needed to update the component name if the very first launch activity
556                     // is different from hot launch activity (i.e YouTube)
557                     if ((launchSuccess && (mLaunchMode.contains(HOT_LAUNCH) ||
558                             mLaunchMode.contains(NOT_SURE)) && lineCount == 3)) {
559                         String activitySplit[] = line.split(":");
560                         if (activitySplit[0].contains(ACTIVITY)) {
561                             mCmpName = activitySplit[1].trim();
562                         }
563                     }
564                     lineCount++;
565                 }
566                 inputStream.close();
567             } catch (IOException e) {
568                 Log.w(TAG, "Error writing the launch file", e);
569             }
570             return launchTime;
571         }
572     }
573 
574     /**
575      * To force stop the given list of apps based on the app name.
576      * @param appNames
577      */
closeApps(String[] appNames)578     private void closeApps(String[] appNames) {
579         for (int i = 0; i < appNames.length; i++) {
580             Intent startIntent = mAppLaunchIntentsMapping.get(appNames[i]);
581             if (startIntent != null) {
582                 String packageName = startIntent.getComponent().getPackageName();
583 
584                 getInstrumentation().getUiAutomation().executeShellCommand(
585                         FORCE_STOP + packageName);
586             }
587             sleep(1000);
588         }
589         sleep(mPostLaunchTimeout);
590     }
591 
592     /**
593      * @return
594      */
isTracesEnabled()595     private boolean isTracesEnabled(){
596         return (null != mTraceDirectoryStr && !mTraceDirectoryStr.isEmpty());
597     }
598 
599     /**
600      * Update the result status
601      * @param appName
602      */
updateResult(String appName)603     private void updateResult(String appName) {
604             // Component name needed for parsing the events log
605             if (null != mComponentName) {
606                 mResult.putString(appName, mComponentName);
607             } else {
608                 // Component name needed for parsing the events log
609                 mResult.putString(appName, mAppLaunchIntentsMapping.get(appName).
610                         getComponent().flattenToString());
611             }
612     }
613 
614 
615     /**
616      * To sleep for given millisecs.
617      * @param time
618      */
sleep(int time)619     private void sleep(int time) {
620         try {
621             Thread.sleep(time);
622         } catch (InterruptedException e) {
623             // ignore
624         }
625     }
626 
627     /**
628      * Return the instrumentation from the registry.
629      * @return
630      */
getInstrumentation()631     private Instrumentation getInstrumentation() {
632         return InstrumentationRegistry.getInstrumentation();
633     }
634 }
635