diff options
author | 2021-02-04 13:09:45 -0800 | |
---|---|---|
committer | 2021-02-12 14:04:10 -0800 | |
commit | 5efe99753969b0f4991e05830c4f6cc26bd1c2e1 (patch) | |
tree | b125257091f7ae96bc90adc06c264f8809fbc176 | |
parent | 191b3b9db547b603b636aa3a9ce4db672401952e (diff) |
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
8 files changed, 215 insertions, 38 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bea4b3925764..880f5db4a675 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10664,7 +10664,7 @@ package android.telecom { method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle(); method @Nullable public final String getTelecomCallId(); method @Deprecated public void onAudioStateChanged(android.telecom.AudioState); - method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean); + method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean); method public final void resetConnectionTime(); method public void setCallDirection(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long); @@ -10841,7 +10841,7 @@ package android.telecom { } public final class RemoteConnection { - method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean); + method @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public void onCallFilteringCompleted(boolean, boolean, @Nullable android.telecom.CallScreeningService.CallResponse, boolean); method @Deprecated public void setAudioState(android.telecom.AudioState); } diff --git a/telecomm/java/android/telecom/CallScreeningService.aidl b/telecomm/java/android/telecom/CallScreeningService.aidl new file mode 100644 index 000000000000..87b5138745f2 --- /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 7988b036ccd3..b7f59e113372 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -30,12 +30,16 @@ 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.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 @@ 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,6 +164,106 @@ public abstract class CallScreeningService extends Service { 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 @@ public abstract class CallScreeningService extends Service { 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 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"); } } } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 089a948b6e55..942a54eb98ba 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -3390,11 +3390,20 @@ public abstract class Connection extends Conferenceable { * {@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 3b06fd3d4ea1..d9b108b70d51 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -759,6 +759,8 @@ public abstract class ConnectionService extends Service { @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 @@ public abstract class ConnectionService extends Service { 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 @@ public abstract class ConnectionService extends Service { 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 @@ public abstract class ConnectionService extends Service { } } - 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 feb2ca53bbbe..6c6097ac71e5 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -1204,15 +1204,25 @@ public final class RemoteConnection { * 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 83c8f62bb3db..0f2e178f1970 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 @@ import android.content.ComponentName; * {@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 301c2bb6cdb2..7599e189cc37 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.net.Uri; 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 @@ oneway interface IConnectionService { 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); |