/*
 * Copyright (C) 2009 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 android.app.cts;

import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.app.Instrumentation.ActivityResult;
import android.app.stubs.ActivityMonitorTestActivity;
import android.app.stubs.InstrumentationTestActivity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.test.InstrumentationTestCase;
import android.util.Log;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Instrumentation_ActivityMonitorTest extends InstrumentationTestCase {
    private static final String TAG = "ActivityMonitorTest";

    private static final long TIMEOUT_FOR_ACTIVITY_LAUNCH_MS = 5000; // 5 sec
    private static final long CHECK_INTERVAL_FOR_ACTIVITY_LAUNCH_MS = 100; // 0.1 sec

    /**
     * check points:
     * 1 Constructor with blocking true and false
     * 2 waitForActivity with timeout and no timeout
     * 3 get info about ActivityMonitor
     */
    public void testActivityMonitor() throws Exception {
        ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
        Instrumentation instrumentation = getInstrumentation();
        ActivityMonitor am = instrumentation.addMonitor(
                InstrumentationTestActivity.class.getName(), result, false);
        Context context = instrumentation.getTargetContext();
        Intent intent = new Intent(context, InstrumentationTestActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
        Activity lastActivity = am.getLastActivity();
        long timeout = System.currentTimeMillis() + TIMEOUT_FOR_ACTIVITY_LAUNCH_MS;
        while (lastActivity == null && System.currentTimeMillis() < timeout) {
            Thread.sleep(CHECK_INTERVAL_FOR_ACTIVITY_LAUNCH_MS);
            lastActivity = am.getLastActivity();
        }
        Activity activity = am.waitForActivity();
        assertSame(activity, lastActivity);
        assertEquals(1, am.getHits());
        assertTrue(activity instanceof InstrumentationTestActivity);
        activity.finish();
        instrumentation.waitForIdleSync();
        context.startActivity(intent);
        timeout = System.currentTimeMillis() + TIMEOUT_FOR_ACTIVITY_LAUNCH_MS;
        activity = null;
        while (activity == null && System.currentTimeMillis() < timeout) {
            Thread.sleep(CHECK_INTERVAL_FOR_ACTIVITY_LAUNCH_MS);
            activity = am.waitForActivityWithTimeout(CHECK_INTERVAL_FOR_ACTIVITY_LAUNCH_MS);
        }
        assertNotNull(activity);
        activity.finish();
        instrumentation.removeMonitor(am);

        am = new ActivityMonitor(InstrumentationTestActivity.class.getName(), result, true);
        assertSame(result, am.getResult());
        assertTrue(am.isBlocking());
        IntentFilter which = new IntentFilter();
        am = new ActivityMonitor(which, result, false);
        assertSame(which, am.getFilter());
        assertFalse(am.isBlocking());
    }

    /**
     * Verifies that
     *   - when ActivityMonitor.onStartActivity returs non-null, then there is monitor hit.
     *   - when ActivityMonitor.onStartActivity returns null, then the activity start is not blocked.
     */
    public void testActivityMonitor_onStartActivity() throws Exception {
        final ActivityResult result = new ActivityResult(Activity.RESULT_OK, new Intent());
        final Instrumentation instrumentation = getInstrumentation();
        final Context context = instrumentation.getTargetContext();
        final Intent intent = new Intent(context, InstrumentationTestActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        // Verify when ActivityMonitor.onStartActivity returns non-null, then there is a monitor hit.
        final CustomActivityMonitor cam1 = new CustomActivityMonitor(result);
        instrumentation.addMonitor(cam1);
        context.startActivity(intent);
        final Activity activity1 = cam1.waitForActivityWithTimeout(
                CHECK_INTERVAL_FOR_ACTIVITY_LAUNCH_MS * 2);
        try {
            assertNull("Activity should not have been started", activity1);
            assertEquals("There should be 1 monitor hit", 1, cam1.getHits());
        } finally {
            instrumentation.removeMonitor(cam1);
        }

        // Verify when ActivityMonitor.onStartActivity returns null, then activity start is not
        // blocked and there is no monitor hit.
        final CustomActivityMonitor cam2 = new CustomActivityMonitor(null);
        instrumentation.addMonitor(cam2);
        Activity activity2 = instrumentation.startActivitySync(intent);
        try {
            assertNotNull("Activity should not be null", activity2);
            assertTrue("Activity returned should be of instance InstrumentationTestActivity",
                    activity2 instanceof InstrumentationTestActivity);
            assertTrue("InstrumentationTestActivity should have been started",
                    ((InstrumentationTestActivity) activity2).isOnCreateCalled());
            assertEquals("There should be no monitor hits", 0, cam2.getHits());
        } finally {
            activity2.finish();
            instrumentation.removeMonitor(cam2);
        }
    }

    /**
     * Verifies that when ActivityMonitor.onStartActivity returns non-null, activity start is blocked.
     */
    public void testActivityMonitor_onStartActivityBlocks() throws Exception {
        final Instrumentation instrumentation = getInstrumentation();
        final Context context = instrumentation.getTargetContext();

        // Start ActivityMonitorTestActivity
        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ActivityMonitorTestActivity amTestActivity =
                (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);

        // Initialize and set activity monitor.
        final int expectedResultCode = 1111;
        final String expectedAction = "matched_using_onStartActivity";
        final CustomActivityMonitor cam = new CustomActivityMonitor(
                new ActivityResult(expectedResultCode, new Intent(expectedAction)));
        instrumentation.addMonitor(cam);

        // Start InstrumentationTestActivity from ActivityMonitorTestActivity and verify
        // it is intercepted using onStartActivity as expected.
        try {
            final CountDownLatch latch = new CountDownLatch(1);
            amTestActivity.setOnActivityResultListener(
                    new ActivityMonitorTestActivity.OnActivityResultListener() {
                        @Override
                        public void onActivityResult(int requestCode, int resultCode, Intent data) {
                            assertEquals("Result code is not same as expected",
                                    expectedResultCode, resultCode);
                            assertNotNull("Data from activity result is null", data);
                            assertEquals("Data action is not same as expected",
                                    expectedAction, data.getAction());
                            latch.countDown();
                        }
                    });
            amTestActivity.startInstrumentationTestActivity(false);
            if (!latch.await(TIMEOUT_FOR_ACTIVITY_LAUNCH_MS, TimeUnit.MILLISECONDS)) {
                fail("Timed out waiting for the activity result from "
                        + ActivityMonitorTestActivity.class.getName());
            }
            assertEquals("There should be 1 monitor hit", 1, cam.getHits());
        } finally {
            amTestActivity.finish();
            instrumentation.removeMonitor(cam);
        }
    }

    /**
     * Verifies that when the activity monitor is created using by passing IntentFilter,
     * then onStartActivity return value is ignored.
     */
    public void testActivityMonitor_onStartActivityAndIntentFilter() throws Exception {
        final Instrumentation instrumentation = getInstrumentation();
        final Context context = instrumentation.getTargetContext();

        // Start ActivityMonitorTestActivity
        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ActivityMonitorTestActivity amTestActivity =
                (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);

        // Initialize and set activity monitor.
        final int expectedResultCode = 1122;
        final String expectedAction = "matched_using_intent_filter";
        final CustomActivityMonitor cam = new CustomActivityMonitor(
                new IntentFilter(InstrumentationTestActivity.START_INTENT),
                new ActivityResult(expectedResultCode, new Intent(expectedAction)),
                true);
        cam.setResultToReturn(new ActivityResult(1111, new Intent("matched_using_onStartActivity")));
        instrumentation.addMonitor(cam);

        // Start explicit InstrumentationTestActivity from ActivityMonitorTestActivity and verify
        // it is intercepted using the intentFilter as expected.
        try {
            final CountDownLatch latch = new CountDownLatch(1);
            amTestActivity.setOnActivityResultListener(
                    new ActivityMonitorTestActivity.OnActivityResultListener() {
                        @Override
                        public void onActivityResult(int requestCode, int resultCode, Intent data) {
                            assertEquals("Result code is not same as expected",
                                    expectedResultCode, resultCode);
                            assertNotNull("Data from activity result is null", data);
                            assertEquals("Data action is not same as expected",
                                    expectedAction, data.getAction());
                            latch.countDown();
                        }
                    });
            amTestActivity.startInstrumentationTestActivity(false);
            if (!latch.await(TIMEOUT_FOR_ACTIVITY_LAUNCH_MS, TimeUnit.MILLISECONDS)) {
                fail("Timed out waiting for the activity result from "
                        + ActivityMonitorTestActivity.class.getName());
            }
            assertEquals("There should be 1 monitor hit", 1, cam.getHits());
        } finally {
            amTestActivity.finish();
            instrumentation.removeMonitor(cam);
        }
    }

    /**
     * Verifies that when the activity monitor is created using by passing activity class,
     * then onStartActivity return value is ignored.
     */
    public void testActivityMonitor_onStartActivityAndActivityClass() throws Exception {
        final Instrumentation instrumentation = getInstrumentation();
        final Context context = instrumentation.getTargetContext();

        // Start ActivityMonitorTestActivity
        final Intent intent = new Intent(context, ActivityMonitorTestActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ActivityMonitorTestActivity amTestActivity =
                (ActivityMonitorTestActivity) instrumentation.startActivitySync(intent);

        // Initialize and set activity monitor.
        final int expectedResultCode = 2244;
        final String expectedAction = "matched_using_activity_class";
        final CustomActivityMonitor cam = new CustomActivityMonitor(
                InstrumentationTestActivity.class.getName(),
                new ActivityResult(expectedResultCode, new Intent(expectedAction)),
                true);
        cam.setResultToReturn(new ActivityResult(2222, new Intent("matched_using_onStartActivity")));
        instrumentation.addMonitor(cam);

        // Start implicit InstrumentationTestActivity from ActivityMonitorTestActivity and verify
        // it is intercepted using the activity class as expected.
        try {
            final CountDownLatch latch = new CountDownLatch(1);
            amTestActivity.setOnActivityResultListener(
                    new ActivityMonitorTestActivity.OnActivityResultListener() {
                        @Override
                        public void onActivityResult(int requestCode, int resultCode, Intent data) {
                            assertEquals("Result code is not same as expected",
                                    expectedResultCode, resultCode);
                            assertNotNull("Data from activity result is null", data);
                            assertEquals("Data action is not same as expected",
                                    expectedAction, data.getAction());
                            latch.countDown();
                        }
                    });
            amTestActivity.startInstrumentationTestActivity(true);
            if (!latch.await(TIMEOUT_FOR_ACTIVITY_LAUNCH_MS, TimeUnit.MILLISECONDS)) {
                fail("Timed out waiting for the activity result from "
                        + ActivityMonitorTestActivity.class.getName());
            }
            assertEquals("There should be 1 monitor hit", 1, cam.getHits());
        } finally {
            amTestActivity.finish();
            instrumentation.removeMonitor(cam);
        }
    }

    private class CustomActivityMonitor extends ActivityMonitor {
        private ActivityResult mResultToReturn;

        public CustomActivityMonitor(ActivityResult resultToReturn) {
            super();
            mResultToReturn = resultToReturn;
        }

        public CustomActivityMonitor(IntentFilter intentFilter, ActivityResult result,
                boolean blocked) {
            super(intentFilter, result, blocked);
        }

        public CustomActivityMonitor(String activityClass, ActivityResult result,
                boolean blocked) {
            super(activityClass, result, blocked);
        }

        public void setResultToReturn(ActivityResult resultToReturn) {
            mResultToReturn = resultToReturn;
        }

        @Override
        public ActivityResult onStartActivity(Intent intent) {
            final boolean implicitInstrumentationTestActivity = intent.getAction() != null &&
                    InstrumentationTestActivity.START_INTENT.equals(intent.getAction());
            final boolean explicitInstrumentationTestActivity = intent.getComponent() != null &&
                    InstrumentationTestActivity.class.getName().equals(
                            intent.getComponent().getClassName());
            if (implicitInstrumentationTestActivity || explicitInstrumentationTestActivity) {
                return mResultToReturn;
            }
            return null;
        }
    }
}
