diff options
Diffstat (limited to 'telecomm/java/android/telecom/CallScreeningService.java')
-rw-r--r-- | telecomm/java/android/telecom/CallScreeningService.java | 273 |
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"); } } } |