/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.tests.applaunch;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IActivityManager.WaitResult;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.test.InstrumentationTestCase;
import android.test.InstrumentationTestRunner;
import android.util.Log;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This test is intended to measure the time it takes for the apps to start.
 * Names of the applications are passed in command line, and the
 * test starts each application, and reports the start up time in milliseconds.
 * The instrumentation expects the following key to be passed on the command line:
 * apps - A list of applications to start and their corresponding result keys
 * in the following format:
 * -e apps <app name>^<result key>|<app name>^<result key>
 */
public class AppLaunch extends InstrumentationTestCase {

    private static final int JOIN_TIMEOUT = 10000;
    private static final String TAG = AppLaunch.class.getSimpleName();
    private static final String KEY_APPS = "apps";
    private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
    // optional parameter: comma separated list of required account types before proceeding
    // with the app launch
    private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
    private static final String WEARABLE_ACTION_GOOGLE =
            "com.google.android.wearable.action.GOOGLE";
    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
    private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
    private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps

    private Map<String, Intent> mNameToIntent;
    private Map<String, String> mNameToProcess;
    private Map<String, String> mNameToResultKey;
    private Map<String, Long> mNameToLaunchTime;
    private IActivityManager mAm;
    private int mLaunchIterations = 10;
    private Bundle mResult = new Bundle();
    private Set<String> mRequiredAccounts;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
    }

    @Override
    protected void tearDown() throws Exception {
        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
        super.tearDown();
    }

    public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException {
        InstrumentationTestRunner instrumentation =
                (InstrumentationTestRunner)getInstrumentation();
        Bundle args = instrumentation.getArguments();
        mAm = ActivityManagerNative.getDefault();

        createMappings();
        parseArgs(args);
        checkAccountSignIn();

        // do initial app launch, without force stopping
        for (String app : mNameToResultKey.keySet()) {
            long launchTime = startApp(app, false);
            if (launchTime <= 0) {
                mNameToLaunchTime.put(app, -1L);
                // simply pass the app if launch isn't successful
                // error should have already been logged by startApp
                continue;
            } else {
                mNameToLaunchTime.put(app, launchTime);
            }
            sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
            closeApp(app, false);
            sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
        }
        // do the real app launch now
        for (int i = 0; i < mLaunchIterations; i++) {
            for (String app : mNameToResultKey.keySet()) {
                long prevLaunchTime = mNameToLaunchTime.get(app);
                long launchTime = 0;
                if (prevLaunchTime < 0) {
                    // skip if the app has previous failures
                    continue;
                }
                launchTime = startApp(app, true);
                if (launchTime <= 0) {
                    // if it fails once, skip the rest of the launches
                    mNameToLaunchTime.put(app, -1L);
                    continue;
                }
                // keep the min launch time
                if (launchTime < prevLaunchTime) {
                    mNameToLaunchTime.put(app, launchTime);
                }
                sleep(POST_LAUNCH_IDLE_TIMEOUT);
                closeApp(app, true);
                sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
            }
        }
        for (String app : mNameToResultKey.keySet()) {
            long launchTime = mNameToLaunchTime.get(app);
            if (launchTime != -1) {
                mResult.putLong(mNameToResultKey.get(app), launchTime);
            }
        }
        instrumentation.sendStatus(0, mResult);
    }

    private void parseArgs(Bundle args) {
        mNameToResultKey = new LinkedHashMap<String, String>();
        mNameToLaunchTime = new HashMap<String, Long>();
        String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
        if (launchIterations != null) {
            mLaunchIterations = Integer.parseInt(launchIterations);
        }
        String appList = args.getString(KEY_APPS);
        if (appList == null)
            return;

        String appNames[] = appList.split("\\|");
        for (String pair : appNames) {
            String[] parts = pair.split("\\^");
            if (parts.length != 2) {
                Log.e(TAG, "The apps key is incorrectly formatted");
                fail();
            }

            mNameToResultKey.put(parts[0], parts[1]);
            mNameToLaunchTime.put(parts[0], 0L);
        }
        String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
        if (requiredAccounts != null) {
            mRequiredAccounts = new HashSet<String>();
            for (String accountType : requiredAccounts.split(",")) {
                mRequiredAccounts.add(accountType);
            }
        }
    }

    private boolean hasLeanback(Context context) {
        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
    }

    private void createMappings() {
        mNameToIntent = new LinkedHashMap<String, Intent>();
        mNameToProcess = new LinkedHashMap<String, String>();

        PackageManager pm = getInstrumentation().getContext()
                .getPackageManager();
        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
        intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
                Intent.CATEGORY_LEANBACK_LAUNCHER :
                Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
        resolveLoop(ris, intentToResolve, pm);
        // For Wear
        intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
        ris = pm.queryIntentActivities(intentToResolve, 0);
        resolveLoop(ris, intentToResolve, pm);
    }

    private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
        if (ris == null || ris.isEmpty()) {
            Log.i(TAG, "Could not find any apps");
        } else {
            for (ResolveInfo ri : ris) {
                Intent startIntent = new Intent(intentToResolve);
                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                startIntent.setClassName(ri.activityInfo.packageName,
                        ri.activityInfo.name);
                String appName = ri.loadLabel(pm).toString();
                if (appName != null) {
                    mNameToIntent.put(appName, startIntent);
                    mNameToProcess.put(appName, ri.activityInfo.processName);
                }
            }
        }
    }

    private long startApp(String appName, boolean forceStopBeforeLaunch)
            throws NameNotFoundException, RemoteException {
        Log.i(TAG, "Starting " + appName);

        Intent startIntent = mNameToIntent.get(appName);
        if (startIntent == null) {
            Log.w(TAG, "App does not exist: " + appName);
            mResult.putString(mNameToResultKey.get(appName), "App does not exist");
            return -1;
        }
        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch);
        Thread t = new Thread(runnable);
        t.start();
        try {
            t.join(JOIN_TIMEOUT);
        } catch (InterruptedException e) {
            // ignore
        }
        WaitResult result = runnable.getResult();
        // report error if any of the following is true:
        // * launch thread is alive
        // * result is not null, but:
        //   * result is not START_SUCCESS
        //   * or in case of no force stop, result is not TASK_TO_FRONT either
        if (t.isAlive() || (result != null
                && ((result.result != ActivityManager.START_SUCCESS)
                        && (!forceStopBeforeLaunch
                                && result.result != ActivityManager.START_TASK_TO_FRONT)))) {
            Log.w(TAG, "Assuming app " + appName + " crashed.");
            reportError(appName, mNameToProcess.get(appName));
            return -1;
        }
        return result.thisTime;
    }

    private void checkAccountSignIn() {
        // ensure that the device has the required account types before starting test
        // e.g. device must have a valid Google account sign in to measure a meaningful launch time
        // for Gmail
        if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
            return;
        }
        final AccountManager am =
                (AccountManager) getInstrumentation().getTargetContext().getSystemService(
                        Context.ACCOUNT_SERVICE);
        Account[] accounts = am.getAccounts();
        // use set here in case device has multiple accounts of the same type
        Set<String> foundAccounts = new HashSet<String>();
        for (Account account : accounts) {
            if (mRequiredAccounts.contains(account.type)) {
                foundAccounts.add(account.type);
            }
        }
        // check if account type matches, if not, fail test with message on what account types
        // are missing
        if (mRequiredAccounts.size() != foundAccounts.size()) {
            mRequiredAccounts.removeAll(foundAccounts);
            StringBuilder sb = new StringBuilder("Device missing these accounts:");
            for (String account : mRequiredAccounts) {
                sb.append(' ');
                sb.append(account);
            }
            fail(sb.toString());
        }
    }

    private void closeApp(String appName, boolean forceStopApp) {
        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
        homeIntent.addCategory(Intent.CATEGORY_HOME);
        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        getInstrumentation().getContext().startActivity(homeIntent);
        sleep(POST_LAUNCH_IDLE_TIMEOUT);
        if (forceStopApp) {
            Intent startIntent = mNameToIntent.get(appName);
            if (startIntent != null) {
                String packageName = startIntent.getComponent().getPackageName();
                try {
                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
                } catch (RemoteException e) {
                    Log.w(TAG, "Error closing app", e);
                }
            }
        }
    }

    private void sleep(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            // ignore
        }
    }

    private void reportError(String appName, String processName) {
        ActivityManager am = (ActivityManager) getInstrumentation()
                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
        if (crashes != null) {
            for (ProcessErrorStateInfo crash : crashes) {
                if (!crash.processName.equals(processName))
                    continue;

                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
                mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
                return;
            }
        }

        mResult.putString(mNameToResultKey.get(appName),
                "Crashed for unknown reason");
        Log.w(TAG, appName
                + " not found in process list, most likely it is crashed");
    }

    private class AppLaunchRunnable implements Runnable {
        private Intent mLaunchIntent;
        private IActivityManager.WaitResult mResult;
        private boolean mForceStopBeforeLaunch;

        public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch) {
            mLaunchIntent = intent;
            mForceStopBeforeLaunch = forceStopBeforeLaunch;
        }

        public IActivityManager.WaitResult getResult() {
            return mResult;
        }

        public void run() {
            try {
                String packageName = mLaunchIntent.getComponent().getPackageName();
                if (mForceStopBeforeLaunch) {
                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
                }
                String mimeType = mLaunchIntent.getType();
                if (mimeType == null && mLaunchIntent.getData() != null
                        && "content".equals(mLaunchIntent.getData().getScheme())) {
                    mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(),
                            UserHandle.USER_CURRENT);
                }

                mResult = mAm.startActivityAndWait(null, null, mLaunchIntent, mimeType,
                        null, null, 0, mLaunchIntent.getFlags(), null, null,
                        UserHandle.USER_CURRENT);
            } catch (RemoteException e) {
                Log.w(TAG, "Error launching app", e);
            }
        }
    }
}
