Add API to request Bug Report with a certain title and description

ActivityManagerService will send the details to dumpstate and
BugreportProgressService will get the details from dumpstate and use
that for the notification.

Bug: 33561517
Test: Modify TelephonyMonitor to use this API and ensure that the
      notification uses that the title and description sent as arguments
      to the API. File a bug using betterBug and ensure that the
      information gets populated automatically.

Change-Id: I455f1df2278e5d569dd19c74245a0704dcf5a321
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b08ca4f..82229d5 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -329,6 +329,18 @@
     // No new code should be calling it.
     void requestBugReport(int bugreportType);
 
+    /**
+     *  Takes a telephony bug report and notifies the user with the title and description
+     *  that are passed to this API as parameters
+     *
+     *  @param shareTitle should be a valid legible string less than 50 chars long
+     *  @param shareDescription should be less than 91 bytes when encoded into UTF-8 format
+     *
+     *  @throws IllegalArgumentException if shareTitle or shareDescription is too big or if the
+     *          paremeters cannot be encoding to an UTF-8 charset.
+     */
+    void requestTelephonyBugReport(in String shareTitle, in String shareDescription);
+
     long inputDispatchingTimedOut(int pid, boolean aboveSystem, in String reason);
     void clearPendingBackup();
     Intent getIntentForIntentSender(in IIntentSender sender);
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index bf5e6f8..d37e6a0 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -31,7 +31,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
 import java.text.NumberFormat;
 import java.util.ArrayList;
@@ -99,7 +98,6 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.View.OnFocusChangeListener;
-import android.view.inputmethod.EditorInfo;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.Toast;
@@ -802,6 +800,17 @@
         if (screenshot != null) {
             info.addScreenshot(screenshot);
         }
+
+        final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
+        if (!TextUtils.isEmpty(shareTitle)) {
+            info.title = shareTitle;
+            final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
+            if (!TextUtils.isEmpty(shareDescription)) {
+                info.shareDescription= shareDescription;
+            }
+            Log.d(TAG, "Bugreport title is " + info.title + ","
+                    + " shareDescription is " + info.shareDescription);
+        }
         info.finished = true;
 
         // Stop running on foreground, otherwise share notification cannot be dismissed.
@@ -977,10 +986,20 @@
         shareIntent.putExtra(EXTRA_ID, info.id);
         shareIntent.putExtra(EXTRA_INFO, info);
 
-        final String title = mContext.getString(R.string.bugreport_finished_title, info.id);
-        final String content = takingScreenshot ?
+        String content;
+        content = takingScreenshot ?
                 mContext.getString(R.string.bugreport_finished_pending_screenshot_text)
                 : mContext.getString(R.string.bugreport_finished_text);
+        final String title;
+        if (TextUtils.isEmpty(info.title)) {
+            title = mContext.getString(R.string.bugreport_finished_title, info.id);
+        } else {
+            title = info.title;
+            if (!TextUtils.isEmpty(info.shareDescription)) {
+                if(!takingScreenshot) content = info.shareDescription;
+            }
+        }
+
         final Notification.Builder builder = newBaseNotification(mContext)
                 .setContentTitle(title)
                 .setTicker(title)
@@ -1241,6 +1260,7 @@
         addExtra(buffer, intent, EXTRA_BUGREPORT);
         addExtra(buffer, intent, EXTRA_SCREENSHOT);
         addExtra(buffer, intent, EXTRA_INFO);
+        addExtra(buffer, intent, EXTRA_TITLE);
 
         if (intent.hasExtra(EXTRA_ORIGINAL_INTENT)) {
             buffer.append(SHORT_EXTRA_ORIGINAL_INTENT).append(": ");
@@ -1647,6 +1667,11 @@
         int screenshotCounter;
 
         /**
+         * Descriptive text that will be shown to the user in the notification message.
+         */
+        String shareDescription;
+
+        /**
          * Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
          */
         BugreportInfo(Context context, int id, int pid, String name, int max) {
@@ -1747,6 +1772,7 @@
                 .append("\n\tlast_update: ").append(getFormattedLastUpdate())
                 .append("\n\taddingDetailsToZip: ").append(addingDetailsToZip)
                 .append(" addedDetailsToZip: ").append(addedDetailsToZip)
+                .append("\n\tshareDescription: ").append(shareDescription)
                 .toString();
         }
 
@@ -1773,6 +1799,7 @@
 
             finished = in.readInt() == 1;
             screenshotCounter = in.readInt();
+            shareDescription = in.readString();
         }
 
         @Override
@@ -1797,6 +1824,7 @@
 
             dest.writeInt(finished ? 1 : 0);
             dest.writeInt(screenshotCounter);
+            dest.writeString(shareDescription);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 92a4b78..96a945f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -384,6 +384,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
 import java.lang.ref.WeakReference;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -593,6 +594,10 @@
     @VisibleForTesting
     static final int NETWORK_STATE_UNBLOCK = 2;
 
+    // Max character limit for a notification title. If the notification title is larger than this
+    // the notification will not be legible to the user.
+    private static final int MAX_BUGREPORT_TITLE_SIZE = 50;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
     AssistUtils mAssistUtils;
@@ -12622,6 +12627,7 @@
      * No new code should be calling it.
      */
     @Deprecated
+    @Override
     public void requestBugReport(int bugreportType) {
         String extraOptions = null;
         switch (bugreportType) {
@@ -12651,6 +12657,46 @@
         SystemProperties.set("ctl.start", "bugreport");
     }
 
+    /**
+     * @deprecated This method is only used by a few internal components and it will soon be
+     * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
+     * No new code should be calling it.
+     */
+    @Deprecated
+    @Override
+    public void requestTelephonyBugReport(String shareTitle, String shareDescription) {
+
+        if (!TextUtils.isEmpty(shareTitle)) {
+            if (shareTitle.length() > MAX_BUGREPORT_TITLE_SIZE) {
+                String errorStr = "shareTitle should be less than " +
+                        MAX_BUGREPORT_TITLE_SIZE + " characters";
+                throw new IllegalArgumentException(errorStr);
+            } else {
+                if (!TextUtils.isEmpty(shareDescription)) {
+                    int length;
+                    try {
+                        length = shareDescription.getBytes("UTF-8").length;
+                    } catch (UnsupportedEncodingException e) {
+                        String errorStr = "shareDescription: UnsupportedEncodingException";
+                        throw new IllegalArgumentException(errorStr);
+                    }
+                    if (length > SystemProperties.PROP_VALUE_MAX) {
+                        String errorStr = "shareTitle should be less than " +
+                                SystemProperties.PROP_VALUE_MAX + " bytes";
+                        throw new IllegalArgumentException(errorStr);
+                    } else {
+                        SystemProperties.set("dumpstate.options.description", shareDescription);
+                    }
+                }
+                SystemProperties.set("dumpstate.options.title", shareTitle);
+            }
+        }
+
+        Slog.d(TAG, "Bugreport notification title " + shareTitle
+                + " description " + shareDescription);
+        requestBugReport(ActivityManager.BUGREPORT_OPTION_TELEPHONY);
+    }
+
     public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
         return r != null ? getInputDispatchingTimeoutLocked(r.app) : KEY_DISPATCHING_TIMEOUT;
     }