Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc73ffc0 authored by Felipe Leme's avatar Felipe Leme
Browse files

Allows users to add details about a bugreport in progress.

The "bugreport in progress" notification now have a "DETAILS" button
that when clicked opens a dialog window displaying the following fields:

  - Name: short name for the bugreport, will be used as part of the
    final files (and by default is the timestamp sent by dumpstate)
  - Title: a 1-line title for the bugreport, will be used as the subject
    in the final message.
  - Description: a detailed description for the bug.

The main advantage of such dialog is that it allows users to enter more
info about a bugreport while it's being generated, rather then when the
bugreport is finished (since of the user doesn't remember what the
context was when the problem happened).

BUG: 25794470
BUG: 10676443
Change-Id: I0d1dba2a94ad989e541415a2a59475619a2e3d13
parent 5144d154
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <EditText
        android:id="@+id/name"
        android:maxLength="30"
        android:singleLine="true"
        android:inputType="textNoSuggestions"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/bugreport_info_name"/>
    <EditText
        android:id="@+id/title"
        android:maxLength="80"
        android:singleLine="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/bugreport_info_title"/>
    <EditText
        android:id="@+id/description"
        android:singleLine="false"
        android:inputType="textMultiLine"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/bugreport_info_description"/>
</LinearLayout>
+15 −0
Original line number Diff line number Diff line
@@ -42,4 +42,19 @@
    <!-- Title for bug reports received from dumpstate without a name. [CHAR LIMIT=30]-->
    <string name="bugreport_unnamed">unnamed</string>

    <!-- Title of the notification action that opens the dialog for the user-defined bug report details. -->
    <string name="bugreport_info_action">Details</string>

    <!--  Title of the dialog asking for user-defined bug report details like name, title, and description. -->
    <string name="bugreport_info_dialog_title">Bug report details</string>

    <!-- Text of the hint asking for the bug report name, which when set will define a suffix in the
         bug report file names. [CHAR LIMIT=30] -->
    <string name="bugreport_info_name">Short name</string>
    <!-- Text of hint asking for the bug report title, which when set will define the
         Subject of the email message. [CHAR LIMIT=60] -->
    <string name="bugreport_info_title">1-line summary</string>
    <!-- Text of hint asking for the bug report description, which when set will describe
         what the bug report is about. [CHAR LIMIT=NONE] -->
    <string name="bugreport_info_description">Detailed description</string>
</resources>
+332 −21

File changed.

Preview size limit exceeded, changes collapsed.

+0 −2
Original line number Diff line number Diff line
@@ -8,9 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_JAVA_LIBRARIES := android.test.runner

# TODO: update and/or remove
LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator
#LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator

LOCAL_PACKAGE_NAME := ShellTests
LOCAL_INSTRUMENTATION_FOR := Shell
+159 −6
Original line number Diff line number Diff line
@@ -94,7 +94,11 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
    private static final int PID = 42;
    private static final String PROGRESS_PROPERTY = "dumpstate.42.progress";
    private static final String MAX_PROPERTY = "dumpstate.42.max";
    private static final String NAME_PROPERTY = "dumpstate.42.name";
    private static final String NAME = "BUG, Y U NO REPORT?";
    private static final String NEW_NAME = "Bug_Forrest_Bug";
    private static final String TITLE = "Wimbugdom Champion 2015";
    private String mDescription;

    private String mPlainTextPath;
    private String mZipPath;
@@ -120,10 +124,17 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
        createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
        createZipFile(mZipPath, 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 testFullWorkflow() throws Exception {
    public void testProgress() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);

@@ -145,6 +156,81 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
        assertServiceNotRunning();
    }

    public void testProgress_changeDetails() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);

        DetailsUi detailsUi = new DetailsUi(mUiBot);

        // Check initial name.
        String actualName = detailsUi.nameField.getText().toString();
        assertEquals("Wrong value on field 'name'", NAME, actualName);

        // 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(PID, mPlainTextPath,
                mScreenshotPath);
        assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);

        assertServiceNotRunning();
    }

    public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
        resetProperties();
        sendBugreportStarted(1000);

        DetailsUi detailsUi = new DetailsUi(mUiBot);

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

        // Wait until the share notifcation is received...
        mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
        // ...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();
        assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT,
                SCREENSHOT_CONTENT);

        assertServiceNotRunning();
    }

    public void testBugreportFinished_withWarning() throws Exception {
        // Explicitly shows the warning.
        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
@@ -204,14 +290,18 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
    private void assertProgressNotification(String name, String percent) {
        // TODO: it current looks for 3 distinct objects, without taking advantage of their
        // relationship.
        String title = mContext.getString(R.string.bugreport_in_progress_title);
        Log.v(TAG, "Looking for progress notification title: '" + title+ "'");
        mUiBot.getNotification(title);
        openProgressNotification();
        Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
        mUiBot.getObject(name);
        mUiBot.getObject(percent);
    }

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

    void resetProperties() {
        // TODO: call method to remove property instead
        SystemProperties.set(PROGRESS_PROPERTY, "0");
@@ -270,7 +360,6 @@ public class BugreportReceiverTest extends InstrumentationTestCase {

    /**
     * Sends a "bugreport finished" intent.
     *
     */
    private void sendBugreportFinished(Integer pid, String bugreportPath, String screenshotPath) {
        Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
@@ -292,13 +381,21 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
     */
    private void assertActionSendMultiple(Bundle extras, String bugreportContent,
            String screenshotContent) throws IOException {
        assertActionSendMultiple(extras, ZIP_FILE, null, bugreportContent, screenshotContent);
    }

    private void assertActionSendMultiple(Bundle extras, String subject, String description,
            String bugreportContent, String screenshotContent) 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", ZIP_FILE, extras.getString(Intent.EXTRA_SUBJECT));
        assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));

        List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
        int expectedSize = screenshotContent != null ? 2 : 1;
@@ -355,6 +452,11 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
        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));
@@ -402,4 +504,55 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
        Log.v(TAG, "Path for '" + file + "': " + path);
        return path;
    }

    /**
     * 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) {
            openProgressNotification();
            detailsButton = mUiBot.getVisibleObject(
                    mContext.getString(R.string.bugreport_info_action).toUpperCase());
            mUiBot.click(detailsButton, "details_button");
            // TODO: unhardcode resource ids
            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");
        }

        /**
         * 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();
            mUiBot.click(detailsButton, "details_button");

        }

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

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