AppLaunch.java revision 6fc955071afc4125a6a52bf7ab01129416ae0dbf
1f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine/*
232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu * Copyright (C) 2013 The Android Open Source Project
3f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
4f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Licensed under the Apache License, Version 2.0 (the "License");
5f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * you may not use this file except in compliance with the License.
6f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * You may obtain a copy of the License at
7f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
8f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *      http://www.apache.org/licenses/LICENSE-2.0
9f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
10f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Unless required by applicable law or agreed to in writing, software
11f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * distributed under the License is distributed on an "AS IS" BASIS,
12f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * See the License for the specific language governing permissions and
14f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * limitations under the License.
15f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine */
16f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavinepackage com.android.tests.applaunch;
17f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
186266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport android.accounts.Account;
196266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport android.accounts.AccountManager;
20f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.ActivityManager;
21f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.ActivityManager.ProcessErrorStateInfo;
22f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.ActivityManagerNative;
23f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.IActivityManager;
2413f77349778fbe95d665542be6f05006879854e2Guang Zhuimport android.app.IActivityManager.WaitResult;
25e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhuimport android.app.UiAutomation;
26f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.Context;
27f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.Intent;
28f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.PackageManager;
29f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.PackageManager.NameNotFoundException;
30f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.ResolveInfo;
31f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.Bundle;
32f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.RemoteException;
33f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.UserHandle;
34f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.test.InstrumentationTestCase;
35f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.test.InstrumentationTestRunner;
36f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.util.Log;
37f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
3832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhuimport java.util.HashMap;
396266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport java.util.HashSet;
40c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhuimport java.util.LinkedHashMap;
41f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport java.util.List;
42f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport java.util.Map;
436266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport java.util.Set;
44f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
45f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine/**
46f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * This test is intended to measure the time it takes for the apps to start.
47f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Names of the applications are passed in command line, and the
48f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * test starts each application, and reports the start up time in milliseconds.
49f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * The instrumentation expects the following key to be passed on the command line:
50f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * apps - A list of applications to start and their corresponding result keys
51f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * in the following format:
52f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * -e apps <app name>^<result key>|<app name>^<result key>
53f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine */
54f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavinepublic class AppLaunch extends InstrumentationTestCase {
55f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
56f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private static final int JOIN_TIMEOUT = 10000;
5732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final String TAG = AppLaunch.class.getSimpleName();
58f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private static final String KEY_APPS = "apps";
5932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
606266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    // optional parameter: comma separated list of required account types before proceeding
616266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    // with the app launch
626266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
63349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    private static final String WEARABLE_ACTION_GOOGLE =
64349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz            "com.google.android.wearable.action.GOOGLE";
6532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
6632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
6732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
68f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
69f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, Intent> mNameToIntent;
70f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, String> mNameToProcess;
71f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, String> mNameToResultKey;
7232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private Map<String, Long> mNameToLaunchTime;
73f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private IActivityManager mAm;
7432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private int mLaunchIterations = 10;
7532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private Bundle mResult = new Bundle();
766266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private Set<String> mRequiredAccounts;
77f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
78e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
79e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void setUp() throws Exception {
80e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.setUp();
81e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
82e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
83e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
84e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
85e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void tearDown() throws Exception {
86e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
87e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.tearDown();
88e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
89e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
9032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException {
91f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        InstrumentationTestRunner instrumentation =
92f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                (InstrumentationTestRunner)getInstrumentation();
933a34d17412a5a304e39be1966a16627677d2136fSvetoslav        Bundle args = instrumentation.getArguments();
94f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        mAm = ActivityManagerNative.getDefault();
95f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
96f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        createMappings();
97f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        parseArgs(args);
986266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        checkAccountSignIn();
99f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
10032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        // do initial app launch, without force stopping
101f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        for (String app : mNameToResultKey.keySet()) {
10232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            long launchTime = startApp(app, false);
1032861a89bed9066e206917c41357a5e589e8482cbGuang Zhu            if (launchTime <= 0) {
10432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                mNameToLaunchTime.put(app, -1L);
10532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                // simply pass the app if launch isn't successful
10632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                // error should have already been logged by startApp
10732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                continue;
1082861a89bed9066e206917c41357a5e589e8482cbGuang Zhu            } else {
1092861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                mNameToLaunchTime.put(app, launchTime);
11032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            }
11132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
11232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            closeApp(app, false);
11332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
11432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
11532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        // do the real app launch now
11632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        for (int i = 0; i < mLaunchIterations; i++) {
11732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            for (String app : mNameToResultKey.keySet()) {
1182861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                long prevLaunchTime = mNameToLaunchTime.get(app);
11932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                long launchTime = 0;
1202861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                if (prevLaunchTime < 0) {
12132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    // skip if the app has previous failures
12232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    continue;
12332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
12432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                launchTime = startApp(app, true);
12532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                if (launchTime <= 0) {
12632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    // if it fails once, skip the rest of the launches
12732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mNameToLaunchTime.put(app, -1L);
12832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    continue;
12932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
1302861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                // keep the min launch time
1312861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                if (launchTime < prevLaunchTime) {
1322861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                    mNameToLaunchTime.put(app, launchTime);
1332861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                }
13432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                sleep(POST_LAUNCH_IDLE_TIMEOUT);
13532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                closeApp(app, true);
13632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
13732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            }
13832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
13932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        for (String app : mNameToResultKey.keySet()) {
1402861a89bed9066e206917c41357a5e589e8482cbGuang Zhu            long launchTime = mNameToLaunchTime.get(app);
1412861a89bed9066e206917c41357a5e589e8482cbGuang Zhu            if (launchTime != -1) {
1422861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                mResult.putLong(mNameToResultKey.get(app), launchTime);
143f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
144f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
14532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        instrumentation.sendStatus(0, mResult);
146f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
147f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
148f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void parseArgs(Bundle args) {
149c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToResultKey = new LinkedHashMap<String, String>();
15032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        mNameToLaunchTime = new HashMap<String, Long>();
15132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
15232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        if (launchIterations != null) {
15332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mLaunchIterations = Integer.parseInt(launchIterations);
15432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
155f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        String appList = args.getString(KEY_APPS);
156f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (appList == null)
157f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            return;
158f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
159f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        String appNames[] = appList.split("\\|");
160f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        for (String pair : appNames) {
161f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            String[] parts = pair.split("\\^");
162f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            if (parts.length != 2) {
1636fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Log.e(TAG, "The apps key is incorrectly formatted");
164f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                fail();
165f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
166f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
167f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            mNameToResultKey.put(parts[0], parts[1]);
16832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mNameToLaunchTime.put(parts[0], 0L);
169f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
1706266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
1716266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (requiredAccounts != null) {
1726266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            mRequiredAccounts = new HashSet<String>();
1736266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            for (String accountType : requiredAccounts.split(",")) {
1746266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                mRequiredAccounts.add(accountType);
1756266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
1766266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
177f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
178f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
1796fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim    private boolean hasLeanback(Context context) {
1806fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
1816fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim    }
1826fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim
183f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void createMappings() {
184c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToIntent = new LinkedHashMap<String, Intent>();
185c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToProcess = new LinkedHashMap<String, String>();
186f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
187f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        PackageManager pm = getInstrumentation().getContext()
188f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                .getPackageManager();
189f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1906fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
1916fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Intent.CATEGORY_LEANBACK_LAUNCHER :
1926fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Intent.CATEGORY_LAUNCHER);
193f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
194349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        resolveLoop(ris, intentToResolve, pm);
1956fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        // For Wear
196349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
197349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        ris = pm.queryIntentActivities(intentToResolve, 0);
198349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        resolveLoop(ris, intentToResolve, pm);
199349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    }
200349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz
201349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
202f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (ris == null || ris.isEmpty()) {
203f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            Log.i(TAG, "Could not find any apps");
204f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } else {
205f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            for (ResolveInfo ri : ris) {
206f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Intent startIntent = new Intent(intentToResolve);
207f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
208f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
209f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                startIntent.setClassName(ri.activityInfo.packageName,
210f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        ri.activityInfo.name);
21132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                String appName = ri.loadLabel(pm).toString();
21232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                if (appName != null) {
21332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mNameToIntent.put(appName, startIntent);
21432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mNameToProcess.put(appName, ri.activityInfo.processName);
21532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
216f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
217f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
218f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
219f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
22032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private long startApp(String appName, boolean forceStopBeforeLaunch)
221f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            throws NameNotFoundException, RemoteException {
222f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Log.i(TAG, "Starting " + appName);
223f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
224f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent startIntent = mNameToIntent.get(appName);
225c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        if (startIntent == null) {
226c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu            Log.w(TAG, "App does not exist: " + appName);
22732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mResult.putString(mNameToResultKey.get(appName), "App does not exist");
22832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            return -1;
229c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        }
23032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch);
231f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Thread t = new Thread(runnable);
232f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        t.start();
233f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        try {
234f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            t.join(JOIN_TIMEOUT);
235f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } catch (InterruptedException e) {
236f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            // ignore
237f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
238c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        WaitResult result = runnable.getResult();
23932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        // report error if any of the following is true:
24032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        // * launch thread is alive
24132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        // * result is not null, but:
2426fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        //   * result is not START_SUCCESS
24332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        //   * or in case of no force stop, result is not TASK_TO_FRONT either
24432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        if (t.isAlive() || (result != null
24532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                && ((result.result != ActivityManager.START_SUCCESS)
24632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                        && (!forceStopBeforeLaunch
24732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                                && result.result != ActivityManager.START_TASK_TO_FRONT)))) {
248f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            Log.w(TAG, "Assuming app " + appName + " crashed.");
24932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            reportError(appName, mNameToProcess.get(appName));
25032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            return -1;
251f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
25232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        return result.thisTime;
253f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
254f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
2556266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private void checkAccountSignIn() {
2566266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // ensure that the device has the required account types before starting test
2576266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // e.g. device must have a valid Google account sign in to measure a meaningful launch time
2586266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // for Gmail
2596266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
2606266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            return;
2616266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
2626266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        final AccountManager am =
2636266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                (AccountManager) getInstrumentation().getTargetContext().getSystemService(
2646266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                        Context.ACCOUNT_SERVICE);
2656266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        Account[] accounts = am.getAccounts();
2666266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // use set here in case device has multiple accounts of the same type
2676266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        Set<String> foundAccounts = new HashSet<String>();
2686266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        for (Account account : accounts) {
2696266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            if (mRequiredAccounts.contains(account.type)) {
2706266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                foundAccounts.add(account.type);
2716266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
2726266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
2736266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // check if account type matches, if not, fail test with message on what account types
2746266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // are missing
2756266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (mRequiredAccounts.size() != foundAccounts.size()) {
2766266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            mRequiredAccounts.removeAll(foundAccounts);
2776266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            StringBuilder sb = new StringBuilder("Device missing these accounts:");
2786266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            for (String account : mRequiredAccounts) {
2796266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                sb.append(' ');
2806266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                sb.append(account);
2816266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
2826266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            fail(sb.toString());
2836266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
2846266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    }
2856266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu
28632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private void closeApp(String appName, boolean forceStopApp) {
287f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
288f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        homeIntent.addCategory(Intent.CATEGORY_HOME);
289f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
290f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
291f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        getInstrumentation().getContext().startActivity(homeIntent);
29232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        sleep(POST_LAUNCH_IDLE_TIMEOUT);
29332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        if (forceStopApp) {
29432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            Intent startIntent = mNameToIntent.get(appName);
29532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            if (startIntent != null) {
29632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                String packageName = startIntent.getComponent().getPackageName();
29732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                try {
29832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
29932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                } catch (RemoteException e) {
30032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    Log.w(TAG, "Error closing app", e);
30132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
30213f77349778fbe95d665542be6f05006879854e2Guang Zhu            }
30313f77349778fbe95d665542be6f05006879854e2Guang Zhu        }
304f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
305f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
306f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void sleep(int time) {
307f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        try {
308f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            Thread.sleep(time);
309f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } catch (InterruptedException e) {
310f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            // ignore
311f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
312f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
313f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
31432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private void reportError(String appName, String processName) {
315f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        ActivityManager am = (ActivityManager) getInstrumentation()
316f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
317f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
318f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (crashes != null) {
319f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            for (ProcessErrorStateInfo crash : crashes) {
320f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                if (!crash.processName.equals(processName))
321f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                    continue;
322f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
323f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
32432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
325f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                return;
326f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
327f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
328f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
32932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        mResult.putString(mNameToResultKey.get(appName),
330f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                "Crashed for unknown reason");
331f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Log.w(TAG, appName
332f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                + " not found in process list, most likely it is crashed");
333f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
334f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
335f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private class AppLaunchRunnable implements Runnable {
336f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        private Intent mLaunchIntent;
337f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        private IActivityManager.WaitResult mResult;
33832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        private boolean mForceStopBeforeLaunch;
33932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu
34032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch) {
341f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            mLaunchIntent = intent;
34232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mForceStopBeforeLaunch = forceStopBeforeLaunch;
343f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
344f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
345f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        public IActivityManager.WaitResult getResult() {
346f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            return mResult;
347f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
348f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
349f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        public void run() {
350f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            try {
351c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu                String packageName = mLaunchIntent.getComponent().getPackageName();
35232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                if (mForceStopBeforeLaunch) {
35332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
35432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
355f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                String mimeType = mLaunchIntent.getType();
356f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                if (mimeType == null && mLaunchIntent.getData() != null
357f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        && "content".equals(mLaunchIntent.getData().getScheme())) {
358f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                    mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(),
359f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                            UserHandle.USER_CURRENT);
360f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                }
361f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
362f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn                mResult = mAm.startActivityAndWait(null, null, mLaunchIntent, mimeType,
3631b012d302b56b4adf950035136d1d191a1936d5aJeff Hao                        null, null, 0, mLaunchIntent.getFlags(), null, null,
364f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        UserHandle.USER_CURRENT);
365f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            } catch (RemoteException e) {
366f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Log.w(TAG, "Error launching app", e);
367f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
368f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
369f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
370f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine}
371