Add APIs to support call composer filtering

Add APIs in callscreeningservice to allow the screening service to
specify which call composer attachments should be shown to the user.

Fixes: 179412110
Test: atest ConnectionServiceTest ExtendedInCallServiceTest
Change-Id: Ib7d3213ecda8f612461e6e36375c16261fc5492a
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index b7f59e1..deeb433 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -17,6 +17,7 @@
 package android.telecom;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -38,6 +39,8 @@
 import com.android.internal.telecom.ICallScreeningAdapter;
 import com.android.internal.telecom.ICallScreeningService;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -176,19 +179,23 @@
         private final boolean mShouldSkipNotification;
         private final boolean mShouldScreenCallViaAudioProcessing;
 
+        private final int mCallComposerAttachmentsToShow;
+
         private ParcelableCallResponse(
-                 boolean shouldDisallowCall,
-                 boolean shouldRejectCall,
-                 boolean shouldSilenceCall,
-                 boolean shouldSkipCallLog,
-                 boolean shouldSkipNotification,
-                 boolean shouldScreenCallViaAudioProcessing) {
+                boolean shouldDisallowCall,
+                boolean shouldRejectCall,
+                boolean shouldSilenceCall,
+                boolean shouldSkipCallLog,
+                boolean shouldSkipNotification,
+                boolean shouldScreenCallViaAudioProcessing,
+                int callComposerAttachmentsToShow) {
             mShouldDisallowCall = shouldDisallowCall;
             mShouldRejectCall = shouldRejectCall;
             mShouldSilenceCall = shouldSilenceCall;
             mShouldSkipCallLog = shouldSkipCallLog;
             mShouldSkipNotification = shouldSkipNotification;
             mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
+            mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
         }
 
         protected ParcelableCallResponse(Parcel in) {
@@ -198,6 +205,7 @@
             mShouldSkipCallLog = in.readBoolean();
             mShouldSkipNotification = in.readBoolean();
             mShouldScreenCallViaAudioProcessing = in.readBoolean();
+            mCallComposerAttachmentsToShow = in.readInt();
         }
 
         public CallResponse toCallResponse() {
@@ -208,6 +216,7 @@
                     .setSkipCallLog(mShouldSkipCallLog)
                     .setSkipNotification(mShouldSkipNotification)
                     .setShouldScreenCallViaAudioProcessing(mShouldScreenCallViaAudioProcessing)
+                    .setCallComposerAttachmentsToShow(mCallComposerAttachmentsToShow)
                     .build();
         }
 
@@ -235,6 +244,10 @@
             return mShouldScreenCallViaAudioProcessing;
         }
 
+        public int getCallComposerAttachmentsToShow() {
+            return mCallComposerAttachmentsToShow;
+        }
+
         public static final Creator<ParcelableCallResponse> CREATOR =
                 new Creator<ParcelableCallResponse>() {
                     @Override
@@ -261,19 +274,64 @@
             dest.writeBoolean(mShouldSkipCallLog);
             dest.writeBoolean(mShouldSkipNotification);
             dest.writeBoolean(mShouldScreenCallViaAudioProcessing);
+            dest.writeInt(mCallComposerAttachmentsToShow);
         }
     }
 
-    /*
-     * Information about how to respond to an incoming call.
+    /**
+     * Information about how to respond to an incoming call. Call screening apps can construct an
+     * instance of this class using {@link CallResponse.Builder}.
      */
     public static class CallResponse {
+        /**
+         * Bit flag indicating whether to show the picture attachment for call composer.
+         *
+         * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
+         */
+        public static final int CALL_COMPOSER_ATTACHMENT_PICTURE = 1;
+
+        /**
+         * Bit flag indicating whether to show the location attachment for call composer.
+         *
+         * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
+         */
+        public static final int CALL_COMPOSER_ATTACHMENT_LOCATION = 1 << 1;
+
+        /**
+         * Bit flag indicating whether to show the subject attachment for call composer.
+         *
+         * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
+         */
+        public static final int CALL_COMPOSER_ATTACHMENT_SUBJECT = 1 << 2;
+
+        /**
+         * Bit flag indicating whether to show the priority attachment for call composer.
+         *
+         * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
+         */
+        public static final int CALL_COMPOSER_ATTACHMENT_PRIORITY = 1 << 3;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = "CALL_COMPOSER_ATTACHMENT_", flag = true,
+                value = {
+                        CALL_COMPOSER_ATTACHMENT_PICTURE,
+                        CALL_COMPOSER_ATTACHMENT_LOCATION,
+                        CALL_COMPOSER_ATTACHMENT_SUBJECT,
+                        CALL_COMPOSER_ATTACHMENT_PRIORITY
+                }
+        )
+        public @interface CallComposerAttachmentType {}
+
+        private static final int NUM_CALL_COMPOSER_ATTACHMENT_TYPES = 4;
+
         private final boolean mShouldDisallowCall;
         private final boolean mShouldRejectCall;
         private final boolean mShouldSilenceCall;
         private final boolean mShouldSkipCallLog;
         private final boolean mShouldSkipNotification;
         private final boolean mShouldScreenCallViaAudioProcessing;
+        private final int mCallComposerAttachmentsToShow;
 
         private CallResponse(
                 boolean shouldDisallowCall,
@@ -281,7 +339,8 @@
                 boolean shouldSilenceCall,
                 boolean shouldSkipCallLog,
                 boolean shouldSkipNotification,
-                boolean shouldScreenCallViaAudioProcessing) {
+                boolean shouldScreenCallViaAudioProcessing,
+                int callComposerAttachmentsToShow) {
             if (!shouldDisallowCall
                     && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
                 throw new IllegalStateException("Invalid response state for allowed call.");
@@ -297,6 +356,7 @@
             mShouldSkipNotification = shouldSkipNotification;
             mShouldSilenceCall = shouldSilenceCall;
             mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
+            mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
         }
 
         /*
@@ -344,6 +404,13 @@
             return mShouldScreenCallViaAudioProcessing;
         }
 
+        /**
+         * @return A bitmask of call composer attachments that should be shown to the user.
+         */
+        public @CallComposerAttachmentType int getCallComposerAttachmentsToShow() {
+            return mCallComposerAttachmentsToShow;
+        }
+
         /** @hide */
         public ParcelableCallResponse toParcelable() {
             return new ParcelableCallResponse(
@@ -352,7 +419,8 @@
                     mShouldSilenceCall,
                     mShouldSkipCallLog,
                     mShouldSkipNotification,
-                    mShouldScreenCallViaAudioProcessing
+                    mShouldScreenCallViaAudioProcessing,
+                    mCallComposerAttachmentsToShow
             );
         }
 
@@ -366,14 +434,17 @@
                     mShouldSilenceCall == that.mShouldSilenceCall &&
                     mShouldSkipCallLog == that.mShouldSkipCallLog &&
                     mShouldSkipNotification == that.mShouldSkipNotification &&
-                    mShouldScreenCallViaAudioProcessing == that.mShouldScreenCallViaAudioProcessing;
+                    mShouldScreenCallViaAudioProcessing
+                            == that.mShouldScreenCallViaAudioProcessing &&
+                    mCallComposerAttachmentsToShow == that.mCallComposerAttachmentsToShow;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(mShouldDisallowCall, mShouldRejectCall, mShouldSilenceCall,
                     mShouldSkipCallLog, mShouldSkipNotification,
-                    mShouldScreenCallViaAudioProcessing);
+                    mShouldScreenCallViaAudioProcessing,
+                    mCallComposerAttachmentsToShow);
         }
 
         public static class Builder {
@@ -383,6 +454,7 @@
             private boolean mShouldSkipCallLog;
             private boolean mShouldSkipNotification;
             private boolean mShouldScreenCallViaAudioProcessing;
+            private int mCallComposerAttachmentsToShow = -1;
 
             /**
              * Sets whether the incoming call should be blocked.
@@ -468,6 +540,38 @@
                 return this;
             }
 
+            /**
+             * Sets the call composer attachments that should be shown to the user.
+             *
+             * Attachments that are not shown will not be passed to the in-call UI responsible for
+             * displaying the call to the user.
+             *
+             * If this method is not called on a {@link Builder}, all attachments will be shown,
+             * except pictures, which will only be shown to users if the call is from a contact.
+             *
+             * Setting attachments to show will have no effect if the call screening service does
+             * not belong to the same package as the system dialer (as returned by
+             * {@link TelecomManager#getSystemDialerPackage()}).
+             *
+             * @param callComposerAttachmentsToShow A bitmask of call composer attachments to show.
+             */
+            public @NonNull Builder setCallComposerAttachmentsToShow(
+                    @CallComposerAttachmentType int callComposerAttachmentsToShow) {
+                // If the argument is less than zero (meaning unset), no-op since the conversion
+                // to/from the parcelable version may call with that value.
+                if (callComposerAttachmentsToShow < 0) {
+                    return this;
+                }
+
+                if ((callComposerAttachmentsToShow
+                        & (1 << NUM_CALL_COMPOSER_ATTACHMENT_TYPES)) != 0) {
+                    throw new IllegalArgumentException("Attachment types must match the ones"
+                            + " defined in CallResponse");
+                }
+                mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
+                return this;
+            }
+
             public CallResponse build() {
                 return new CallResponse(
                         mShouldDisallowCall,
@@ -475,7 +579,8 @@
                         mShouldSilenceCall,
                         mShouldSkipCallLog,
                         mShouldSkipNotification,
-                        mShouldScreenCallViaAudioProcessing);
+                        mShouldScreenCallViaAudioProcessing,
+                        mCallComposerAttachmentsToShow);
             }
        }
     }