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

Commit b2449407 authored by Grace Jia's avatar Grace Jia
Browse files

Use IncomingCallFilterGraph to perform incoming call filters.

Bug: 135929421
Test: TelecomUnitTest, cts
Change-Id: Ia2a0d14ae94e77c1b637ffa2551a2493c710b847
parent 83b03309
Loading
Loading
Loading
Loading
+72 −14
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -34,6 +35,7 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.Process;
@@ -75,14 +77,15 @@ import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
import com.android.server.telecom.callfiltering.BlockCheckerFilter;
import com.android.server.telecom.callfiltering.CallFilterResultCallback;
import com.android.server.telecom.callfiltering.CallFilteringResult;
import com.android.server.telecom.callfiltering.CallFilteringResult.Builder;
import com.android.server.telecom.callfiltering.CallScreeningServiceController;
import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;
import com.android.server.telecom.callfiltering.DirectToVoicemailFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilter;
import com.android.server.telecom.callfiltering.IncomingCallFilterGraph;
import com.android.server.telecom.callfiltering.NewCallScreeningServiceFilter;
import com.android.server.telecom.callredirection.CallRedirectionProcessor;
import com.android.server.telecom.components.ErrorDialogActivity;
import com.android.server.telecom.settings.BlockedNumbersUtil;
@@ -92,13 +95,13 @@ import com.android.server.telecom.ui.CallRedirectionTimeoutDialogActivity;
import com.android.server.telecom.ui.ConfirmCallDialogActivity;
import com.android.server.telecom.ui.IncomingCallNotifier;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -358,6 +361,8 @@ public class CallsManager extends Call.ListenerBase

    private Runnable mStopTone;

    private LinkedList<HandlerThread> mGraphHandlerThreads;

    /**
     * Listener to PhoneAccountRegistrar events.
     */
@@ -548,6 +553,7 @@ public class CallsManager extends Call.ListenerBase
                CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        intentFilter.addAction(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED);
        context.registerReceiver(mReceiver, intentFilter);
        mGraphHandlerThreads = new LinkedList<>();
    }

    public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) {
@@ -631,14 +637,16 @@ public class CallsManager extends Call.ListenerBase
            return;
        }

        IncomingCallFilterGraph graph = setUpCallFilterGraph(incomingCall);
        graph.performFiltering();
    }

    private IncomingCallFilterGraph setUpCallFilterGraph(Call incomingCall) {
        incomingCall.setIsUsingCallFiltering(true);
        List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
        filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
        filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter(),
                mCallerInfoLookupHelper, null));
        filters.add(new CallScreeningServiceController(mContext, this, mPhoneAccountRegistrar,
                new ParcelableCallUtils.Converter(), mLock,
                new TelecomServiceImpl.SettingsSecureAdapterImpl(), mCallerInfoLookupHelper,
        String carrierPackageName = getCarrierPackageName();
        String defaultDialerPackageName = TelecomManager.from(mContext).getDefaultDialerPackage();
        String userChosenPackageName = getRoleManagerAdapter().getDefaultCallScreeningApp();
        CallScreeningServiceHelper.AppLabelProxy appLabelProxy =
                new CallScreeningServiceHelper.AppLabelProxy() {
                    @Override
                    public CharSequence getAppLabel(String packageName) {
@@ -652,9 +660,53 @@ public class CallsManager extends Call.ListenerBase

                        return null;
                    }
                }));
        mIncomingCallFilterFactory.create(mContext, this, incomingCall, mLock,
                mTimeoutsAdapter, filters).performFiltering();
                };
        ParcelableCallUtils.Converter converter = new ParcelableCallUtils.Converter();

        IncomingCallFilterGraph graph = new IncomingCallFilterGraph(incomingCall,
                this::onCallFilteringComplete, mContext, mTimeoutsAdapter, mLock);
        DirectToVoicemailFilter voicemailFilter = new DirectToVoicemailFilter(incomingCall,
                mCallerInfoLookupHelper);
        BlockCheckerFilter blockCheckerFilter = new BlockCheckerFilter(mContext, incomingCall,
                mCallerInfoLookupHelper, new BlockCheckerAdapter());
        NewCallScreeningServiceFilter carrierCallScreeningServiceFilter =
                new NewCallScreeningServiceFilter(incomingCall, carrierPackageName,
                        NewCallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, this,
                        appLabelProxy, converter);
        NewCallScreeningServiceFilter defaultDialerCallScreeningServiceFilter =
                new NewCallScreeningServiceFilter(incomingCall, defaultDialerPackageName,
                        NewCallScreeningServiceFilter.PACKAGE_TYPE_DEFAULT_DIALER, mContext, this,
                        appLabelProxy, converter);
        NewCallScreeningServiceFilter userChosenCallScreeningServiceFilter =
                new NewCallScreeningServiceFilter(incomingCall, userChosenPackageName,
                        NewCallScreeningServiceFilter.PACKAGE_TYPE_USER_CHOSEN, mContext, this,
                        appLabelProxy, converter);
        graph.addFilter(voicemailFilter);
        graph.addFilter(blockCheckerFilter);
        graph.addFilter(carrierCallScreeningServiceFilter);
        graph.addFilter(defaultDialerCallScreeningServiceFilter);
        graph.addFilter(userChosenCallScreeningServiceFilter);
        IncomingCallFilterGraph.addEdge(voicemailFilter, carrierCallScreeningServiceFilter);
        IncomingCallFilterGraph.addEdge(blockCheckerFilter, carrierCallScreeningServiceFilter);
        IncomingCallFilterGraph.addEdge(carrierCallScreeningServiceFilter,
                defaultDialerCallScreeningServiceFilter);
        IncomingCallFilterGraph.addEdge(carrierCallScreeningServiceFilter,
                userChosenCallScreeningServiceFilter);
        mGraphHandlerThreads.add(graph.getHandlerThread());
        return graph;
    }

    private String getCarrierPackageName() {
        ComponentName componentName = null;
        CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService
                (Context.CARRIER_CONFIG_SERVICE);
        PersistableBundle configBundle = configManager.getConfig();
        if (configBundle != null) {
            componentName = ComponentName.unflattenFromString(configBundle.getString
                    (CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, ""));
        }

        return componentName != null ? componentName.getPackageName() : null;
    }

    @Override
@@ -662,6 +714,8 @@ public class CallsManager extends Call.ListenerBase
        // Only set the incoming call as ringing if it isn't already disconnected. It is possible
        // that the connection service disconnected the call before it was even added to Telecom, in
        // which case it makes no sense to set it back to a ringing state.
        mGraphHandlerThreads.clear();

        if (incomingCall.getState() != CallState.DISCONNECTED &&
                incomingCall.getState() != CallState.DISCONNECTING) {
            setCallState(incomingCall, CallState.RINGING,
@@ -4778,4 +4832,8 @@ public class CallsManager extends Call.ListenerBase
                .filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount()))
                .forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported));
    }

    public LinkedList<HandlerThread> getGraphHandlerThreads() {
        return mGraphHandlerThreads;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -182,6 +182,7 @@ public class CallFilteringResult {
                .setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
                .setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
                .setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
                .setContactExists(contactExists || other.contactExists)
                .build();
    }

+10 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.telecom.Logging.Runnable;

import com.android.server.telecom.Call;
import com.android.server.telecom.LoggedHandlerExecutor;
import com.android.server.telecom.LogUtils;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;

@@ -62,6 +63,7 @@ public class IncomingCallFilterGraph {
        }

        public CallFilteringResult whenDone(CallFilteringResult result) {
            Log.i(TAG, "Filter %s done, result: %s.", mFilter, result);
            mFilter.result = result;
            for (CallFilter filter : mFilter.getFollowings()) {
                if (filter.decrementAndGetIndegree() == 0) {
@@ -72,6 +74,7 @@ public class IncomingCallFilterGraph {
                synchronized (mLock) {
                    mFinished = true;
                    mListener.onCallFilteringComplete(mCall, result);
                    Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, result);
                }
                mHandlerThread.quit();
            }
@@ -100,7 +103,7 @@ public class IncomingCallFilterGraph {
    }

    public void performFiltering() {

        Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);
        CallFilter dummyStart = new CallFilter();
        mDummyComplete = new CallFilter();

@@ -118,6 +121,7 @@ public class IncomingCallFilterGraph {
            public void loggedRun() {
                if (!mFinished) {
                    Log.i(this, "Graph timed out when performing filtering.");
                    Log.addEvent(mCall, LogUtils.Events.FILTERING_TIMED_OUT);
                    mListener.onCallFilteringComplete(mCall, mCurrentResult);
                    mFinished = true;
                    mHandlerThread.quit();
@@ -148,10 +152,15 @@ public class IncomingCallFilterGraph {
                new LoggedHandlerExecutor(mHandler, "ICFG.sF", null))
                .thenApplyAsync(postFilterTask::whenDone,
                        new LoggedHandlerExecutor(mHandler, "ICFG.sF", null));
        Log.i(TAG, "Filter %s scheduled.", filter);
    }

    public static void addEdge(CallFilter before, CallFilter after) {
        before.addFollowings(after);
        after.addDependency(before);
    }

    public HandlerThread getHandlerThread() {
        return mHandlerThread;
    }
}
+19 −17
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

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;
@@ -70,7 +68,7 @@ public class NewCallScreeningServiceFilter extends CallFilter {
            if (mCall == null || (!mCall.getId().equals(callId))) {
                Log.w(this, "allowCall, unknown call id: %s", callId);
            }
            mResultFuture.complete(DEFAULT_RESULT);
            mResultFuture.complete(mPriorStageResult);
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
        }
@@ -91,10 +89,11 @@ public class NewCallScreeningServiceFilter extends CallFilter {
                        .setCallBlockReason(CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE)
                        .setCallScreeningAppName(mAppName)
                        .setCallScreeningComponentName(componentName.flattenToString())
                        .setContactExists(mPriorStageResult.contactExists)
                        .build());
            } else {
                Log.w(this, "disallowCall, unknown call id: %s", callId);
                mResultFuture.complete(DEFAULT_RESULT);
                mResultFuture.complete(mPriorStageResult);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
@@ -110,10 +109,11 @@ public class NewCallScreeningServiceFilter extends CallFilter {
                        .setShouldSilence(true)
                        .setShouldAddToCallLog(true)
                        .setShouldShowNotification(true)
                        .setContactExists(mPriorStageResult.contactExists)
                        .build());
            } else {
                Log.w(this, "silenceCall, unknown call id: %s" , callId);
                mResultFuture.complete(DEFAULT_RESULT);
                mResultFuture.complete(mPriorStageResult);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
@@ -134,10 +134,11 @@ public class NewCallScreeningServiceFilter extends CallFilter {
                        .setShouldReject(false)
                        .setShouldSilence(false)
                        .setShouldScreenViaAudio(true)
                        .setContactExists(mPriorStageResult.contactExists)
                        .build());
            } else {
                Log.w(this, "screenCallFurther, unknown call id: %s", callId);
                mResultFuture.complete(DEFAULT_RESULT);
                mResultFuture.complete(mPriorStageResult);
            }
            Binder.restoreCallingIdentity(token);
            unbindCallScreeningService();
@@ -162,26 +163,26 @@ public class NewCallScreeningServiceFilter extends CallFilter {
                                toParcelableCallForScreening(mCall, isSystemDialer()));
            } catch (RemoteException e) {
                Log.e(this, e, "Failed to set the call screening adapter");
                mResultFuture.complete(DEFAULT_RESULT);
                mResultFuture.complete(mPriorStageResult);
            }
            Log.i(this, "Binding completed.");
        }

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

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

        @Override
        public void onNullBinding(ComponentName name) {
            mResultFuture.complete(DEFAULT_RESULT);
            mResultFuture.complete(mPriorStageResult);
            Log.i(this, "Null binding.");
        }
    }
@@ -206,20 +207,22 @@ public class NewCallScreeningServiceFilter extends CallFilter {
    }

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

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

        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);
            return CompletableFuture.completedFuture(priorStageResult);
        }

        CompletableFuture<CallFilteringResult> resultFuture = new CompletableFuture<>();
@@ -245,7 +248,7 @@ public class NewCallScreeningServiceFilter extends CallFilter {
        if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
                mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
            Log.i(this, "Call screening service binding failed.");
            resultFuture.complete(DEFAULT_RESULT);
            resultFuture.complete(mPriorStageResult);
        }
    }

@@ -265,7 +268,6 @@ public class NewCallScreeningServiceFilter extends CallFilter {
    }

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

}
+7 −4
Original line number Diff line number Diff line
@@ -21,14 +21,12 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -78,14 +76,12 @@ import com.android.server.telecom.CallsManagerListenerBase;
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ContactsAsyncHelper;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.HeadsetMediaButton;
import com.android.server.telecom.HeadsetMediaButtonFactory;
import com.android.server.telecom.InCallWakeLockController;
import com.android.server.telecom.InCallWakeLockControllerFactory;
import com.android.server.telecom.MissedCallNotifier;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
import com.android.server.telecom.ProximitySensorManager;
import com.android.server.telecom.ProximitySensorManagerFactory;
@@ -111,6 +107,7 @@ import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -377,6 +374,12 @@ public class TelecomSystemTest extends TelecomTestCase {
    @Override
    public void tearDown() throws Exception {
        mTelecomSystem.getCallsManager().waitOnHandlers();
        LinkedList<HandlerThread> handlerThreads = mTelecomSystem.getCallsManager()
                .getGraphHandlerThreads();
        for (HandlerThread handlerThread : handlerThreads) {
            handlerThread.quitSafely();
        }
        handlerThreads.clear();
        waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
        waitForHandlerAction(mHandlerThread.getThreadHandler(), TEST_TIMEOUT);
        // Bring down the threads that are active.