Refactor CallScreeningService's internal structure
Use a single AIDL method and perform logic in Telecom instead of slicing
up the call response on the client side.
Also pass through the call response to the connection service.
Bug: 179412110
Test: atest ConnectionServiceTest CallScreeningServiceTest
Change-Id: I878c0ce34142da104dc0e2795487b03a6bdacb5f
diff --git a/telecomm/java/android/telecom/CallScreeningService.aidl b/telecomm/java/android/telecom/CallScreeningService.aidl
new file mode 100644
index 0000000..87b5138
--- /dev/null
+++ b/telecomm/java/android/telecom/CallScreeningService.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable CallScreeningService.ParcelableCallResponse;
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 7988b03..b7f59e1 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -30,12 +30,16 @@
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.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 +136,10 @@
.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,6 +164,106 @@
private ICallScreeningAdapter mCallScreeningAdapter;
+ /**
+ * 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 ParcelableCallResponse(
+ boolean shouldDisallowCall,
+ boolean shouldRejectCall,
+ boolean shouldSilenceCall,
+ boolean shouldSkipCallLog,
+ boolean shouldSkipNotification,
+ boolean shouldScreenCallViaAudioProcessing) {
+ mShouldDisallowCall = shouldDisallowCall;
+ mShouldRejectCall = shouldRejectCall;
+ mShouldSilenceCall = shouldSilenceCall;
+ mShouldSkipCallLog = shouldSkipCallLog;
+ mShouldSkipNotification = shouldSkipNotification;
+ mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
+ }
+
+ protected ParcelableCallResponse(Parcel in) {
+ mShouldDisallowCall = in.readBoolean();
+ mShouldRejectCall = in.readBoolean();
+ mShouldSilenceCall = in.readBoolean();
+ mShouldSkipCallLog = in.readBoolean();
+ mShouldSkipNotification = in.readBoolean();
+ mShouldScreenCallViaAudioProcessing = in.readBoolean();
+ }
+
+ public CallResponse toCallResponse() {
+ return new CallResponse.Builder()
+ .setDisallowCall(mShouldDisallowCall)
+ .setRejectCall(mShouldRejectCall)
+ .setSilenceCall(mShouldSilenceCall)
+ .setSkipCallLog(mShouldSkipCallLog)
+ .setSkipNotification(mShouldSkipNotification)
+ .setShouldScreenCallViaAudioProcessing(mShouldScreenCallViaAudioProcessing)
+ .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 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);
+ }
+ }
+
/*
* Information about how to respond to an incoming call.
*/
@@ -237,6 +344,38 @@
return mShouldScreenCallViaAudioProcessing;
}
+ /** @hide */
+ public ParcelableCallResponse toParcelable() {
+ return new ParcelableCallResponse(
+ mShouldDisallowCall,
+ mShouldRejectCall,
+ mShouldSilenceCall,
+ mShouldSkipCallLog,
+ mShouldSkipNotification,
+ mShouldScreenCallViaAudioProcessing
+ );
+ }
+
+ @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;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mShouldDisallowCall, mShouldRejectCall, mShouldSilenceCall,
+ mShouldSkipCallLog, mShouldSkipNotification,
+ mShouldScreenCallViaAudioProcessing);
+ }
+
public static class Builder {
private boolean mShouldDisallowCall;
private boolean mShouldRejectCall;
@@ -423,21 +562,12 @@
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");
}
}
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 089a948..942a54e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3390,11 +3390,20 @@
* {@code true}, {@link #onDisconnect()} will be called soon after
* this is called.
* @param isInContacts Indicates whether the caller is in the user's contacts list.
+ * @param callScreeningResponse The response that was returned from the
+ * {@link CallScreeningService} that handled this call. If no
+ * response was received from a call screening service,
+ * this will be {@code null}.
+ * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
+ * system dialer. If {@code callScreeningResponse} is
+ * {@code null}, this will be {@code false}.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_CONTACTS)
- public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts) { }
+ public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
+ @Nullable CallScreeningService.CallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer) { }
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 3b06fd3..d9b108b 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -759,6 +759,8 @@
@Override
public void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
+ CallScreeningService.ParcelableCallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_CALL_FILTERING_COMPLETED);
try {
@@ -766,7 +768,9 @@
args.arg1 = callId;
args.arg2 = isBlocked;
args.arg3 = isInContacts;
- args.arg4 = Log.createSubsession();
+ args.arg4 = callScreeningResponse;
+ args.arg5 = isResponseFromSystemDialer;
+ args.arg6 = Log.createSubsession();
mHandler.obtainMessage(MSG_ON_CALL_FILTERING_COMPLETED, args).sendToTarget();
} finally {
Log.endSession();
@@ -1437,12 +1441,16 @@
case MSG_ON_CALL_FILTERING_COMPLETED: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- Log.continueSession((Session) args.arg4,
+ Log.continueSession((Session) args.arg6,
SESSION_HANDLER + SESSION_CALL_FILTERING_COMPLETED);
String callId = (String) args.arg1;
boolean isBlocked = (boolean) args.arg2;
boolean isInContacts = (boolean) args.arg3;
- onCallFilteringCompleted(callId, isBlocked, isInContacts);
+ CallScreeningService.ParcelableCallResponse callScreeningResponse =
+ (CallScreeningService.ParcelableCallResponse) args.arg4;
+ boolean isResponseFromSystemDialer = (boolean) args.arg5;
+ onCallFilteringCompleted(callId, isBlocked, isInContacts,
+ callScreeningResponse, isResponseFromSystemDialer);
} finally {
args.recycle();
Log.endSession();
@@ -2458,11 +2466,16 @@
}
}
- private void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts) {
- Log.i(this, "onCallFilteringCompleted(%b, %b)", isBlocked, isInContacts);
+ private void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
+ CallScreeningService.ParcelableCallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer) {
+ Log.i(this, "onCallFilteringCompleted(%s, %b, %b, %s, %b)", callId,
+ isBlocked, isInContacts, callScreeningResponse, isResponseFromSystemDialer);
Connection connection = findConnectionForAction(callId, "onCallFilteringCompleted");
if (connection != null) {
- connection.onCallFilteringCompleted(isBlocked, isInContacts);
+ connection.onCallFilteringCompleted(isBlocked, isInContacts,
+ callScreeningResponse == null ? null : callScreeningResponse.toCallResponse(),
+ isResponseFromSystemDialer);
}
}
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index feb2ca5..6c6097a 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1204,15 +1204,25 @@
* the results of a contacts lookup for the remote party.
* @param isBlocked Whether call filtering indicates that the call should be blocked
* @param isInContacts Whether the remote party is in the user's contacts
+ * @param callScreeningResponse The response that was returned from the
+ * {@link CallScreeningService} that handled this call. If no
+ * response was received from a call screening service,
+ * this will be {@code null}.
+ * @param isResponseFromSystemDialer Whether {@code callScreeningResponse} was sent from the
+ * system dialer. If {@code callScreeningResponse} is
+ * {@code null}, this will be {@code false}.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_CONTACTS)
- public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts) {
+ public void onCallFilteringCompleted(boolean isBlocked, boolean isInContacts,
+ @Nullable CallScreeningService.CallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer) {
Log.startSession("RC.oCFC", getActiveOwnerInfo());
try {
if (mConnected) {
mConnectionService.onCallFilteringCompleted(mConnectionId, isBlocked, isInContacts,
+ callScreeningResponse.toParcelable(), isResponseFromSystemDialer,
null /*Session.Info*/);
}
} catch (RemoteException ignored) {
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index 83c8f62..0f2e178 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telecom;
import android.content.ComponentName;
+import android.telecom.CallScreeningService;
/**
* Internal remote callback interface for call screening services.
@@ -26,16 +27,6 @@
* {@hide}
*/
oneway interface ICallScreeningAdapter {
- void allowCall(String callId);
-
- void silenceCall(String callId);
-
- void screenCallFurther(String callId);
-
- void disallowCall(
- String callId,
- boolean shouldReject,
- boolean shouldAddToCallLog,
- boolean shouldShowNotification,
- in ComponentName componentName);
+ void onScreeningResponse(String callId, in ComponentName componentName,
+ in CallScreeningService.ParcelableCallResponse response);
}
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 301c2bb..7599e18 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.telecom.CallAudioState;
+import android.telecom.CallScreeningService;
import android.telecom.ConnectionRequest;
import android.telecom.Logging.Session;
import android.telecom.PhoneAccountHandle;
@@ -119,7 +120,8 @@
void sendCallEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo);
void onCallFilteringCompleted(String callId, boolean isBlocked, boolean isInContacts,
- in Session.Info sessionInfo);
+ in CallScreeningService.ParcelableCallResponse callScreeningResponse,
+ boolean isResponseFromSystemDialer, in Session.Info sessionInfo);
void onExtrasChanged(String callId, in Bundle extras, in Session.Info sessionInfo);