Skeleton API for IncidentManager to retrieve incident reports.

Bug: 123543706
Test: make
Change-Id: I0a41d476703cb0c1c728c6de1bf290162129e699
diff --git a/api/system-current.txt b/api/system-current.txt
index dcc3dc7..0f83ab3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1298,6 +1298,7 @@
     field public static final String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY";
     field public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
     field public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
+    field public static final String ACTION_INCIDENT_REPORT_READY = "android.intent.action.INCIDENT_REPORT_READY";
     field public static final String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
     field public static final String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
     field public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
@@ -5336,11 +5337,17 @@
   public class IncidentManager {
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void approveReport(android.net.Uri);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
     field public static final int FLAG_CONFIRMATION_DIALOG = 1; // 0x1
+    field public static final int PRIVACY_POLICY_AUTO = 200; // 0xc8
+    field public static final int PRIVACY_POLICY_EXPLICIT = 100; // 0x64
+    field public static final int PRIVACY_POLICY_LOCAL = 0; // 0x0
   }
 
   public static class IncidentManager.AuthListener {
@@ -5349,6 +5356,17 @@
     method public void onReportDenied();
   }
 
+  public static class IncidentManager.IncidentReport implements java.io.Closeable android.os.Parcelable {
+    ctor public IncidentManager.IncidentReport(android.os.Parcel);
+    method public void close();
+    method public int describeContents();
+    method public java.io.InputStream getInputStream() throws java.io.IOException;
+    method public long getPrivacyPolicy();
+    method public long getTimestamp();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.IncidentManager.IncidentReport> CREATOR;
+  }
+
   public static class IncidentManager.PendingReport {
     ctor public IncidentManager.PendingReport(@NonNull android.net.Uri);
     method public int getFlags();
diff --git a/api/test-current.txt b/api/test-current.txt
index 4ca3f56..2c0223d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1284,11 +1284,17 @@
   public class IncidentManager {
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void approveReport(android.net.Uri);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
     field public static final int FLAG_CONFIRMATION_DIALOG = 1; // 0x1
+    field public static final int PRIVACY_POLICY_AUTO = 200; // 0xc8
+    field public static final int PRIVACY_POLICY_EXPLICIT = 100; // 0x64
+    field public static final int PRIVACY_POLICY_LOCAL = 0; // 0x0
   }
 
   public static class IncidentManager.AuthListener {
@@ -1297,6 +1303,17 @@
     method public void onReportDenied();
   }
 
+  public static class IncidentManager.IncidentReport implements java.io.Closeable android.os.Parcelable {
+    ctor public IncidentManager.IncidentReport(android.os.Parcel);
+    method public void close();
+    method public int describeContents();
+    method public java.io.InputStream getInputStream() throws java.io.IOException;
+    method public long getPrivacyPolicy();
+    method public long getTimestamp();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.IncidentManager.IncidentReport> CREATOR;
+  }
+
   public static class IncidentManager.PendingReport {
     ctor public IncidentManager.PendingReport(@NonNull android.net.Uri);
     method public int getFlags();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8d14091..65ea635 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1487,6 +1487,24 @@
             "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED";
 
     /**
+     * An incident report has been taken, and the user has approved it for sharing.
+     * <p>
+     * This will be sent directly to the registered receiver, which must have
+     * both the DUMP and USAGE_STATS permissions.
+     * <p>
+     * After receiving this, the application should wait until a suitable time
+     * (e.g. network available), get the list of available reports with
+     * {@link IncidentManager#getIncidentReportList IncidentManager.getIncidentReportList(String)}
+     * and then when the reports have been successfully uploaded, call
+     * {@link IncidentManager#deleteIncidentReport IncidentManager.deleteIncidentReport(Uri)}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_INCIDENT_REPORT_READY =
+            "android.intent.action.INCIDENT_REPORT_READY";
+
+    /**
      * Activity Action: Show power usage information to the user.
      * <p>Input: Nothing.
      * <p>Output: Nothing.
diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java
index 88a578a..a1c7b08 100644
--- a/core/java/android/os/IncidentManager.java
+++ b/core/java/android/os/IncidentManager.java
@@ -16,7 +16,9 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
@@ -25,6 +27,11 @@
 import android.net.Uri;
 import android.util.Slog;
 
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -95,6 +102,33 @@
      */
     public static final int FLAG_CONFIRMATION_DIALOG = 0x1;
 
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device only via adb.
+     */
+    public static final int PRIVACY_POLICY_LOCAL = 0;
+
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device with contemporary consent.
+     */
+    public static final int PRIVACY_POLICY_EXPLICIT = 100;
+
+    /**
+     * Flag marking fields and incident reports than can be taken
+     * off the device with prior consent.
+     */
+    public static final int PRIVACY_POLICY_AUTO = 200;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = { "PRIVACY_POLICY_" }, value = {
+            PRIVACY_POLICY_AUTO,
+            PRIVACY_POLICY_EXPLICIT,
+            PRIVACY_POLICY_LOCAL,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PrivacyPolicy {}
+
     private final Context mContext;
 
     private Object mLock = new Object();
@@ -203,6 +237,110 @@
     }
 
     /**
+     * Record of an incident report that has previously been taken.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static class IncidentReport implements Parcelable, Closeable {
+        private final long mTimestampMs;
+        private final int mPrivacyPolicy;
+        private ParcelFileDescriptor mFileDescriptor;
+
+        public IncidentReport(Parcel in) {
+            mTimestampMs = in.readLong();
+            mPrivacyPolicy = in.readInt();
+            if (in.readInt() != 0) {
+                mFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+            } else {
+                mFileDescriptor = null;
+            }
+        }
+
+        /**
+         * Close the input stream associated with this entry.
+         */
+        public void close() {
+            try {
+                if (mFileDescriptor != null) {
+                    mFileDescriptor.close();
+                    mFileDescriptor = null;
+                }
+            } catch (IOException e) {
+            }
+        }
+
+        /**
+         * Get the time at which this incident report was taken, in wall clock time
+         * ({@link System#uptimeMillis System.uptimeMillis()} time base).
+         */
+        public long getTimestamp() {
+            return mTimestampMs;
+        }
+
+        /**
+         * Get the privacy level to which this report has been filtered.
+         *
+         * @see #PRIVACY_POLICY_AUTO
+         * @see #PRIVACY_POLICY_EXPLICIT
+         * @see #PRIVACY_POLICY_LOCAL
+         */
+        public long getPrivacyPolicy() {
+            return mPrivacyPolicy;
+        }
+
+        /**
+         * Get the contents of this incident report.
+         */
+        public InputStream getInputStream() throws IOException {
+            if (mFileDescriptor == null) {
+                return null;
+            }
+            return new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
+        }
+
+        /**
+         * @inheritDoc
+         */
+        public int describeContents() {
+            return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
+        }
+
+        /**
+         * @inheritDoc
+         */
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeLong(mTimestampMs);
+            out.writeInt(mPrivacyPolicy);
+            if (mFileDescriptor != null) {
+                out.writeInt(1);
+                mFileDescriptor.writeToParcel(out, flags);
+            } else {
+                out.writeInt(0);
+            }
+        }
+
+        /**
+         * {@link Parcelable.Creator Creator} for {@link IncidentReport}.
+         */
+        public static final Parcelable.Creator<IncidentReport> CREATOR = new Parcelable.Creator() {
+            /**
+             * @inheritDoc
+             */
+            public IncidentReport[] newArray(int size) {
+                return new IncidentReport[size];
+            }
+
+            /**
+             * @inheritDoc
+             */
+            public IncidentReport createFromParcel(Parcel in) {
+                return new IncidentReport(in);
+            }
+        };
+    }
+
+    /**
      * Listener for the status of an incident report being authroized or denied.
      *
      * @see #requestAuthorization
@@ -242,7 +380,7 @@
     }
 
     /**
-     * Take an incident report and put it in dropbox.
+     * Take an incident report.
      */
     @RequiresPermission(allOf = {
             android.Manifest.permission.DUMP,
@@ -325,6 +463,52 @@
         }
     }
 
+    /**
+     * Get the incident reports that are available for upload for the supplied
+     * broadcast recevier.
+     *
+     * @param receiverClass Class name of broadcast receiver in this package that
+     *   was registered to retrieve reports.
+     *
+     * @return A list of {@link Uri Uris} that are awaiting upload.
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.DUMP,
+            android.Manifest.permission.PACKAGE_USAGE_STATS
+    })
+    public @NonNull List<Uri> getIncidentReportList(String receiverClass) {
+        throw new RuntimeException("implement me");
+    }
+
+    /**
+     * Get the incident report with the given URI id.
+     *
+     * @param uri Identifier of the incident report.
+     *
+     * @return an IncidentReport object, or null if the incident report has been
+     *  expired from disk.
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.DUMP,
+            android.Manifest.permission.PACKAGE_USAGE_STATS
+    })
+    public @Nullable IncidentReport getIncidentReport(Uri uri) {
+        throw new RuntimeException("implement me");
+    }
+
+    /**
+     * Delete the incident report with the given URI id.
+     *
+     * @param uri Identifier of the incident report.
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.DUMP,
+            android.Manifest.permission.PACKAGE_USAGE_STATS
+    })
+    public void deleteIncidentReports(Uri uri) {
+        throw new RuntimeException("implement me");
+    }
+
     private void reportIncidentInternal(IncidentReportArgs args) {
         try {
             final IIncidentManager service = getIIncidentManagerLocked();
diff --git a/core/java/android/os/IncidentReportArgs.java b/core/java/android/os/IncidentReportArgs.java
index 3ca7f77..8d44727 100644
--- a/core/java/android/os/IncidentReportArgs.java
+++ b/core/java/android/os/IncidentReportArgs.java
@@ -32,19 +32,16 @@
 @TestApi
 public final class IncidentReportArgs implements Parcelable {
 
-    private static final int DEST_EXPLICIT = 100;
-    private static final int DEST_AUTO = 200;
-
     private final IntArray mSections = new IntArray();
     private final ArrayList<byte[]> mHeaders = new ArrayList<byte[]>();
     private boolean mAll;
-    private int mDest;
+    private int mPrivacyPolicy;
 
     /**
      * Construct an incident report args with no fields.
      */
     public IncidentReportArgs() {
-        mDest = DEST_AUTO;
+        mPrivacyPolicy = IncidentManager.PRIVACY_POLICY_AUTO;
     }
 
     /**
@@ -75,7 +72,7 @@
             out.writeByteArray(mHeaders.get(i));
         }
 
-        out.writeInt(mDest);
+        out.writeInt(mPrivacyPolicy);
     }
 
     public void readFromParcel(Parcel in) {
@@ -93,7 +90,7 @@
             mHeaders.add(in.createByteArray());
         }
 
-        mDest = in.readInt();
+        mPrivacyPolicy = in.readInt();
     }
 
     public static final Parcelable.Creator<IncidentReportArgs> CREATOR
@@ -128,7 +125,7 @@
         sb.append(", ");
         sb.append(mHeaders.size());
         sb.append(" headers), ");
-        sb.append("Dest enum value: ").append(mDest);
+        sb.append("privacy: ").append(mPrivacyPolicy);
         return sb.toString();
     }
 
@@ -145,14 +142,15 @@
     /**
      * Set this incident report privacy policy spec.
      */
-    public void setPrivacyPolicy(int dest) {
-        switch (dest) {
-            case DEST_EXPLICIT:
-            case DEST_AUTO:
-                mDest = dest;
+    public void setPrivacyPolicy(int privacyPolicy) {
+        switch (privacyPolicy) {
+            case IncidentManager.PRIVACY_POLICY_LOCAL:
+            case IncidentManager.PRIVACY_POLICY_EXPLICIT:
+            case IncidentManager.PRIVACY_POLICY_AUTO:
+                mPrivacyPolicy = privacyPolicy;
                 break;
             default:
-                mDest = DEST_AUTO;
+                mPrivacyPolicy = IncidentManager.PRIVACY_POLICY_AUTO;
         }
     }