Loading core/res/res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,13 @@ <!-- Format for build summary info [CHAR LIMIT=NONE] --> <string name="bugreport_status" translatable="false">%s (%s)</string> <!-- Toast message informing user in how many seconds a bugreport screenshot will be taken --> <!-- DO NOT TRANSLATE YET: final phrasing still being discussed --> <plurals name="bugreport_countdown"> <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item> <item quantity="other">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> seconds.</item> </plurals> <!-- label for item that enables silent mode in phone options dialog --> <string name="global_action_toggle_silent_mode">Silent mode</string> Loading packages/Shell/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" /> <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" /> <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <uses-permission android:name="android.permission.VIBRATE" /> <application android:label="@string/app_label" android:forceDeviceEncrypted="true" Loading packages/Shell/res/values/strings.xml +8 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,14 @@ <!-- 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 notification action that takes aditional screenshots. --> <string name="bugreport_screenshot_action">Screenshot</string> <!-- Toast message sent when the a screenshot for the bug report was taken successfully. --> <string name="bugreport_screenshot_taken">Screenshot taken succesfully.</string> <!-- Toast message sent when the a screenshot for the bug report was not taken due to an error. --> <string name="bugreport_screenshot_failed">Screenshot could not be taken.</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> Loading packages/Shell/src/com/android/shell/BugreportProgressService.java +430 −168 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +126 −17 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ 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; Loading @@ -35,7 +36,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; 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; Loading @@ -56,6 +60,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.text.format.DateUtils; import android.util.Log; import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener; Loading Loading @@ -151,7 +156,25 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, null, 1); assertServiceNotRunning(); } public void testProgress_takeExtraScreenshot() throws Exception { resetProperties(); sendBugreportStarted(1000); waitForScreenshotButtonEnabled(true); takeScreenshot(); assertScreenshotButtonEnabled(false); waitForScreenshotButtonEnabled(true); Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, null, 2); assertServiceNotRunning(); } Loading Loading @@ -194,7 +217,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NEW_NAME, TITLE, mDescription, 1); assertServiceNotRunning(); } Loading Loading @@ -225,8 +249,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { // Finally, share bugreport. Bundle extras = acceptBugreportAndGetSharedIntent(); assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, TITLE, mDescription, 1); assertServiceNotRunning(); } Loading Loading @@ -288,7 +312,7 @@ 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 // TODO: it currently looks for 3 distinct objects, without taking advantage of their // relationship. openProgressNotification(); Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'"); Loading @@ -311,7 +335,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { /** * Sends a "bugreport started" intent with the default values. */ private void sendBugreportStarted(int max) { private void sendBugreportStarted(int max) throws Exception { Intent intent = new Intent(INTENT_BUGREPORT_STARTED); intent.putExtra(EXTRA_PID, PID); intent.putExtra(EXTRA_NAME, NAME); Loading Loading @@ -377,15 +401,29 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } /** * Asserts the proper ACTION_SEND_MULTIPLE intent was sent. * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent. */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent) throws IOException { assertActionSendMultiple(extras, ZIP_FILE, null, bugreportContent, screenshotContent); assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, null, ZIP_FILE, null, 0); } private void assertActionSendMultiple(Bundle extras, String subject, String description, String bugreportContent, String screenshotContent) throws IOException { /** * 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 pid emulated dumpstate pid * @param name bugreport name as provided by the user * @param title bugreport name as provided by the user (or received by dumpstate) * @param description bugreport description as provided by the user * @param numberScreenshots expected number of screenshots taken by Shell. */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent, int pid, String name, String title, String description, int numberScreenshots) throws IOException { String body = extras.getString(Intent.EXTRA_TEXT); assertContainsRegex("missing build info", SystemProperties.get("ro.build.description"), body); Loading @@ -395,31 +433,61 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertContainsRegex("missing description", description, body); } assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT)); assertEquals("wrong subject", title, extras.getString(Intent.EXTRA_SUBJECT)); List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM); int expectedSize = screenshotContent != null ? 2 : 1; 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", expectedSize, attachments.size()); // Need to interact through all attachments, since order is not guaranteed. Uri zipUri = null, screenshotUri = null; 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")) { screenshotUri = attachment; screenshotUris.add(attachment); } } assertNotNull("did not get .zip attachment", zipUri); assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT); // 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", screenshotUri); assertContent(screenshotUri, SCREENSHOT_CONTENT); assertNotNull("did not get .png attachment for external screenshot", externalScreenshotUri); assertContent(externalScreenshotUri, SCREENSHOT_CONTENT); } else { assertNull("should not have .png attachment", screenshotUri); 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 = name != null ? 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 { Loading Loading @@ -505,6 +573,47 @@ public class BugreportReceiverTest extends InstrumentationTestCase { return path; } /** * Gets the notification button used to take a screenshot. */ private UiObject getScreenshotButton() { openProgressNotification(); 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 = SCREENSHOT_DELAY_SECONDS + 2; 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. */ Loading Loading
core/res/res/values/strings.xml +7 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,13 @@ <!-- Format for build summary info [CHAR LIMIT=NONE] --> <string name="bugreport_status" translatable="false">%s (%s)</string> <!-- Toast message informing user in how many seconds a bugreport screenshot will be taken --> <!-- DO NOT TRANSLATE YET: final phrasing still being discussed --> <plurals name="bugreport_countdown"> <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item> <item quantity="other">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> seconds.</item> </plurals> <!-- label for item that enables silent mode in phone options dialog --> <string name="global_action_toggle_silent_mode">Silent mode</string> Loading
packages/Shell/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,7 @@ <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" /> <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" /> <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <uses-permission android:name="android.permission.VIBRATE" /> <application android:label="@string/app_label" android:forceDeviceEncrypted="true" Loading
packages/Shell/res/values/strings.xml +8 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,14 @@ <!-- 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 notification action that takes aditional screenshots. --> <string name="bugreport_screenshot_action">Screenshot</string> <!-- Toast message sent when the a screenshot for the bug report was taken successfully. --> <string name="bugreport_screenshot_taken">Screenshot taken succesfully.</string> <!-- Toast message sent when the a screenshot for the bug report was not taken due to an error. --> <string name="bugreport_screenshot_failed">Screenshot could not be taken.</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> Loading
packages/Shell/src/com/android/shell/BugreportProgressService.java +430 −168 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +126 −17 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ 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; Loading @@ -35,7 +36,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; 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; Loading @@ -56,6 +60,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.text.format.DateUtils; import android.util.Log; import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener; Loading Loading @@ -151,7 +156,25 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, null, 1); assertServiceNotRunning(); } public void testProgress_takeExtraScreenshot() throws Exception { resetProperties(); sendBugreportStarted(1000); waitForScreenshotButtonEnabled(true); takeScreenshot(); assertScreenshotButtonEnabled(false); waitForScreenshotButtonEnabled(true); Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, null, 2); assertServiceNotRunning(); } Loading Loading @@ -194,7 +217,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NEW_NAME, TITLE, mDescription, 1); assertServiceNotRunning(); } Loading Loading @@ -225,8 +249,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { // Finally, share bugreport. Bundle extras = acceptBugreportAndGetSharedIntent(); assertActionSendMultiple(extras, TITLE, mDescription, BUGREPORT_CONTENT, SCREENSHOT_CONTENT); assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, TITLE, mDescription, 1); assertServiceNotRunning(); } Loading Loading @@ -288,7 +312,7 @@ 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 // TODO: it currently looks for 3 distinct objects, without taking advantage of their // relationship. openProgressNotification(); Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'"); Loading @@ -311,7 +335,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { /** * Sends a "bugreport started" intent with the default values. */ private void sendBugreportStarted(int max) { private void sendBugreportStarted(int max) throws Exception { Intent intent = new Intent(INTENT_BUGREPORT_STARTED); intent.putExtra(EXTRA_PID, PID); intent.putExtra(EXTRA_NAME, NAME); Loading Loading @@ -377,15 +401,29 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } /** * Asserts the proper ACTION_SEND_MULTIPLE intent was sent. * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent. */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent) throws IOException { assertActionSendMultiple(extras, ZIP_FILE, null, bugreportContent, screenshotContent); assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, null, ZIP_FILE, null, 0); } private void assertActionSendMultiple(Bundle extras, String subject, String description, String bugreportContent, String screenshotContent) throws IOException { /** * 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 pid emulated dumpstate pid * @param name bugreport name as provided by the user * @param title bugreport name as provided by the user (or received by dumpstate) * @param description bugreport description as provided by the user * @param numberScreenshots expected number of screenshots taken by Shell. */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent, int pid, String name, String title, String description, int numberScreenshots) throws IOException { String body = extras.getString(Intent.EXTRA_TEXT); assertContainsRegex("missing build info", SystemProperties.get("ro.build.description"), body); Loading @@ -395,31 +433,61 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertContainsRegex("missing description", description, body); } assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT)); assertEquals("wrong subject", title, extras.getString(Intent.EXTRA_SUBJECT)); List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM); int expectedSize = screenshotContent != null ? 2 : 1; 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", expectedSize, attachments.size()); // Need to interact through all attachments, since order is not guaranteed. Uri zipUri = null, screenshotUri = null; 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")) { screenshotUri = attachment; screenshotUris.add(attachment); } } assertNotNull("did not get .zip attachment", zipUri); assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT); // 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", screenshotUri); assertContent(screenshotUri, SCREENSHOT_CONTENT); assertNotNull("did not get .png attachment for external screenshot", externalScreenshotUri); assertContent(externalScreenshotUri, SCREENSHOT_CONTENT); } else { assertNull("should not have .png attachment", screenshotUri); 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 = name != null ? 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 { Loading Loading @@ -505,6 +573,47 @@ public class BugreportReceiverTest extends InstrumentationTestCase { return path; } /** * Gets the notification button used to take a screenshot. */ private UiObject getScreenshotButton() { openProgressNotification(); 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 = SCREENSHOT_DELAY_SECONDS + 2; 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. */ Loading