blob: a629aac33d250a34f6a321229ad643a138c8ad0e [file] [log] [blame]
Felipe Lemee53e85f2015-11-17 17:37:53 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.shell;
18
19import static android.test.MoreAsserts.assertContainsRegex;
20import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
Felipe Lemeb9238b32015-11-24 17:31:47 -080021import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
Felipe Leme85ae3cf2016-02-24 15:36:50 -080022import static com.android.shell.BugreportProgressService.EXTRA_ID;
Felipe Leme69c02922015-11-24 17:48:05 -080023import static com.android.shell.BugreportProgressService.EXTRA_MAX;
24import static com.android.shell.BugreportProgressService.EXTRA_NAME;
25import static com.android.shell.BugreportProgressService.EXTRA_PID;
Felipe Lemeb9238b32015-11-24 17:31:47 -080026import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
Felipe Leme69c02922015-11-24 17:48:05 -080027import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
28import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
Felipe Lemed1e0f122015-12-18 16:12:41 -080029import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
Felipe Lemee53e85f2015-11-17 17:37:53 -080030
31import java.io.BufferedOutputStream;
32import java.io.BufferedWriter;
33import java.io.ByteArrayOutputStream;
Felipe Lemea0bf0332015-12-11 09:35:03 -080034import java.io.File;
Felipe Lemee53e85f2015-11-17 17:37:53 -080035import java.io.FileOutputStream;
36import java.io.IOException;
37import java.io.InputStream;
38import java.io.OutputStreamWriter;
39import java.io.Writer;
Felipe Lemee86b63b2016-02-08 09:39:50 -080040import java.text.NumberFormat;
Felipe Lemed1e0f122015-12-18 16:12:41 -080041import java.util.ArrayList;
Felipe Lemee53e85f2015-11-17 17:37:53 -080042import java.util.List;
Felipe Lemed1e0f122015-12-18 16:12:41 -080043import java.util.SortedSet;
44import java.util.TreeSet;
Felipe Lemee53e85f2015-11-17 17:37:53 -080045import java.util.zip.ZipEntry;
46import java.util.zip.ZipInputStream;
47import java.util.zip.ZipOutputStream;
48
49import libcore.io.Streams;
Felipe Lemeba477932015-12-09 11:04:59 -080050import android.app.ActivityManager;
51import android.app.ActivityManager.RunningServiceInfo;
Felipe Lemee53e85f2015-11-17 17:37:53 -080052import android.app.Instrumentation;
53import android.app.NotificationManager;
54import android.content.Context;
Felipe Lemea0bf0332015-12-11 09:35:03 -080055import android.content.ContextWrapper;
Felipe Lemee53e85f2015-11-17 17:37:53 -080056import android.content.Intent;
57import android.net.Uri;
58import android.os.Bundle;
59import android.os.SystemProperties;
60import android.service.notification.StatusBarNotification;
61import android.support.test.uiautomator.UiDevice;
Felipe Leme6bbb6b92015-12-07 17:43:55 -080062import android.support.test.uiautomator.UiObject;
Felipe Lemee86b63b2016-02-08 09:39:50 -080063import android.support.test.uiautomator.UiObjectNotFoundException;
Felipe Leme26288782016-02-25 12:10:43 -080064import android.support.test.uiautomator.UiSelector;
Felipe Lemee53e85f2015-11-17 17:37:53 -080065import android.test.InstrumentationTestCase;
Felipe Leme2bfa0852015-12-10 12:43:31 -080066import android.test.suitebuilder.annotation.LargeTest;
Felipe Leme4967f732016-01-06 11:38:53 -080067import android.text.TextUtils;
Felipe Lemed1e0f122015-12-18 16:12:41 -080068import android.text.format.DateUtils;
Felipe Lemee53e85f2015-11-17 17:37:53 -080069import android.util.Log;
70
71import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
Felipe Lemec4f646772016-01-12 18:12:09 -080072import com.android.shell.BugreportProgressService;
Felipe Lemee53e85f2015-11-17 17:37:53 -080073
74/**
75 * Integration tests for {@link BugreportReceiver}.
76 * <p>
77 * These tests don't mock any component and rely on external UI components (like the notification
78 * bar and activity chooser), which can make them unreliable and slow.
79 * <p>
80 * The general workflow is:
81 * <ul>
82 * <li>creates the bug report files
83 * <li>generates the BUGREPORT_FINISHED intent
84 * <li>emulate user actions to share the intent with a custom activity
85 * <li>asserts the extras received by the custom activity
86 * </ul>
87 * <p>
Felipe Leme6bbb6b92015-12-07 17:43:55 -080088 * <strong>NOTE</strong>: these tests only work if the device is unlocked.
Felipe Lemee53e85f2015-11-17 17:37:53 -080089 */
Felipe Leme2bfa0852015-12-10 12:43:31 -080090@LargeTest
Felipe Lemee53e85f2015-11-17 17:37:53 -080091public class BugreportReceiverTest extends InstrumentationTestCase {
Felipe Lemee53e85f2015-11-17 17:37:53 -080092 private static final String TAG = "BugreportReceiverTest";
93
94 // Timeout for UI operations, in milliseconds.
Felipe Leme46d47912015-12-09 13:03:09 -080095 private static final int TIMEOUT = (int) BugreportProgressService.POLLING_FREQUENCY * 4;
Felipe Lemee53e85f2015-11-17 17:37:53 -080096
Felipe Lemec4f646772016-01-12 18:12:09 -080097 // Timeout for when waiting for a screenshot to finish.
98 private static final int SAFE_SCREENSHOT_DELAY = SCREENSHOT_DELAY_SECONDS + 10;
99
Felipe Lemea0bf0332015-12-11 09:35:03 -0800100 private static final String BUGREPORTS_DIR = "bugreports";
Felipe Lemee53e85f2015-11-17 17:37:53 -0800101 private static final String BUGREPORT_FILE = "test_bugreport.txt";
102 private static final String ZIP_FILE = "test_bugreport.zip";
Felipe Leme26288782016-02-25 12:10:43 -0800103 private static final String ZIP_FILE2 = "test_bugreport2.zip";
Felipe Lemea0bf0332015-12-11 09:35:03 -0800104 private static final String SCREENSHOT_FILE = "test_screenshot.png";
Felipe Lemee53e85f2015-11-17 17:37:53 -0800105
106 private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n";
107 private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n";
108
Felipe Leme93702ab2015-12-11 13:06:45 -0800109 private static final int PID = 42;
Felipe Leme26288782016-02-25 12:10:43 -0800110 private static final int PID2 = 24;
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800111 private static final int ID = 108;
Felipe Leme26288782016-02-25 12:10:43 -0800112 private static final int ID2 = 801;
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800113 private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress";
114 private static final String MAX_PROPERTY = "dumpstate." + PID + ".max";
115 private static final String NAME_PROPERTY = "dumpstate." + PID + ".name";
Felipe Leme93702ab2015-12-11 13:06:45 -0800116 private static final String NAME = "BUG, Y U NO REPORT?";
Felipe Leme26288782016-02-25 12:10:43 -0800117 private static final String NAME2 = "A bugreport's life";
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800118 private static final String NEW_NAME = "Bug_Forrest_Bug";
Felipe Leme26288782016-02-25 12:10:43 -0800119 private static final String NEW_NAME2 = "BugsyReportsy";
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800120 private static final String TITLE = "Wimbugdom Champion 2015";
Felipe Leme26288782016-02-25 12:10:43 -0800121 private static final String TITLE2 = "Master of the Universe";
122 private static final String DESCRIPTION = "One's description...";
123 private static final String DESCRIPTION2 = "...is another's treasure.";
Felipe Leme4967f732016-01-06 11:38:53 -0800124
125 private static final String NO_DESCRIPTION = null;
126 private static final String NO_NAME = null;
127 private static final String NO_SCREENSHOT = null;
128 private static final String NO_TITLE = null;
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800129 private static final int NO_ID = 0;
Felipe Lemec8e2b602016-01-29 13:55:35 -0800130 private static final boolean RENAMED_SCREENSHOTS = true;
131 private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
Felipe Leme4967f732016-01-06 11:38:53 -0800132
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800133 private String mDescription;
Felipe Leme93702ab2015-12-11 13:06:45 -0800134
Felipe Lemea0bf0332015-12-11 09:35:03 -0800135 private String mPlainTextPath;
136 private String mZipPath;
Felipe Leme26288782016-02-25 12:10:43 -0800137 private String mZipPath2;
Felipe Lemea0bf0332015-12-11 09:35:03 -0800138 private String mScreenshotPath;
139
Felipe Lemee53e85f2015-11-17 17:37:53 -0800140 private Context mContext;
141 private UiBot mUiBot;
142 private CustomActionSendMultipleListener mListener;
143
144 @Override
145 protected void setUp() throws Exception {
Felipe Lemec4f646772016-01-12 18:12:09 -0800146 Log.i(TAG, "#### setup() on " + getName());
Felipe Lemee53e85f2015-11-17 17:37:53 -0800147 Instrumentation instrumentation = getInstrumentation();
148 mContext = instrumentation.getTargetContext();
149 mUiBot = new UiBot(UiDevice.getInstance(instrumentation), TIMEOUT);
150 mListener = ActionSendMultipleConsumerActivity.getListener(mContext);
Felipe Leme93702ab2015-12-11 13:06:45 -0800151
152 cancelExistingNotifications();
153
Felipe Lemea0bf0332015-12-11 09:35:03 -0800154 mPlainTextPath = getPath(BUGREPORT_FILE);
155 mZipPath = getPath(ZIP_FILE);
Felipe Leme26288782016-02-25 12:10:43 -0800156 mZipPath2 = getPath(ZIP_FILE2);
Felipe Lemea0bf0332015-12-11 09:35:03 -0800157 mScreenshotPath = getPath(SCREENSHOT_FILE);
Felipe Leme93702ab2015-12-11 13:06:45 -0800158 createTextFile(mPlainTextPath, BUGREPORT_CONTENT);
159 createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
160 createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
Felipe Leme26288782016-02-25 12:10:43 -0800161 createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT);
Felipe Leme93702ab2015-12-11 13:06:45 -0800162
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800163 // Creates a multi-line description.
164 StringBuilder sb = new StringBuilder();
165 for (int i = 1; i <= 20; i++) {
166 sb.append("All work and no play makes Shell a dull app!\n");
167 }
168 mDescription = sb.toString();
169
Felipe Leme6bbb6b92015-12-07 17:43:55 -0800170 BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800171 }
172
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800173 public void testProgress() throws Exception {
Felipe Leme93702ab2015-12-11 13:06:45 -0800174 resetProperties();
175 sendBugreportStarted(1000);
Felipe Leme22881292016-01-06 09:57:23 -0800176 waitForScreenshotButtonEnabled(true);
Felipe Leme69c02922015-11-24 17:48:05 -0800177
Felipe Lemee86b63b2016-02-08 09:39:50 -0800178 final NumberFormat nf = NumberFormat.getPercentInstance();
179 nf.setMinimumFractionDigits(2);
180 nf.setMaximumFractionDigits(2);
181
182 assertProgressNotification(NAME, nf.format(0));
Felipe Leme69c02922015-11-24 17:48:05 -0800183
Felipe Leme93702ab2015-12-11 13:06:45 -0800184 SystemProperties.set(PROGRESS_PROPERTY, "108");
Felipe Lemee86b63b2016-02-08 09:39:50 -0800185 assertProgressNotification(NAME, nf.format(0.108));
Felipe Leme69c02922015-11-24 17:48:05 -0800186
Felipe Leme93702ab2015-12-11 13:06:45 -0800187 SystemProperties.set(PROGRESS_PROPERTY, "500");
Felipe Lemee86b63b2016-02-08 09:39:50 -0800188 assertProgressNotification(NAME, nf.format(0.50));
Felipe Leme69c02922015-11-24 17:48:05 -0800189
Felipe Leme93702ab2015-12-11 13:06:45 -0800190 SystemProperties.set(MAX_PROPERTY, "2000");
Felipe Lemee86b63b2016-02-08 09:39:50 -0800191 assertProgressNotification(NAME, nf.format(0.25));
Felipe Leme69c02922015-11-24 17:48:05 -0800192
Felipe Leme93702ab2015-12-11 13:06:45 -0800193 Bundle extras =
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800194 sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath);
195 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800196 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
Felipe Lemed1e0f122015-12-18 16:12:41 -0800197
198 assertServiceNotRunning();
199 }
200
Felipe Lemedb313632016-02-25 17:06:58 -0800201 public void testProgress_cancel() throws Exception {
202 resetProperties();
203 sendBugreportStarted(1000);
204 waitForScreenshotButtonEnabled(true);
205
206 final NumberFormat nf = NumberFormat.getPercentInstance();
207 nf.setMinimumFractionDigits(2);
208 nf.setMaximumFractionDigits(2);
209
210 assertProgressNotification(NAME, nf.format(0));
211
212 openProgressNotification(ID);
213 UiObject cancelButton = mUiBot.getVisibleObject(mContext.getString(
214 com.android.internal.R.string.cancel).toUpperCase());
215 mUiBot.click(cancelButton, "cancel_button");
216
217 waitForService(false);
218 }
219
Felipe Lemed1e0f122015-12-18 16:12:41 -0800220 public void testProgress_takeExtraScreenshot() throws Exception {
Felipe Lemec4f646772016-01-12 18:12:09 -0800221 takeExtraScreenshotTest(false);
222 }
223
224 public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
225 takeExtraScreenshotTest(true);
226 }
227
228 private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
Felipe Lemed1e0f122015-12-18 16:12:41 -0800229 resetProperties();
230 sendBugreportStarted(1000);
231
232 waitForScreenshotButtonEnabled(true);
233 takeScreenshot();
234 assertScreenshotButtonEnabled(false);
235 waitForScreenshotButtonEnabled(true);
236
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800237 sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
Felipe Lemec4f646772016-01-12 18:12:09 -0800238
239 if (serviceDies) {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800240 waitShareNotification(ID);
Felipe Lemec4f646772016-01-12 18:12:09 -0800241 killService();
242 }
243
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800244 Bundle extras = acceptBugreportAndGetSharedIntent(ID);
245 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800246 NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS);
Felipe Leme69c02922015-11-24 17:48:05 -0800247
Felipe Leme93702ab2015-12-11 13:06:45 -0800248 assertServiceNotRunning();
Felipe Leme69c02922015-11-24 17:48:05 -0800249 }
250
Felipe Lemec4f646772016-01-12 18:12:09 -0800251 public void testScreenshotFinishesAfterBugreport() throws Exception {
252 screenshotFinishesAfterBugreportTest(false);
253 }
254
255 public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
256 screenshotFinishesAfterBugreportTest(true);
257 }
258
259 private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
260 resetProperties();
261
262 sendBugreportStarted(1000);
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800263 sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT);
264 waitShareNotification(ID);
Felipe Lemec4f646772016-01-12 18:12:09 -0800265
266 // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
267 Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
268
269 if (serviceDies) {
270 killService();
271 }
272
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800273 Bundle extras = acceptBugreportAndGetSharedIntent(ID);
274 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800275 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
Felipe Lemec4f646772016-01-12 18:12:09 -0800276
277 assertServiceNotRunning();
278 }
279
Felipe Leme4967f732016-01-06 11:38:53 -0800280 public void testProgress_changeDetailsInvalidInput() throws Exception {
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800281 resetProperties();
282 sendBugreportStarted(1000);
Felipe Leme22881292016-01-06 09:57:23 -0800283 waitForScreenshotButtonEnabled(true);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800284
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800285 DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800286
287 // Check initial name.
Felipe Leme26288782016-02-25 12:10:43 -0800288 detailsUi.assertName(NAME);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800289
290 // Change name - it should have changed system property once focus is changed.
291 detailsUi.nameField.setText(NEW_NAME);
292 detailsUi.focusAwayFromName();
293 assertPropertyValue(NAME_PROPERTY, NEW_NAME);
294
295 // Cancel the dialog to make sure property was restored.
296 detailsUi.clickCancel();
297 assertPropertyValue(NAME_PROPERTY, NAME);
298
299 // Now try to set an invalid name.
300 detailsUi.reOpen();
301 detailsUi.nameField.setText("/etc/passwd");
302 detailsUi.clickOk();
303 assertPropertyValue(NAME_PROPERTY, "_etc_passwd");
304
305 // Finally, make the real changes.
306 detailsUi.reOpen();
307 detailsUi.nameField.setText(NEW_NAME);
308 detailsUi.titleField.setText(TITLE);
309 detailsUi.descField.setText(mDescription);
310
311 detailsUi.clickOk();
312
313 assertPropertyValue(NAME_PROPERTY, NEW_NAME);
314 assertProgressNotification(NEW_NAME, "0.00%");
315
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800316 Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath,
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800317 mScreenshotPath);
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800318 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800319 NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
Felipe Leme4967f732016-01-06 11:38:53 -0800320
321 assertServiceNotRunning();
322 }
323
324 public void testProgress_changeDetailsPlainBugreport() throws Exception {
325 changeDetailsTest(true);
326 }
327
328 public void testProgress_changeDetailsZippedBugreport() throws Exception {
329 changeDetailsTest(false);
330 }
331
332 public void changeDetailsTest(boolean plainText) throws Exception {
Felipe Leme4967f732016-01-06 11:38:53 -0800333 resetProperties();
334 sendBugreportStarted(1000);
335 waitForScreenshotButtonEnabled(true);
336
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800337 DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
Felipe Leme4967f732016-01-06 11:38:53 -0800338
339 // Check initial name.
Felipe Leme26288782016-02-25 12:10:43 -0800340 detailsUi.assertName(NAME);
Felipe Leme4967f732016-01-06 11:38:53 -0800341
342 // Change fields.
343 detailsUi.reOpen();
344 detailsUi.nameField.setText(NEW_NAME);
345 detailsUi.titleField.setText(TITLE);
346 detailsUi.descField.setText(mDescription);
347
348 detailsUi.clickOk();
349
350 assertPropertyValue(NAME_PROPERTY, NEW_NAME);
351 assertProgressNotification(NEW_NAME, "0.00%");
352
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800353 Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID,
Felipe Leme4967f732016-01-06 11:38:53 -0800354 plainText? mPlainTextPath : mZipPath, mScreenshotPath);
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800355 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800356 NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
357
358 assertServiceNotRunning();
359 }
360
Felipe Lemedb313632016-02-25 17:06:58 -0800361 public void testProgress_changeJustDetailsTouchingDetails() throws Exception {
362 changeJustDetailsTest(true);
363 }
364
365 public void testProgress_changeJustDetailsTouchingNotification() throws Exception {
366 changeJustDetailsTest(false);
367 }
368
369 private void changeJustDetailsTest(boolean touchDetails) throws Exception {
Felipe Lemec8e2b602016-01-29 13:55:35 -0800370 resetProperties();
371 sendBugreportStarted(1000);
372 waitForScreenshotButtonEnabled(true);
373
Felipe Lemedb313632016-02-25 17:06:58 -0800374 DetailsUi detailsUi = new DetailsUi(mUiBot, ID, touchDetails);
Felipe Lemec8e2b602016-01-29 13:55:35 -0800375
376 detailsUi.nameField.setText("");
377 detailsUi.titleField.setText("");
378 detailsUi.descField.setText(mDescription);
379 detailsUi.clickOk();
380
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800381 Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
382 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800383 NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800384
385 assertServiceNotRunning();
386 }
387
Felipe Leme26288782016-02-25 12:10:43 -0800388 /*
389 * TODO: this test can be flanky because it relies in the order the notifications are displayed,
390 * since mUiBot gets the first notification.
391 * Ideally, openProgressNotification() should return the whole notification, so DetailsUi
392 * could use it and find children instead, but unfortunately the notification object hierarchy
393 * is too complex and getting it from the notification text object would be to fragile
394 * (for instance, it could require navigating many parents up in the hierarchy).
395 */
396 public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception {
397 resetProperties();
398 sendBugreportStarted(ID, PID, NAME, 1000);
399 waitForScreenshotButtonEnabled(true);
400
401 DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
402 detailsUi.assertName(NAME);
Felipe Lemebbd91e52016-02-26 16:48:22 -0800403 detailsUi.assertTitle("");
404 detailsUi.assertDescription("");
Felipe Leme26288782016-02-25 12:10:43 -0800405 detailsUi.nameField.setText(NEW_NAME);
406 detailsUi.titleField.setText(TITLE);
407 detailsUi.descField.setText(DESCRIPTION);
408 detailsUi.clickOk();
409
410 sendBugreportStarted(ID2, PID2, NAME2, 1000);
411
412 Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
413 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
414 NEW_NAME, TITLE, DESCRIPTION, 1, RENAMED_SCREENSHOTS);
415
416 detailsUi = new DetailsUi(mUiBot, ID2);
417 detailsUi.assertName(NAME2);
Felipe Lemebbd91e52016-02-26 16:48:22 -0800418 detailsUi.assertTitle("");
419 detailsUi.assertDescription("");
Felipe Leme26288782016-02-25 12:10:43 -0800420 detailsUi.nameField.setText(NEW_NAME2);
421 detailsUi.titleField.setText(TITLE2);
422 detailsUi.descField.setText(DESCRIPTION2);
423 detailsUi.clickOk();
424
425 // Must use a different zip file otherwise it will fail because zip already contains
426 // title.txt and description.txt entries.
427 extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT);
428 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2,
429 NEW_NAME2, TITLE2, DESCRIPTION2, 1, RENAMED_SCREENSHOTS);
430
431 assertServiceNotRunning();
432 }
433
Felipe Leme22881292016-01-06 09:57:23 -0800434 /**
435 * Tests the scenario where the initial screenshot and dumpstate are finished while the user
436 * is changing the info in the details screen.
437 */
438 public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
439 bugreportFinishedWhileChangingDetailsTest(false);
440 }
441
442 /**
443 * Tests the scenario where dumpstate is finished while the user is changing the info in the
444 * details screen, but the initial screenshot finishes afterwards.
445 */
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800446 public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
Felipe Leme22881292016-01-06 09:57:23 -0800447 bugreportFinishedWhileChangingDetailsTest(true);
448 }
449
450 private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800451 resetProperties();
452 sendBugreportStarted(1000);
Felipe Leme22881292016-01-06 09:57:23 -0800453 if (waitScreenshot) {
454 waitForScreenshotButtonEnabled(true);
455 }
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800456
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800457 DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800458
459 // Finish the bugreport while user's still typing the name.
460 detailsUi.nameField.setText(NEW_NAME);
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800461 sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800462
Felipe Leme22881292016-01-06 09:57:23 -0800463 // Wait until the share notification is received...
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800464 waitShareNotification(ID);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800465 // ...then close notification bar.
466 mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
467
468 // Make sure UI was updated properly.
469 assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled());
470 assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString());
471
472 // Finish changing other fields.
473 detailsUi.titleField.setText(TITLE);
474 detailsUi.descField.setText(mDescription);
475 detailsUi.clickOk();
476
477 // Finally, share bugreport.
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800478 Bundle extras = acceptBugreportAndGetSharedIntent(ID);
479 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800480 NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800481
482 assertServiceNotRunning();
483 }
484
Felipe Leme6bbb6b92015-12-07 17:43:55 -0800485 public void testBugreportFinished_withWarning() throws Exception {
486 // Explicitly shows the warning.
487 BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
488
489 // Send notification and click on share.
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800490 sendBugreportFinished(NO_ID, mPlainTextPath, null);
491 acceptBugreport(NO_ID);
Felipe Leme6bbb6b92015-12-07 17:43:55 -0800492
493 // Handle the warning
494 mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
495 // TODO: get ok and showMessageAgain from the dialog reference above
496 UiObject showMessageAgain =
497 mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
498 mUiBot.click(showMessageAgain, "show-message-again");
499 UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
500 mUiBot.click(ok, "ok");
501
502 // Share the bugreport.
503 mUiBot.chooseActivity(UI_NAME);
504 Bundle extras = mListener.getExtras();
Felipe Leme4967f732016-01-06 11:38:53 -0800505 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
Felipe Leme6bbb6b92015-12-07 17:43:55 -0800506
507 // Make sure it's hidden now.
508 int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
509 assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
510 }
511
Felipe Lemec4f646772016-01-12 18:12:09 -0800512 public void testShareBugreportAfterServiceDies() throws Exception {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800513 sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
Felipe Lemec4f646772016-01-12 18:12:09 -0800514 killService();
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800515 Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
Felipe Lemec4f646772016-01-12 18:12:09 -0800516 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
517 }
518
Felipe Lemee53e85f2015-11-17 17:37:53 -0800519 public void testBugreportFinished_plainBugreportAndScreenshot() throws Exception {
Felipe Leme93702ab2015-12-11 13:06:45 -0800520 Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, mScreenshotPath);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800521 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
522 }
523
524 public void testBugreportFinished_zippedBugreportAndScreenshot() throws Exception {
Felipe Leme93702ab2015-12-11 13:06:45 -0800525 Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, mScreenshotPath);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800526 assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
527 }
528
529 public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
Felipe Leme4967f732016-01-06 11:38:53 -0800530 Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT);
531 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800532 }
533
534 public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
Felipe Leme4967f732016-01-06 11:38:53 -0800535 Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT);
536 assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800537 }
538
539 private void cancelExistingNotifications() {
540 NotificationManager nm = NotificationManager.from(mContext);
541 for (StatusBarNotification notification : nm.getActiveNotifications()) {
542 int id = notification.getId();
543 Log.i(TAG, "Canceling existing notification (id=" + id + ")");
544 nm.cancel(id);
545 }
546 }
547
Felipe Leme69c02922015-11-24 17:48:05 -0800548 private void assertProgressNotification(String name, String percent) {
Felipe Lemed1e0f122015-12-18 16:12:41 -0800549 // TODO: it currently looks for 3 distinct objects, without taking advantage of their
Felipe Leme69c02922015-11-24 17:48:05 -0800550 // relationship.
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800551 openProgressNotification(ID);
Felipe Leme69c02922015-11-24 17:48:05 -0800552 Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
553 mUiBot.getObject(name);
554 mUiBot.getObject(percent);
555 }
556
Felipe Lemedb313632016-02-25 17:06:58 -0800557 private UiObject openProgressNotification(int id) {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800558 String title = mContext.getString(R.string.bugreport_in_progress_title, id);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800559 Log.v(TAG, "Looking for progress notification title: '" + title + "'");
Felipe Lemedb313632016-02-25 17:06:58 -0800560 return mUiBot.getNotification(title);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800561 }
562
Felipe Leme93702ab2015-12-11 13:06:45 -0800563 void resetProperties() {
564 // TODO: call method to remove property instead
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800565 SystemProperties.set(PROGRESS_PROPERTY, "Reset");
566 SystemProperties.set(MAX_PROPERTY, "Reset");
567 SystemProperties.set(NAME_PROPERTY, "Reset");
Felipe Leme93702ab2015-12-11 13:06:45 -0800568 }
569
570 /**
571 * Sends a "bugreport started" intent with the default values.
572 */
Felipe Lemed1e0f122015-12-18 16:12:41 -0800573 private void sendBugreportStarted(int max) throws Exception {
Felipe Leme26288782016-02-25 12:10:43 -0800574 sendBugreportStarted(ID, PID, NAME, max);
575 }
576
577 private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception {
Felipe Leme93702ab2015-12-11 13:06:45 -0800578 Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
Felipe Lemeec175382016-01-26 18:17:15 -0800579 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Felipe Leme26288782016-02-25 12:10:43 -0800580 intent.putExtra(EXTRA_ID, id);
581 intent.putExtra(EXTRA_PID, pid);
582 intent.putExtra(EXTRA_NAME, name);
Felipe Leme93702ab2015-12-11 13:06:45 -0800583 intent.putExtra(EXTRA_MAX, max);
584 mContext.sendBroadcast(intent);
585 }
586
Felipe Lemee53e85f2015-11-17 17:37:53 -0800587 /**
588 * Sends a "bugreport finished" intent and waits for the result.
589 *
Felipe Leme93702ab2015-12-11 13:06:45 -0800590 * @return extras sent in the shared intent.
Felipe Lemee53e85f2015-11-17 17:37:53 -0800591 */
Felipe Leme93702ab2015-12-11 13:06:45 -0800592 private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath,
593 String screenshotPath) {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800594 return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath);
Felipe Leme69c02922015-11-24 17:48:05 -0800595 }
596
Felipe Leme93702ab2015-12-11 13:06:45 -0800597 /**
598 * Sends a "bugreport finished" intent and waits for the result.
599 *
600 * @return extras sent in the shared intent.
601 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800602 private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
Felipe Leme69c02922015-11-24 17:48:05 -0800603 String screenshotPath) {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800604 sendBugreportFinished(id, bugreportPath, screenshotPath);
605 return acceptBugreportAndGetSharedIntent(id);
Felipe Leme93702ab2015-12-11 13:06:45 -0800606 }
607
608 /**
609 * Accepts the notification to share the finished bugreport and waits for the result.
610 *
611 * @return extras sent in the shared intent.
612 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800613 private Bundle acceptBugreportAndGetSharedIntent(int id) {
614 acceptBugreport(id);
Felipe Leme93702ab2015-12-11 13:06:45 -0800615 mUiBot.chooseActivity(UI_NAME);
616 return mListener.getExtras();
617 }
618
619 /**
Felipe Lemec4f646772016-01-12 18:12:09 -0800620 * Waits for the notification to share the finished bugreport.
621 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800622 private void waitShareNotification(int id) {
623 mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, id));
Felipe Lemec4f646772016-01-12 18:12:09 -0800624 }
625
626 /**
Felipe Leme93702ab2015-12-11 13:06:45 -0800627 * Accepts the notification to share the finished bugreport.
628 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800629 private void acceptBugreport(int id) {
630 mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
Felipe Leme93702ab2015-12-11 13:06:45 -0800631 }
632
633 /**
634 * Sends a "bugreport finished" intent.
Felipe Leme93702ab2015-12-11 13:06:45 -0800635 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800636 private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) {
Felipe Leme69c02922015-11-24 17:48:05 -0800637 Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
Felipe Lemeec175382016-01-26 18:17:15 -0800638 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800639 if (id != NO_ID) {
640 intent.putExtra(EXTRA_ID, id);
Felipe Leme69c02922015-11-24 17:48:05 -0800641 }
Felipe Lemee53e85f2015-11-17 17:37:53 -0800642 if (bugreportPath != null) {
643 intent.putExtra(EXTRA_BUGREPORT, bugreportPath);
644 }
645 if (screenshotPath != null) {
646 intent.putExtra(EXTRA_SCREENSHOT, screenshotPath);
647 }
648
649 mContext.sendBroadcast(intent);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800650 }
651
652 /**
Felipe Lemed1e0f122015-12-18 16:12:41 -0800653 * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
Felipe Lemee53e85f2015-11-17 17:37:53 -0800654 */
655 private void assertActionSendMultiple(Bundle extras, String bugreportContent,
656 String screenshotContent) throws IOException {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800657 assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE,
Felipe Lemec8e2b602016-01-29 13:55:35 -0800658 NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800659 }
660
Felipe Lemed1e0f122015-12-18 16:12:41 -0800661 /**
662 * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
663 *
664 * @param extras extras received in the intent
665 * @param bugreportContent expected content in the bugreport file
666 * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800667 * @param id emulated dumpstate id
Felipe Lemed1e0f122015-12-18 16:12:41 -0800668 * @param pid emulated dumpstate pid
Felipe Leme4967f732016-01-06 11:38:53 -0800669 * @param name expected subject
670 * @param name bugreport name as provided by the user (or received by dumpstate)
671 * @param title bugreport name as provided by the user
Felipe Lemed1e0f122015-12-18 16:12:41 -0800672 * @param description bugreport description as provided by the user
673 * @param numberScreenshots expected number of screenshots taken by Shell.
Felipe Leme22881292016-01-06 09:57:23 -0800674 * @param renamedScreenshots whether the screenshots are expected to be renamed
Felipe Lemed1e0f122015-12-18 16:12:41 -0800675 */
676 private void assertActionSendMultiple(Bundle extras, String bugreportContent,
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800677 String screenshotContent, int id, int pid, String subject,
Felipe Leme4967f732016-01-06 11:38:53 -0800678 String name, String title, String description,
Felipe Leme22881292016-01-06 09:57:23 -0800679 int numberScreenshots, boolean renamedScreenshots) throws IOException {
Felipe Lemee53e85f2015-11-17 17:37:53 -0800680 String body = extras.getString(Intent.EXTRA_TEXT);
681 assertContainsRegex("missing build info",
682 SystemProperties.get("ro.build.description"), body);
683 assertContainsRegex("missing serial number",
684 SystemProperties.get("ro.serialno"), body);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800685 if (description != null) {
686 assertContainsRegex("missing description", description, body);
687 }
Felipe Lemee53e85f2015-11-17 17:37:53 -0800688
Felipe Leme4967f732016-01-06 11:38:53 -0800689 assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));
Felipe Lemee53e85f2015-11-17 17:37:53 -0800690
691 List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
Felipe Lemed1e0f122015-12-18 16:12:41 -0800692 int expectedNumberScreenshots = numberScreenshots;
693 if (screenshotContent != null) {
694 expectedNumberScreenshots ++; // Add screenshot received by dumpstate
695 }
696 int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
Felipe Lemec4f646772016-01-12 18:12:09 -0800697 assertEquals("wrong number of attachments (" + attachments + ")",
698 expectedSize, attachments.size());
Felipe Lemee53e85f2015-11-17 17:37:53 -0800699
700 // Need to interact through all attachments, since order is not guaranteed.
Felipe Lemed1e0f122015-12-18 16:12:41 -0800701 Uri zipUri = null;
702 List<Uri> screenshotUris = new ArrayList<>(expectedNumberScreenshots);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800703 for (Uri attachment : attachments) {
704 if (attachment.getPath().endsWith(".zip")) {
705 zipUri = attachment;
706 }
707 if (attachment.getPath().endsWith(".png")) {
Felipe Lemed1e0f122015-12-18 16:12:41 -0800708 screenshotUris.add(attachment);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800709 }
710 }
711 assertNotNull("did not get .zip attachment", zipUri);
712 assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT);
Felipe Leme4967f732016-01-06 11:38:53 -0800713 if (!TextUtils.isEmpty(title)) {
714 assertZipContent(zipUri, "title.txt", title);
715 }
716 if (!TextUtils.isEmpty(description)) {
717 assertZipContent(zipUri, "description.txt", description);
718 }
Felipe Lemee53e85f2015-11-17 17:37:53 -0800719
Felipe Lemed1e0f122015-12-18 16:12:41 -0800720 // URI of the screenshot taken by dumpstate.
721 Uri externalScreenshotUri = null;
722 SortedSet<String> internalScreenshotNames = new TreeSet<>();
723 for (Uri screenshotUri : screenshotUris) {
724 String screenshotName = screenshotUri.getLastPathSegment();
725 if (screenshotName.endsWith(SCREENSHOT_FILE)) {
726 externalScreenshotUri = screenshotUri;
727 } else {
728 internalScreenshotNames.add(screenshotName);
729 }
Felipe Lemee53e85f2015-11-17 17:37:53 -0800730 }
Felipe Lemed1e0f122015-12-18 16:12:41 -0800731 // Check external screenshot
732 if (screenshotContent != null) {
733 assertNotNull("did not get .png attachment for external screenshot",
734 externalScreenshotUri);
735 assertContent(externalScreenshotUri, SCREENSHOT_CONTENT);
736 } else {
737 assertNull("should not have .png attachment for external screenshot",
738 externalScreenshotUri);
739 }
740 // Check internal screenshots.
741 SortedSet<String> expectedNames = new TreeSet<>();
742 for (int i = 1 ; i <= numberScreenshots; i++) {
Felipe Leme22881292016-01-06 09:57:23 -0800743 String prefix = renamedScreenshots ? name : Integer.toString(pid);
Felipe Lemed1e0f122015-12-18 16:12:41 -0800744 String expectedName = "screenshot-" + prefix + "-" + i + ".png";
745 expectedNames.add(expectedName);
746 }
747 // Ideally we should use MoreAsserts, but the error message in case of failure is not
748 // really useful.
749 assertEquals("wrong names for internal screenshots",
750 expectedNames, internalScreenshotNames);
Felipe Lemee53e85f2015-11-17 17:37:53 -0800751 }
752
753 private void assertContent(Uri uri, String expectedContent) throws IOException {
754 Log.v(TAG, "assertContents(uri=" + uri);
755 try (InputStream is = mContext.getContentResolver().openInputStream(uri)) {
756 String actualContent = new String(Streams.readFully(is));
757 assertEquals("wrong content for '" + uri + "'", expectedContent, actualContent);
758 }
759 }
760
761 private void assertZipContent(Uri uri, String entryName, String expectedContent)
762 throws IOException, IOException {
763 Log.v(TAG, "assertZipEntry(uri=" + uri + ", entryName=" + entryName);
764 try (ZipInputStream zis = new ZipInputStream(mContext.getContentResolver().openInputStream(
765 uri))) {
766 ZipEntry entry;
767 while ((entry = zis.getNextEntry()) != null) {
768 Log.v(TAG, "Zip entry: " + entry.getName());
769 if (entry.getName().equals(entryName)) {
770 ByteArrayOutputStream bos = new ByteArrayOutputStream();
771 Streams.copy(zis, bos);
772 String actualContent = new String(bos.toByteArray(), "UTF-8");
773 bos.close();
774 assertEquals("wrong content for zip entry'" + entryName + "' on '" + uri + "'",
775 expectedContent, actualContent);
776 return;
777 }
778 }
779 }
780 fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
781 }
782
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800783 private void assertPropertyValue(String key, String expectedValue) {
784 String actualValue = SystemProperties.get(key);
785 assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue);
786 }
787
Felipe Leme93702ab2015-12-11 13:06:45 -0800788 private void assertServiceNotRunning() {
789 String service = BugreportProgressService.class.getName();
790 assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
791 }
792
Felipe Lemec4f646772016-01-12 18:12:09 -0800793 private void killService() {
794 waitForService(true);
795 Log.v(TAG, "Stopping service");
796 boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
797 Log.d(TAG, "stopService returned " + stopped);
798 waitForService(false);
799 assertServiceNotRunning(); // Sanity check.
800 }
801
Felipe Lemeba477932015-12-09 11:04:59 -0800802 private boolean isServiceRunning(String name) {
803 ActivityManager manager = (ActivityManager) mContext
804 .getSystemService(Context.ACTIVITY_SERVICE);
805 for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
806 if (service.service.getClassName().equals(name)) {
807 return true;
808 }
809 }
810 return false;
811 }
812
Felipe Lemec4f646772016-01-12 18:12:09 -0800813 private void waitForService(boolean expectRunning) {
814 String service = BugreportProgressService.class.getName();
815 boolean actualRunning;
816 for (int i = 1; i <= 5; i++) {
817 actualRunning = isServiceRunning(service);
818 Log.d(TAG, "Attempt " + i + " to check status of service '"
819 + service + "': expected=" + expectRunning + ", actual= " + actualRunning);
820 if (actualRunning == expectRunning) {
821 return;
822 }
823 try {
824 Thread.sleep(DateUtils.SECOND_IN_MILLIS);
825 } catch (InterruptedException e) {
826 Log.w(TAG, "thread interrupted");
827 Thread.currentThread().interrupt();
828 }
829 }
830 if (!expectRunning) {
831 // Typically happens when service is waiting for a screenshot to finish.
832 Log.w(TAG, "Service didn't stop; try to kill it again");
833 killService();
834 return;
835 }
836
837 fail("Service status didn't change to " + expectRunning);
838 }
839
Felipe Leme26288782016-02-25 12:10:43 -0800840 private void createTextFile(String path, String content) throws IOException {
Felipe Lemee53e85f2015-11-17 17:37:53 -0800841 Log.v(TAG, "createFile(" + path + ")");
842 try (Writer writer = new BufferedWriter(new OutputStreamWriter(
843 new FileOutputStream(path)))) {
844 writer.write(content);
845 }
846 }
847
848 private void createZipFile(String path, String entryName, String content) throws IOException {
849 Log.v(TAG, "createZipFile(" + path + ", " + entryName + ")");
850 try (ZipOutputStream zos = new ZipOutputStream(
851 new BufferedOutputStream(new FileOutputStream(path)))) {
852 ZipEntry entry = new ZipEntry(entryName);
853 zos.putNextEntry(entry);
854 byte[] data = content.getBytes();
855 zos.write(data, 0, data.length);
856 zos.closeEntry();
857 }
858 }
Felipe Lemea0bf0332015-12-11 09:35:03 -0800859
860 private String getPath(String file) {
861 File rootDir = new ContextWrapper(mContext).getFilesDir();
862 File dir = new File(rootDir, BUGREPORTS_DIR);
Felipe Lemee2b4f492015-12-11 18:19:26 -0800863 if (!dir.exists()) {
864 Log.i(TAG, "Creating directory " + dir);
865 assertTrue("Could not create directory " + dir, dir.mkdir());
866 }
Felipe Lemea0bf0332015-12-11 09:35:03 -0800867 String path = new File(dir, file).getAbsolutePath();
868 Log.v(TAG, "Path for '" + file + "': " + path);
869 return path;
870 }
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800871
872 /**
Felipe Lemed1e0f122015-12-18 16:12:41 -0800873 * Gets the notification button used to take a screenshot.
874 */
875 private UiObject getScreenshotButton() {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800876 openProgressNotification(ID);
Felipe Lemed1e0f122015-12-18 16:12:41 -0800877 return mUiBot.getVisibleObject(
878 mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
879 }
880
881 /**
882 * Takes a screenshot using the system notification.
883 */
884 private void takeScreenshot() throws Exception {
885 UiObject screenshotButton = getScreenshotButton();
886 mUiBot.click(screenshotButton, "screenshot_button");
887 }
888
889 private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
890 UiObject screenshotButton = getScreenshotButton();
Felipe Lemec4f646772016-01-12 18:12:09 -0800891 int maxAttempts = SAFE_SCREENSHOT_DELAY;
Felipe Lemed1e0f122015-12-18 16:12:41 -0800892 int i = 0;
893 do {
894 boolean enabled = screenshotButton.isEnabled();
895 if (enabled == expectedEnabled) {
896 return screenshotButton;
897 }
898 i++;
899 Log.v(TAG, "Sleeping for 1 second while waiting for screenshot.enable to be "
900 + expectedEnabled + " (attempt " + i + ")");
901 Thread.sleep(DateUtils.SECOND_IN_MILLIS);
902 } while (i <= maxAttempts);
903 fail("screenshot.enable didn't change to " + expectedEnabled + " in " + maxAttempts + "s");
904 return screenshotButton;
905 }
906
907 private void assertScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
908 UiObject screenshotButton = getScreenshotButton();
909 assertEquals("wrong state for screenshot button ", expectedEnabled,
910 screenshotButton.isEnabled());
911 }
912
913 /**
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800914 * Helper class containing the UiObjects present in the bugreport info dialog.
915 */
916 private final class DetailsUi {
917
918 final UiObject detailsButton;
919 final UiObject nameField;
920 final UiObject titleField;
921 final UiObject descField;
922 final UiObject okButton;
923 final UiObject cancelButton;
924
925 /**
926 * Gets the UI objects by opening the progress notification and clicking DETAILS.
927 */
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800928 DetailsUi(UiBot uiBot, int id) throws UiObjectNotFoundException {
Felipe Lemedb313632016-02-25 17:06:58 -0800929 this(uiBot, id, true);
930 }
931
932 /**
933 * Gets the UI objects by opening the progress notification and clicking on DETAILS or in
934 * the notification itself.
935 */
936 DetailsUi(UiBot uiBot, int id, boolean clickDetails) throws UiObjectNotFoundException {
937 UiObject notification = openProgressNotification(id);
Felipe Leme26288782016-02-25 12:10:43 -0800938 detailsButton = mUiBot.getVisibleObject(mContext.getString(
939 R.string.bugreport_info_action).toUpperCase());
940
Felipe Lemedb313632016-02-25 17:06:58 -0800941 if (clickDetails) {
942 mUiBot.click(detailsButton, "details_button");
943 } else {
944 mUiBot.click(notification, "notification");
945 }
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800946 // TODO: unhardcode resource ids
Felipe Lemee86b63b2016-02-08 09:39:50 -0800947 UiObject dialogTitle = mUiBot.getVisibleObjectById("android:id/alertTitle");
948 assertEquals("Wrong title", mContext.getString(R.string.bugreport_info_dialog_title,
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800949 id), dialogTitle.getText().toString());
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800950 nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
951 titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
952 descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
953 okButton = mUiBot.getObjectById("android:id/button1");
954 cancelButton = mUiBot.getObjectById("android:id/button2");
955 }
956
Felipe Leme26288782016-02-25 12:10:43 -0800957 private void assertField(String name, UiObject field, String expected) {
958 try {
959 String actual = field.getText().toString();
960 assertEquals("Wrong value on field '" + name + "'", expected, actual);
961 } catch (UiObjectNotFoundException e) {
962 // Should not happen...
963 throw new IllegalStateException("field not found: " + name, e);
964 }
965 }
966
967 void assertName(String expected) {
968 assertField("name", nameField, expected);
969 }
970
971 void assertTitle(String expected) {
972 assertField("title", titleField, expected);
973 }
974
975 void assertDescription(String expected) {
976 assertField("description", descField, expected);
977 }
978
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800979 /**
980 * Takes focus away from the name field so it can be validated.
981 */
982 void focusAwayFromName() {
983 mUiBot.click(titleField, "title_field"); // Change focus.
984 mUiBot.pressBack(); // Dismiss keyboard.
985 }
986
987 void reOpen() {
Felipe Leme85ae3cf2016-02-24 15:36:50 -0800988 openProgressNotification(ID);
Felipe Lemebc73ffc2015-12-11 15:07:14 -0800989 mUiBot.click(detailsButton, "details_button");
990
991 }
992
993 void clickOk() {
994 mUiBot.click(okButton, "details_ok_button");
995 }
996
997 void clickCancel() {
998 mUiBot.click(cancelButton, "details_cancel_button");
999 }
1000 }
Felipe Lemee53e85f2015-11-17 17:37:53 -08001001}