/*
 * Copyright (C) 2015 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.shell;

import static android.test.MoreAsserts.assertContainsRegex;
import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.EXTRA_ID;
import static com.android.shell.BugreportProgressService.EXTRA_MAX;
import static com.android.shell.BugreportProgressService.EXTRA_NAME;
import static com.android.shell.BugreportProgressService.EXTRA_PID;
import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import libcore.io.Streams;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Instrumentation;
import android.app.NotificationManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemProperties;
import android.service.notification.StatusBarNotification;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;

import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
import com.android.shell.BugreportProgressService;

/**
 * Integration tests for {@link BugreportReceiver}.
 * <p>
 * These tests don't mock any component and rely on external UI components (like the notification
 * bar and activity chooser), which can make them unreliable and slow.
 * <p>
 * The general workflow is:
 * <ul>
 * <li>creates the bug report files
 * <li>generates the BUGREPORT_FINISHED intent
 * <li>emulate user actions to share the intent with a custom activity
 * <li>asserts the extras received by the custom activity
 * </ul>
 * <p>
 * <strong>NOTE</strong>: these tests only work if the device is unlocked.
 */
@LargeTest
public class BugreportReceiverTest extends InstrumentationTestCase {
    private static final String TAG = "BugreportReceiverTest";

    // Timeout for UI operations, in milliseconds.
    private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;

    // Timeout for when waiting for a screenshot to finish.
    private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;

    private static final String BUGREPORTS_DIR = "bugreports";
    private static final String BUGREPORT_FILE = "test_bugreport.txt";
    private static final String ZIP_FILE = "test_bugreport.zip";
    private static final String ZIP_FILE2 = "test_bugreport2.zip";
    private static final String SCREENSHOT_FILE = "test_screenshot.png";

    private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
    private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";

    private static final int PID = 42;
    private static final int PID2 = 24;
    private static final int ID = 108;
    private static final int ID2 = 801;
    private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress";
    private static final String MAX_PROPERTY = "dumpstate." + PID + ".max";
    private static final String NAME_PROPERTY = "dumpstate." + PID + ".name";
    private static final String NAME = "BUG, Y U NO REPORT?";
    private static final String NAME2 = "A bugreport's life";
    private static final String NEW_NAME = "Bug_Forrest_Bug";
    private static final String NEW_NAME2 = "BugsyReportsy";
    private static final String TITLE = "Wimbugdom Champion 2015";
    private static final String TITLE2 = "Master of the Universe";
    private static final String DESCRIPTION = "One's description...";
    private static final String DESCRIPTION2 = "...is another's treasure.";

    private static final String NO_DESCRIPTION = null;
    private static final String NO_NAME = null;
    private static final String NO_SCREENSHOT = null;
    private static final String NO_TITLE = null;
    private static final int NO_ID = 0;
    private static final boolean RENAMED_SCREENSHOTS = true;
    private static final boolean DIDNT_RENAME_SCREENSHOTS = false;

    private String mDescription;

    private String mPlainTextPath;
    private String mZipPath;
    private String mZipPath2;
    private String mScreenshotPath;

    private Context mContext;
    private UiBot mUiBot;
    private CustomActionSendMultipleListener mListener;

    @Override
    protected void setUp() throws Exception {
        Log.i(TAG, "#### setup() on " + getName());
        Instrumentation instrumentation = getInstrumentation();
        mContext = instrumentation.getTargetContext();
        mUiBot = new UiBot(UiDevice.getInstance(instrumentation), TIMEOUT);
        mListener = ActionSendMultipleConsumerActivity.getListener(mContext);

        cancelExistingNotifications();

        mPlainTextPath = getPath(BUGREPORT_FILE);
        mZipPath = getPath(ZIP_FILE);
        mZipPath2 = getPath(ZIP_FILE2);
        mScreenshotPath = getPath(SCREENSHOT_FILE);
        createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
        createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
        createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
        createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT);

        // Creates a multi-line description.
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 20; i++) {
            sb.append("All work and no play makes Shell a dull app!\n");
        }
        mDescription = sb.toString();

        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
    }

    public void testProgress() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        waitForScreenshotButtonEnabled(true);

        final NumberFormat nf = NumberFormat.getPercentInstance();
        nf.setMinimumFractionDigits(2);
        nf.setMaximumFractionDigits(2);

        assertProgressNotification(NAME, nf.format(0));

        SystemProperties.set(PROGRESS_PROPERTY, "108");
        assertProgressNotification(NAME, nf.format(0.108));

        SystemProperties.set(PROGRESS_PROPERTY, "500");
        assertProgressNotification(NAME, nf.format(0.50));

        SystemProperties.set(MAX_PROPERTY, "2000");
        assertProgressNotification(NAME, nf.format(0.25));

        Bundle extras =
                sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testProgress_cancel() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        waitForScreenshotButtonEnabled(true);

        final NumberFormat nf = NumberFormat.getPercentInstance();
        nf.setMinimumFractionDigits(2);
        nf.setMaximumFractionDigits(2);

        assertProgressNotification(NAME, nf.format(0));

        openProgressNotification(ID);
        UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString(
                com.android.internal.R.string.cancel).toUpperCase());
        mUiBot.click(cancelButton, "cancel_button");

        waitForService(false);
    }

    public void testProgress_takeExtraScreenshot() throws Exception {
        takeExtraScreenshotTest(false);
    }

    public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
        takeExtraScreenshotTest(true);
    }

    private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
        resetProperties();
        sendBugreportStarted(1000);

        waitForScreenshotButtonEnabled(true);
        takeScreenshot();
        assertScreenshotButtonEnabled(false);
        waitForScreenshotButtonEnabled(true);

        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);

        if (serviceDies) {
            waitShareNotification(ID);
            killService();
        }

        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testScreenshotFinishesAfterBugreport() throws Exception {
        screenshotFinishesAfterBugreportTest(false);
    }

    public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
        screenshotFinishesAfterBugreportTest(true);
    }

    private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
        resetProperties();

        sendBugreportStarted(1000);
        sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT);
        waitShareNotification(ID);

        // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
        Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);

        if (serviceDies) {
            killService();
        }

        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
                NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testProgress_changeDetailsInvalidInput() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        waitForScreenshotButtonEnabled(true);

        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);

        // Check initial name.
        detailsUi.assertName(NAME);

        // Change name - it should have changed system property once focus is changed.
        detailsUi.nameField.setText(NEW_NAME);
        detailsUi.focusAwayFromName();
        assertPropertyValue(NAME_PROPERTY, NEW_NAME);

        // Cancel the dialog to make sure property was restored.
        detailsUi.clickCancel();
        assertPropertyValue(NAME_PROPERTY, NAME);

        // Now try to set an invalid name.
        detailsUi.reOpen();
        detailsUi.nameField.setText("/etc/passwd");
        detailsUi.clickOk();
        assertPropertyValue(NAME_PROPERTY, "_etc_passwd");

        // Finally, make the real changes.
        detailsUi.reOpen();
        detailsUi.nameField.setText(NEW_NAME);
        detailsUi.titleField.setText(TITLE);
        detailsUi.descField.setText(mDescription);

        detailsUi.clickOk();

        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
        assertProgressNotification(NEW_NAME, "0.00%");

        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
                mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testProgress_changeDetailsPlainBugreport() throws Exception {
        changeDetailsTest(true);
    }

    public void testProgress_changeDetailsZippedBugreport() throws Exception {
        changeDetailsTest(false);
    }

    public void changeDetailsTest(boolean plainText) throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        waitForScreenshotButtonEnabled(true);

        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);

        // Check initial name.
        detailsUi.assertName(NAME);

        // Change fields.
        detailsUi.reOpen();
        detailsUi.nameField.setText(NEW_NAME);
        detailsUi.titleField.setText(TITLE);
        detailsUi.descField.setText(mDescription);

        detailsUi.clickOk();

        assertPropertyValue(NAME_PROPERTY, NEW_NAME);
        assertProgressNotification(NEW_NAME, "0.00%");

        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
                plainText? mPlainTextPath : mZipPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testProgress_changeJustDetailsTouchingDetails() throws Exception {
        changeJustDetailsTest(true);
    }

    public void testProgress_changeJustDetailsTouchingNotification() throws Exception {
        changeJustDetailsTest(false);
    }

    private void changeJustDetailsTest(boolean touchDetails) throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        waitForScreenshotButtonEnabled(true);

        DetailsUi detailsUi = new DetailsUi(mUiBot, ID, touchDetails);

        detailsUi.nameField.setText("");
        detailsUi.titleField.setText("");
        detailsUi.descField.setText(mDescription);
        detailsUi.clickOk();

        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS);

        assertServiceNotRunning();
    }

    /*
     * TODO: this test can be flanky because it relies in the order the notifications are displayed,
     * since mUiBot gets the first notification.
     * Ideally, openProgressNotification() should return the whole notification, so DetailsUi
     * could use it and find children instead, but unfortunately the notification object hierarchy
     * is too complex and getting it from the notification text object would be to fragile
     * (for instance, it could require navigating many parents up in the hierarchy).
     */
    public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception {
        resetProperties();
        sendBugreportStarted(ID, PID, NAME, 1000);
        waitForScreenshotButtonEnabled(true);

        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
        detailsUi.assertName(NAME);
        detailsUi.assertTitle("");
        detailsUi.assertDescription("");
        detailsUi.nameField.setText(NEW_NAME);
        detailsUi.titleField.setText(TITLE);
        detailsUi.descField.setText(DESCRIPTION);
        detailsUi.clickOk();

        sendBugreportStarted(ID2, PID2, NAME2, 1000);

        Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                NEW_NAME, TITLE, DESCRIPTION, 1, RENAMED_SCREENSHOTS);

        detailsUi = new DetailsUi(mUiBot, ID2);
        detailsUi.assertName(NAME2);
        detailsUi.assertTitle("");
        detailsUi.assertDescription("");
        detailsUi.nameField.setText(NEW_NAME2);
        detailsUi.titleField.setText(TITLE2);
        detailsUi.descField.setText(DESCRIPTION2);
        detailsUi.clickOk();

        // Must use a different zip file otherwise it will fail because zip already contains
        // title.txt and description.txt entries.
        extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
                NEW_NAME2, TITLE2, DESCRIPTION2, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    /**
     * Tests the scenario where the initial screenshot and dumpstate are finished while the user
     * is changing the info in the details screen.
     */
    public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
        bugreportFinishedWhileChangingDetailsTest(false);
    }

    /**
     * Tests the scenario where dumpstate is finished while the user is changing the info in the
     * details screen, but the initial screenshot finishes afterwards.
     */
    public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
        bugreportFinishedWhileChangingDetailsTest(true);
    }

    private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
        resetProperties();
        sendBugreportStarted(1000);
        if (waitScreenshot) {
            waitForScreenshotButtonEnabled(true);
        }

        DetailsUi detailsUi = new DetailsUi(mUiBot, ID);

        // Finish the bugreport while user's still typing the name.
        detailsUi.nameField.setText(NEW_NAME);
        sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);

        // Wait until the share notification is received...
        waitShareNotification(ID);
        // ...then close notification bar.
        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));

        // Make sure UI was updated properly.
        assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled());
        assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString());

        // Finish changing other fields.
        detailsUi.titleField.setText(TITLE);
        detailsUi.descField.setText(mDescription);
        detailsUi.clickOk();

        // Finally, share bugreport.
        Bundle extras = acceptBugreportAndGetSharedIntent(ID);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
                NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);

        assertServiceNotRunning();
    }

    public void testBugreportFinished_withWarning() throws Exception {
        // Explicitly shows the warning.
        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);

        // Send notification and click on share.
        sendBugreportFinished(NO_ID, mPlainTextPath, null);
        acceptBugreport(NO_ID);

        // Handle the warning
        mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
        // TODO: get ok and showMessageAgain from the dialog reference above
        UiObject showMessageAgain =
                mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
        mUiBot.click(showMessageAgain, "show-message-again");
        UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
        mUiBot.click(ok, "ok");

        // Share the bugreport.
        mUiBot.chooseActivity(UI_NAME);
        Bundle extras = mListener.getExtras();
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);

        // Make sure it's hidden now.
        int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
        assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
    }

    public void testShareBugreportAfterServiceDies() throws Exception {
        sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
        killService();
        Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
    }

    public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
    }

    public void testBugreportFinished_zippedBugreportAndScreenshot() throws Exception {
        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, mScreenshotPath);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
    }

    public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
    }

    public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
        Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT);
        assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
    }

    private void cancelExistingNotifications() {
        NotificationManager nm = NotificationManager.from(mContext);
        for (StatusBarNotification notification : nm.getActiveNotifications()) {
            int id = notification.getId();
            Log.i(TAG, "Canceling existing notification (id=" + id + ")");
            nm.cancel(id);
        }
    }

    private void assertProgressNotification(String name, String percent) {
        // TODO: it currently looks for 3 distinct objects, without taking advantage of their
        // relationship.
        openProgressNotification(ID);
        Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
        mUiBot.getObject(name);
        mUiBot.getObject(percent);
    }

    private UiObject openProgressNotification(int id) {
        String title = mContext.getString(R.string.bugreport_in_progress_title, id);
        Log.v(TAG, "Looking for progress notification title: '" + title + "'");
        return mUiBot.getNotification(title);
    }

    void resetProperties() {
        // TODO: call method to remove property instead
        SystemProperties.set(PROGRESS_PROPERTY, "Reset");
        SystemProperties.set(MAX_PROPERTY, "Reset");
        SystemProperties.set(NAME_PROPERTY, "Reset");
    }

    /**
     * Sends a "bugreport started" intent with the default values.
     */
    private void sendBugreportStarted(int max) throws Exception {
        sendBugreportStarted(ID, PID, NAME, max);
    }

    private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception {
        Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(EXTRA_ID, id);
        intent.putExtra(EXTRA_PID, pid);
        intent.putExtra(EXTRA_NAME, name);
        intent.putExtra(EXTRA_MAX, max);
        mContext.sendBroadcast(intent);
    }

    /**
     * Sends a "bugreport finished" intent and waits for the result.
     *
     * @return extras sent in the shared intent.
     */
    private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
            String screenshotPath) {
        return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath);
    }

    /**
     * Sends a "bugreport finished" intent and waits for the result.
     *
     * @return extras sent in the shared intent.
     */
    private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
            String screenshotPath) {
        sendBugreportFinished(id, bugreportPath, screenshotPath);
        return acceptBugreportAndGetSharedIntent(id);
    }

    /**
     * Accepts the notification to share the finished bugreport and waits for the result.
     *
     * @return extras sent in the shared intent.
     */
    private Bundle acceptBugreportAndGetSharedIntent(int id) {
        acceptBugreport(id);
        mUiBot.chooseActivity(UI_NAME);
        return mListener.getExtras();
    }

    /**
     * Waits for the notification to share the finished bugreport.
     */
    private void waitShareNotification(int id) {
        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, id));
    }

    /**
     * Accepts the notification to share the finished bugreport.
     */
    private void acceptBugreport(int id) {
        mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
    }

    /**
     * Sends a "bugreport finished" intent.
     */
    private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
        Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        if (id != NO_ID) {
            intent.putExtra(EXTRA_ID, id);
        }
        if (bugreportPath != null) {
            intent.putExtra(EXTRA_BUGREPORT, bugreportPath);
        }
        if (screenshotPath != null) {
            intent.putExtra(EXTRA_SCREENSHOT, screenshotPath);
        }

        mContext.sendBroadcast(intent);
    }

    /**
     * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
     */
    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
            String screenshotContent) throws IOException {
        assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE,
                NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
    }

    /**
     * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
     *
     * @param extras extras received in the intent
     * @param bugreportContent expected content in the bugreport file
     * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
     * @param id emulated dumpstate id
     * @param pid emulated dumpstate pid
     * @param name expected subject
     * @param name bugreport name as provided by the user (or received by dumpstate)
     * @param title bugreport name as provided by the user
     * @param description bugreport description as provided by the user
     * @param numberScreenshots expected number of screenshots taken by Shell.
     * @param renamedScreenshots whether the screenshots are expected to be renamed
     */
    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
            String screenshotContent, int id, int pid, String subject,
            String name, String title, String description,
            int numberScreenshots, boolean renamedScreenshots) throws IOException {
        String body = extras.getString(Intent.EXTRA_TEXT);
        assertContainsRegex("missing build info",
                SystemProperties.get("ro.build.description"), body);
        assertContainsRegex("missing serial number",
                SystemProperties.get("ro.serialno"), body);
        if (description != null) {
            assertContainsRegex("missing description", description, body);
        }

        assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));

        List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
        int expectedNumberScreenshots = numberScreenshots;
        if (screenshotContent != null) {
            expectedNumberScreenshots ++; // Add screenshot received by dumpstate
        }
        int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
        assertEquals("wrong number of attachments (" + attachments + ")",
                expectedSize, attachments.size());

        // Need to interact through all attachments, since order is not guaranteed.
        Uri zipUri = null;
        List<Uri> screenshotUris = new ArrayList<>(expectedNumberScreenshots);
        for (Uri attachment : attachments) {
            if (attachment.getPath().endsWith(".zip")) {
                zipUri = attachment;
            }
            if (attachment.getPath().endsWith(".png")) {
                screenshotUris.add(attachment);
            }
        }
        assertNotNull("did not get .zip attachment", zipUri);
        assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT);
        if (!TextUtils.isEmpty(title)) {
            assertZipContent(zipUri, "title.txt", title);
        }
        if (!TextUtils.isEmpty(description)) {
            assertZipContent(zipUri, "description.txt", description);
        }

        // URI of the screenshot taken by dumpstate.
        Uri externalScreenshotUri = null;
        SortedSet<String> internalScreenshotNames = new TreeSet<>();
        for (Uri screenshotUri : screenshotUris) {
            String screenshotName = screenshotUri.getLastPathSegment();
            if (screenshotName.endsWith(SCREENSHOT_FILE)) {
                externalScreenshotUri = screenshotUri;
            } else {
                internalScreenshotNames.add(screenshotName);
            }
        }
        // Check external screenshot
        if (screenshotContent != null) {
            assertNotNull("did not get .png attachment for external screenshot",
                    externalScreenshotUri);
            assertContent(externalScreenshotUri, SCREENSHOT_CONTENT);
        } else {
            assertNull("should not have .png attachment for external screenshot",
                    externalScreenshotUri);
        }
        // Check internal screenshots.
        SortedSet<String> expectedNames = new TreeSet<>();
        for (int i = 1 ; i <= numberScreenshots; i++) {
            String prefix = renamedScreenshots  ? name : Integer.toString(pid);
            String expectedName = "screenshot-" + prefix + "-" + i + ".png";
            expectedNames.add(expectedName);
        }
        // Ideally we should use MoreAsserts, but the error message in case of failure is not
        // really useful.
        assertEquals("wrong names for internal screenshots",
                expectedNames, internalScreenshotNames);
    }

    private void assertContent(Uri uri, String expectedContent) throws IOException {
        Log.v(TAG, "assertContents(uri=" + uri);
        try (InputStream is = mContext.getContentResolver().openInputStream(uri)) {
            String actualContent = new String(Streams.readFully(is));
            assertEquals("wrong content for '" + uri + "'", expectedContent, actualContent);
        }
    }

    private void assertZipContent(Uri uri, String entryName, String expectedContent)
            throws IOException, IOException {
        Log.v(TAG, "assertZipEntry(uri=" + uri + ", entryName=" + entryName);
        try (ZipInputStream zis = new ZipInputStream(mContext.getContentResolver().openInputStream(
                uri))) {
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                Log.v(TAG, "Zip entry: " + entry.getName());
                if (entry.getName().equals(entryName)) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    Streams.copy(zis, bos);
                    String actualContent = new String(bos.toByteArray(), "UTF-8");
                    bos.close();
                    assertEquals("wrong content for zip entry'" + entryName + "' on '" + uri + "'",
                            expectedContent, actualContent);
                    return;
                }
            }
        }
        fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
    }

    private void assertPropertyValue(String key, String expectedValue) {
        String actualValue = SystemProperties.get(key);
        assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue);
    }

    private void assertServiceNotRunning() {
        String service = BugreportProgressService.class.getName();
        assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
    }

    private void killService() {
        waitForService(true);
        Log.v(TAG, "Stopping service");
        boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
        Log.d(TAG, "stopService returned " + stopped);
        waitForService(false);
        assertServiceNotRunning();  // Sanity check.
    }

    private boolean isServiceRunning(String name) {
        ActivityManager manager = (ActivityManager) mContext
                .getSystemService(Context.ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (service.service.getClassName().equals(name)) {
                return true;
            }
        }
        return false;
    }

    private void waitForService(boolean expectRunning) {
        String service = BugreportProgressService.class.getName();
        boolean actualRunning;
        for (int i = 1; i <= 5; i++) {
            actualRunning = isServiceRunning(service);
            Log.d(TAG, "Attempt " + i + " to check status of service '"
                    + service + "': expected=" + expectRunning + ", actual= " + actualRunning);
            if (actualRunning == expectRunning) {
                return;
            }
            try {
                Thread.sleep(DateUtils.SECOND_IN_MILLIS);
            } catch (InterruptedException e) {
                Log.w(TAG, "thread interrupted");
                Thread.currentThread().interrupt();
            }
        }
        if (!expectRunning) {
            // Typically happens when service is waiting for a screenshot to finish.
            Log.w(TAG, "Service didn't stop; try to kill it again");
            killService();
            return;
        }

        fail("Service status didn't change to " + expectRunning);
    }

    private void createTextFile(String path, String content) throws IOException {
        Log.v(TAG, "createFile(" + path + ")");
        try (Writer writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(path)))) {
            writer.write(content);
        }
    }

    private void createZipFile(String path, String entryName, String content) throws IOException {
        Log.v(TAG, "createZipFile(" + path + ", " + entryName + ")");
        try (ZipOutputStream zos = new ZipOutputStream(
                new BufferedOutputStream(new FileOutputStream(path)))) {
            ZipEntry entry = new ZipEntry(entryName);
            zos.putNextEntry(entry);
            byte[] data = content.getBytes();
            zos.write(data, 0, data.length);
            zos.closeEntry();
        }
    }

    private String getPath(String file) {
        File rootDir = new ContextWrapper(mContext).getFilesDir();
        File dir = new File(rootDir, BUGREPORTS_DIR);
        if (!dir.exists()) {
            Log.i(TAG, "Creating directory " + dir);
            assertTrue("Could not create directory " + dir, dir.mkdir());
        }
        String path = new File(dir, file).getAbsolutePath();
        Log.v(TAG, "Path for '" + file + "': " + path);
        return path;
    }

    /**
     * Gets the notification button used to take a screenshot.
     */
    private UiObject getScreenshotButton() {
        openProgressNotification(ID);
        return mUiBot.getVisibleObject(
                mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
    }

    /**
     * Takes a screenshot using the system notification.
     */
    private void takeScreenshot() throws Exception {
        UiObject screenshotButton = getScreenshotButton();
        mUiBot.click(screenshotButton, "screenshot_button");
    }

    private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
        UiObject screenshotButton = getScreenshotButton();
        int maxAttempts = SAFE_SCREENSHOT_DELAY;
        int i = 0;
        do {
            boolean enabled = screenshotButton.isEnabled();
            if (enabled == expectedEnabled) {
                return screenshotButton;
            }
            i++;
            Log.v(TAG, "Sleeping for 1 second while waiting for screenshot.enable to be "
                    + expectedEnabled + " (attempt " + i + ")");
            Thread.sleep(DateUtils.SECOND_IN_MILLIS);
        } while (i <= maxAttempts);
        fail("screenshot.enable didn't change to " + expectedEnabled + " in " + maxAttempts + "s");
        return screenshotButton;
    }

    private void assertScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
        UiObject screenshotButton = getScreenshotButton();
        assertEquals("wrong state for screenshot button ", expectedEnabled,
                screenshotButton.isEnabled());
    }

    /**
     * Helper class containing the UiObjects present in the bugreport info dialog.
     */
    private final class DetailsUi {

        final UiObject detailsButton;
        final UiObject nameField;
        final UiObject titleField;
        final UiObject descField;
        final UiObject okButton;
        final UiObject cancelButton;

        /**
         * Gets the UI objects by opening the progress notification and clicking DETAILS.
         */
        DetailsUi(UiBot uiBot, int id) throws UiObjectNotFoundException {
            this(uiBot, id, true);
        }

        /**
         * Gets the UI objects by opening the progress notification and clicking on DETAILS or in
         * the notification itself.
         */
        DetailsUi(UiBot uiBot, int id, boolean clickDetails) throws UiObjectNotFoundException {
            UiObject notification = openProgressNotification(id);
            detailsButton = mUiBot.getVisibleObject(mContext.getString(
                    R.string.bugreport_info_action).toUpperCase());

            if (clickDetails) {
                mUiBot.click(detailsButton, "details_button");
            } else {
                mUiBot.click(notification, "notification");
            }
            // TODO: unhardcode resource ids
            UiObject dialogTitle = mUiBot.getVisibleObjectById("android:id/alertTitle");
            assertEquals("Wrong title", mContext.getString(R.string.bugreport_info_dialog_title,
                    id), dialogTitle.getText().toString());
            nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
            titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
            descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
            okButton = mUiBot.getObjectById("android:id/button1");
            cancelButton = mUiBot.getObjectById("android:id/button2");
        }

        private void assertField(String name, UiObject field, String expected) {
            try {
                String actual = field.getText().toString();
                assertEquals("Wrong value on field '" + name + "'", expected, actual);
            } catch (UiObjectNotFoundException e) {
                // Should not happen...
                throw new IllegalStateException("field not found: " + name, e);
            }
        }

        void assertName(String expected) {
            assertField("name", nameField, expected);
        }

        void assertTitle(String expected) {
            assertField("title", titleField, expected);
        }

        void assertDescription(String expected) {
            assertField("description", descField, expected);
        }

        /**
         * Takes focus away from the name field so it can be validated.
         */
        void focusAwayFromName() {
            mUiBot.click(titleField, "title_field"); // Change focus.
            mUiBot.pressBack(); // Dismiss keyboard.
        }

        void reOpen() {
            openProgressNotification(ID);
            mUiBot.click(detailsButton, "details_button");

        }

        void clickOk() {
            mUiBot.click(okButton, "details_ok_button");
        }

        void clickCancel() {
            mUiBot.click(cancelButton, "details_cancel_button");
        }
    }
}
