Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0df1dcd2 authored by Grace Jia's avatar Grace Jia Committed by android-build-merger
Browse files

Refactored CallScreeningServiceFilter to NewCallScreeningServiceFilter.

am: ed0cef05

Change-Id: I047bf443df79f638c6b67b50184b89490a4ea26f
parents 688952f2 ed0cef05
Loading
Loading
Loading
Loading
+31 −3
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ public class CallFilteringResult {
        private boolean mShouldShowNotification;
        private boolean mShouldSilence = false;
        private boolean mShouldScreenViaAudio = false;
        private boolean mContactExists = false;
        private int mCallBlockReason = Calls.BLOCK_REASON_NOT_BLOCKED;
        private CharSequence mCallScreeningAppName = null;
        private String mCallScreeningComponentName = null;
@@ -77,11 +78,30 @@ public class CallFilteringResult {
            return this;
        }

        public Builder setContactExists(boolean contactExists) {
            mContactExists = contactExists;
            return this;
        }

        public static Builder from(CallFilteringResult result) {
            return new Builder()
                    .setShouldAllowCall(result.shouldAllowCall)
                    .setShouldReject(result.shouldReject)
                    .setShouldAddToCallLog(result.shouldAddToCallLog)
                    .setShouldShowNotification(result.shouldShowNotification)
                    .setShouldSilence(result.shouldSilence)
                    .setCallBlockReason(result.mCallBlockReason)
                    .setShouldScreenViaAudio(result.shouldScreenViaAudio)
                    .setCallScreeningAppName(result.mCallScreeningAppName)
                    .setCallScreeningComponentName(result.mCallScreeningComponentName)
                    .setContactExists(result.contactExists);
        }

        public CallFilteringResult build() {
            return new CallFilteringResult(mShouldAllowCall, mShouldReject, mShouldSilence,
                    mShouldAddToCallLog, mShouldShowNotification, mCallBlockReason,
                    mCallScreeningAppName, mCallScreeningComponentName,
                    mShouldScreenViaAudio);
                    mCallScreeningAppName, mCallScreeningComponentName, mShouldScreenViaAudio,
                    mContactExists);
        }
    }

@@ -94,11 +114,12 @@ public class CallFilteringResult {
    public int mCallBlockReason;
    public CharSequence mCallScreeningAppName;
    public String mCallScreeningComponentName;
    public boolean contactExists;

    private CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
            shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int
            callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName,
            boolean shouldScreenViaAudio) {
            boolean shouldScreenViaAudio, boolean contactExists) {
        this.shouldAllowCall = shouldAllowCall;
        this.shouldReject = shouldReject;
        this.shouldSilence = shouldSilence;
@@ -108,6 +129,7 @@ public class CallFilteringResult {
        this.mCallBlockReason = callBlockReason;
        this.mCallScreeningAppName = callScreeningAppName;
        this.mCallScreeningComponentName = callScreeningComponentName;
        this.contactExists = contactExists;
    }

    /**
@@ -187,6 +209,7 @@ public class CallFilteringResult {
                .setCallBlockReason(callBlockReason)
                .setCallScreeningAppName(callScreeningAppName)
                .setCallScreeningComponentName(callScreeningComponentName)
                .setContactExists(contactExists || other.contactExists)
                .build();
    }

@@ -204,6 +227,7 @@ public class CallFilteringResult {
        if (shouldAddToCallLog != that.shouldAddToCallLog) return false;
        if (shouldShowNotification != that.shouldShowNotification) return false;
        if (mCallBlockReason != that.mCallBlockReason) return false;
        if (contactExists != that.contactExists) return false;

        if ((TextUtils.isEmpty(mCallScreeningAppName) &&
            TextUtils.isEmpty(that.mCallScreeningAppName)) &&
@@ -258,6 +282,10 @@ public class CallFilteringResult {
            sb.append(", notified");
        }

        if (contactExists) {
            sb.append(", contact exists");
        }

        if (mCallBlockReason != 0) {
            sb.append(", mCallBlockReason = ");
            sb.append(mCallBlockReason);
+2 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import java.util.concurrent.Executor;
public class IncomingCallFilterGraph {
    //TODO: Add logging for control flow.
    public static final String TAG = "IncomingCallFilterGraph";
    public static final CallFilteringResult DEFAULT_SCREENING_RESULT =
    public static final CallFilteringResult DEFAULT_RESULT =
            new CallFilteringResult.Builder()
                    .setShouldAllowCall(true)
                    .setShouldReject(false)
@@ -92,8 +92,8 @@ public class IncomingCallFilterGraph {
        mFinished = false;
        mContext = context;
        mTimeoutsAdapter = timeoutsAdapter;
        mCurrentResult = DEFAULT_SCREENING_RESULT;
        mLock = lock;
        mCurrentResult = DEFAULT_RESULT;
    }

    public void addFilter(CallFilter filter) {
+271 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 com.android.server.telecom.callfiltering;

import static com.android.server.telecom.callfiltering.IncomingCallFilterGraph.DEFAULT_RESULT;

import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.CallLog;
import android.telecom.Log;
import android.telecom.TelecomManager;

import com.android.internal.telecom.ICallScreeningAdapter;
import com.android.internal.telecom.ICallScreeningService;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallScreeningServiceHelper;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.ParcelableCallUtils;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class NewCallScreeningServiceFilter extends CallFilter {
    //TODO: Change the name of this class with CallScreeningServiceFilter
    public static final int PACKAGE_TYPE_CARRIER = 0;
    public static final int PACKAGE_TYPE_DEFAULT_DIALER = 1;
    public static final int PACKAGE_TYPE_USER_CHOSEN = 2;
    public static final long CALL_SCREENING_FILTER_TIMEOUT = 5000;

    private final Call mCall;
    private final String mPackageName;
    private final int mPackagetype;
    private PackageManager mPackageManager;
    private Context mContext;
    private CallScreeningServiceConnection mConnection;
    private final CallsManager mCallsManager;
    private CharSequence mAppName;
    private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter;

    private class CallScreeningAdapter extends ICallScreeningAdapter.Stub {
        private CompletableFuture<CallFilteringResult> mResultFuture;

        public CallScreeningAdapter(CompletableFuture<CallFilteringResult> resultFuture) {
            mResultFuture = resultFuture;
        }

        @Override
        public void allowCall(String callId) {
            Long token = Binder.clearCallingIdentity();
            if (mCall == null || (!mCall.getId().equals(callId))) {
                Log.w(this, "allowCall, unknown call id: %s", callId);
            }
            mResultFuture.complete(DEFAULT_RESULT);
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
        }

        @Override
        public void disallowCall(String callId, boolean shouldReject,
                boolean shouldAddToCallLog, boolean shouldShowNotification,
                ComponentName componentName) {
            long token = Binder.clearCallingIdentity();
            if (mCall != null && mCall.getId().equals(callId)) {
                mResultFuture.complete(new CallFilteringResult.Builder()
                        .setShouldAllowCall(false)
                        .setShouldReject(shouldReject)
                        .setShouldSilence(false)
                        .setShouldAddToCallLog(shouldAddToCallLog
                                || packageTypeShouldAdd(mPackagetype))
                        .setShouldShowNotification(shouldShowNotification)
                        .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
                        .setCallScreeningAppName(mAppName)
                        .setCallScreeningComponentName(componentName.flattenToString())
                        .build());
            } else {
                Log.w(this, "disallowCall, unknown call id: %s", callId);
                mResultFuture.complete(DEFAULT_RESULT);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
        }

        @Override
        public void silenceCall(String callId) {
            long token = Binder.clearCallingIdentity();
            if (mCall != null && mCall.getId().equals(callId)) {
                mResultFuture.complete(new CallFilteringResult.Builder()
                        .setShouldAllowCall(true)
                        .setShouldReject(false)
                        .setShouldSilence(true)
                        .setShouldAddToCallLog(true)
                        .setShouldShowNotification(true)
                        .build());
            } else {
                Log.w(this, "silenceCall, unknown call id: %s" , callId);
                mResultFuture.complete(DEFAULT_RESULT);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
        }

        @Override
        public void screenCallFurther(String callId) {
            long token = Binder.clearCallingIdentity();
            if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
                throw new SecurityException("Only the default/system dialer may request screen via"
                    + "background call audio");
            }
            // TODO: add permission check for the additional role-based permission

            if (mCall != null && mCall.getId().equals(callId)) {
                mResultFuture.complete(new CallFilteringResult.Builder()
                        .setShouldAllowCall(true)
                        .setShouldReject(false)
                        .setShouldSilence(false)
                        .setShouldScreenViaAudio(true)
                        .build());
            } else {
                Log.w(this, "screenCallFurther, unknown call id: %s", callId);
                mResultFuture.complete(DEFAULT_RESULT);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
        }
    }

    private class CallScreeningServiceConnection implements ServiceConnection {
        private CompletableFuture<CallFilteringResult> mResultFuture;

        public CallScreeningServiceConnection(CompletableFuture<CallFilteringResult> resultFuture) {
            mResultFuture = resultFuture;
        }

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            ICallScreeningService callScreeningService =
                    ICallScreeningService.Stub.asInterface(service);

            try {
                callScreeningService.screenCall(new CallScreeningAdapter(mResultFuture),
                        mParcelableCallUtilsConverter.
                                toParcelableCallForScreening(mCall, isSystemDialer()));
            } catch (RemoteException e) {
                Log.e(this, e, "Failed to set the call screening adapter");
                mResultFuture.complete(DEFAULT_RESULT);
            }
            Log.i(this, "Binding completed.");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mResultFuture.complete(DEFAULT_RESULT);
            Log.i(this, "Service disconnected.");
        }

        @Override
        public void onBindingDied(ComponentName name) {
            mResultFuture.complete(DEFAULT_RESULT);
            Log.i(this, "Binding died.");
        }

        @Override
        public void onNullBinding(ComponentName name) {
            mResultFuture.complete(DEFAULT_RESULT);
            Log.i(this, "Null binding.");
        }
    }

    public NewCallScreeningServiceFilter(
            Call call,
            String packageName,
            int packageType,
            Context context,
            CallsManager callsManager,
            CallScreeningServiceHelper.AppLabelProxy appLabelProxy,
            ParcelableCallUtils.Converter parcelableCallUtilsConverter) {
        super();
        mCall = call;
        mPackageName = packageName;
        mPackagetype = packageType;
        mContext = context;
        mPackageManager = mContext.getPackageManager();
        mCallsManager = callsManager;
        mAppName = appLabelProxy.getAppLabel(mPackageName);
        mParcelableCallUtilsConverter = parcelableCallUtilsConverter;
    }

    @Override
    public CompletionStage<CallFilteringResult> startFilterLookup(CallFilteringResult priorStageResult) {
        if (mPackageName == null) {
            return CompletableFuture.completedFuture(DEFAULT_RESULT);
        }

        if (!priorStageResult.shouldAllowCall) {
            // Call already blocked by other filters, no need to bind to call screening service.
            return CompletableFuture.completedFuture(DEFAULT_RESULT);
        }

        if (priorStageResult.contactExists && (!hasReadContactsPermission())) {
            // Binding to the call screening service will be skipped if it does NOT hold
            // READ_CONTACTS permission and the number is in the user’s contacts
            return CompletableFuture.completedFuture(DEFAULT_RESULT);
        }

        CompletableFuture<CallFilteringResult> resultFuture = new CompletableFuture<>();

        bindCallScreeningService(resultFuture);
        return resultFuture;
    }

    private boolean hasReadContactsPermission() {
        int permission = PackageManager.PERMISSION_DENIED;
        if (mPackagetype == PACKAGE_TYPE_CARRIER || mPackagetype == PACKAGE_TYPE_DEFAULT_DIALER) {
            permission = PackageManager.PERMISSION_GRANTED;
        } else if (mPackageManager != null) {
            permission = mPackageManager.checkPermission(Manifest.permission.READ_CONTACTS,
                    mPackageName);
        }
        return permission == PackageManager.PERMISSION_GRANTED;
    }

    private void bindCallScreeningService(
            CompletableFuture<CallFilteringResult> resultFuture) {
        mConnection = new CallScreeningServiceConnection(resultFuture);
        if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
                mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
            Log.i(this, "Call screening service binding failed.");
            resultFuture.complete(DEFAULT_RESULT);
        }
    }

    private void unbindCallScreeningService() {
        if (mConnection != null) {
            mContext.unbindService(mConnection);
        }
        mConnection = null;
    }

    private boolean isSystemDialer() {
        if (mPackagetype != PACKAGE_TYPE_DEFAULT_DIALER) {
            return false;
        } else {
            return mPackageName.equals(TelecomManager.from(mContext).getSystemDialerPackage());
        }
    }

    private boolean packageTypeShouldAdd(int packageType) {
        return packageType == PACKAGE_TYPE_CARRIER;
    }

}
+320 −0

File added.

Preview size limit exceeded, changes collapsed.