summaryrefslogtreecommitdiff
path: root/telecomm/java/android/telecom/CallScreeningService.java
diff options
context:
space:
mode:
Diffstat (limited to 'telecomm/java/android/telecom/CallScreeningService.java')
-rw-r--r--telecomm/java/android/telecom/CallScreeningService.java273
1 files changed, 254 insertions, 19 deletions
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 7988b036ccd3..deeb4331bcaa 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;
@@ -30,12 +31,18 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
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;
+
/**
* This service can be implemented by the default dialer (see
* {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
@@ -132,7 +139,10 @@ public abstract class CallScreeningService extends Service {
.createFromParcelableCall((ParcelableCall) args.arg2);
onScreenCall(callDetails);
if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) {
- mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
+ mCallScreeningAdapter.onScreeningResponse(
+ callDetails.getTelecomCallId(),
+ new ComponentName(getPackageName(), getClass().getName()),
+ null);
}
} catch (RemoteException e) {
Log.w(this, "Exception when screening call: " + e);
@@ -157,16 +167,171 @@ public abstract class CallScreeningService extends Service {
private ICallScreeningAdapter mCallScreeningAdapter;
- /*
- * Information about how to respond to an incoming call.
+ /**
+ * Parcelable version of {@link CallResponse} used to do IPC.
+ * @hide
+ */
+ public static class ParcelableCallResponse implements Parcelable {
+ 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 ParcelableCallResponse(
+ 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) {
+ mShouldDisallowCall = in.readBoolean();
+ mShouldRejectCall = in.readBoolean();
+ mShouldSilenceCall = in.readBoolean();
+ mShouldSkipCallLog = in.readBoolean();
+ mShouldSkipNotification = in.readBoolean();
+ mShouldScreenCallViaAudioProcessing = in.readBoolean();
+ mCallComposerAttachmentsToShow = in.readInt();
+ }
+
+ public CallResponse toCallResponse() {
+ return new CallResponse.Builder()
+ .setDisallowCall(mShouldDisallowCall)
+ .setRejectCall(mShouldRejectCall)
+ .setSilenceCall(mShouldSilenceCall)
+ .setSkipCallLog(mShouldSkipCallLog)
+ .setSkipNotification(mShouldSkipNotification)
+ .setShouldScreenCallViaAudioProcessing(mShouldScreenCallViaAudioProcessing)
+ .setCallComposerAttachmentsToShow(mCallComposerAttachmentsToShow)
+ .build();
+ }
+
+ public boolean shouldDisallowCall() {
+ return mShouldDisallowCall;
+ }
+
+ public boolean shouldRejectCall() {
+ return mShouldRejectCall;
+ }
+
+ public boolean shouldSilenceCall() {
+ return mShouldSilenceCall;
+ }
+
+ public boolean shouldSkipCallLog() {
+ return mShouldSkipCallLog;
+ }
+
+ public boolean shouldSkipNotification() {
+ return mShouldSkipNotification;
+ }
+
+ public boolean shouldScreenCallViaAudioProcessing() {
+ return mShouldScreenCallViaAudioProcessing;
+ }
+
+ public int getCallComposerAttachmentsToShow() {
+ return mCallComposerAttachmentsToShow;
+ }
+
+ public static final Creator<ParcelableCallResponse> CREATOR =
+ new Creator<ParcelableCallResponse>() {
+ @Override
+ public ParcelableCallResponse createFromParcel(Parcel in) {
+ return new ParcelableCallResponse(in);
+ }
+
+ @Override
+ public ParcelableCallResponse[] newArray(int size) {
+ return new ParcelableCallResponse[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mShouldDisallowCall);
+ dest.writeBoolean(mShouldRejectCall);
+ dest.writeBoolean(mShouldSilenceCall);
+ dest.writeBoolean(mShouldSkipCallLog);
+ dest.writeBoolean(mShouldSkipNotification);
+ dest.writeBoolean(mShouldScreenCallViaAudioProcessing);
+ dest.writeInt(mCallComposerAttachmentsToShow);
+ }
+ }
+
+ /**
+ * 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,
@@ -174,7 +339,8 @@ public abstract class CallScreeningService extends Service {
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.");
@@ -190,6 +356,7 @@ public abstract class CallScreeningService extends Service {
mShouldSkipNotification = shouldSkipNotification;
mShouldSilenceCall = shouldSilenceCall;
mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
+ mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
}
/*
@@ -237,6 +404,49 @@ public abstract class CallScreeningService extends Service {
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(
+ mShouldDisallowCall,
+ mShouldRejectCall,
+ mShouldSilenceCall,
+ mShouldSkipCallLog,
+ mShouldSkipNotification,
+ mShouldScreenCallViaAudioProcessing,
+ mCallComposerAttachmentsToShow
+ );
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CallResponse that = (CallResponse) o;
+ return mShouldDisallowCall == that.mShouldDisallowCall &&
+ mShouldRejectCall == that.mShouldRejectCall &&
+ mShouldSilenceCall == that.mShouldSilenceCall &&
+ mShouldSkipCallLog == that.mShouldSkipCallLog &&
+ mShouldSkipNotification == that.mShouldSkipNotification &&
+ mShouldScreenCallViaAudioProcessing
+ == that.mShouldScreenCallViaAudioProcessing &&
+ mCallComposerAttachmentsToShow == that.mCallComposerAttachmentsToShow;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mShouldDisallowCall, mShouldRejectCall, mShouldSilenceCall,
+ mShouldSkipCallLog, mShouldSkipNotification,
+ mShouldScreenCallViaAudioProcessing,
+ mCallComposerAttachmentsToShow);
+ }
+
public static class Builder {
private boolean mShouldDisallowCall;
private boolean mShouldRejectCall;
@@ -244,6 +454,7 @@ public abstract class CallScreeningService extends Service {
private boolean mShouldSkipCallLog;
private boolean mShouldSkipNotification;
private boolean mShouldScreenCallViaAudioProcessing;
+ private int mCallComposerAttachmentsToShow = -1;
/**
* Sets whether the incoming call should be blocked.
@@ -329,6 +540,38 @@ public abstract class CallScreeningService extends Service {
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,
@@ -336,7 +579,8 @@ public abstract class CallScreeningService extends Service {
mShouldSilenceCall,
mShouldSkipCallLog,
mShouldSkipNotification,
- mShouldScreenCallViaAudioProcessing);
+ mShouldScreenCallViaAudioProcessing,
+ mCallComposerAttachmentsToShow);
}
}
}
@@ -423,21 +667,12 @@ public abstract class CallScreeningService extends Service {
public final void respondToCall(@NonNull Call.Details callDetails,
@NonNull CallResponse response) {
try {
- if (response.getDisallowCall()) {
- mCallScreeningAdapter.disallowCall(
- callDetails.getTelecomCallId(),
- response.getRejectCall(),
- !response.getSkipCallLog(),
- !response.getSkipNotification(),
- new ComponentName(getPackageName(), getClass().getName()));
- } else if (response.getSilenceCall()) {
- mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
- } else if (response.getShouldScreenCallViaAudioProcessing()) {
- mCallScreeningAdapter.screenCallFurther(callDetails.getTelecomCallId());
- } else {
- mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
- }
+ mCallScreeningAdapter.onScreeningResponse(
+ callDetails.getTelecomCallId(),
+ new ComponentName(getPackageName(), getClass().getName()),
+ response.toParcelable());
} catch (RemoteException e) {
+ Log.e(this, e, "Got remote exception when returning response");
}
}
}