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

Commit 67d34fa0 authored by Hall Liu's avatar Hall Liu
Browse files

Add classes/tests for parallel call-filtering lookup

Adds the IncomingCallFilter class, which serves as a controller for the
call-filtering operations. Also adds DirectToVoicemailCallFilter, which
is an implementation of the CallFilter interface defined in
IncomingCallFilter.

No changes are made to existing functionality. Those will be coming in
a future CL.

Bug: 26883888
Change-Id: Idf6662a9e71de60a87d1fc6b6b148fe9a2b12a8e
parent c4492b7e
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.server.telecom.Call;

public interface CallFilterResultCallback {
    void onCallFilteringComplete(Call call, CallFilteringResult result);
}
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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;

public class CallFilteringResult {
    public boolean shouldAllowCall;
    public boolean shouldReject;
    public boolean shouldAddToCallLog;
    public boolean shouldShowNotification;

    public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
            shouldAddToCallLog, boolean shouldShowNotification) {
        this.shouldAllowCall = shouldAllowCall;
        this.shouldReject = shouldReject;
        this.shouldAddToCallLog = shouldAddToCallLog;
        this.shouldShowNotification = shouldShowNotification;
    }

    /**
     * Combine this CallFilteringResult with another, returning a CallFilteringResult with
     * the more restrictive properties of the two.
     */
    public CallFilteringResult combine(CallFilteringResult other) {
        if (other == null) {
            return this;
        }

        return new CallFilteringResult(
                shouldAllowCall && other.shouldAllowCall,
                shouldReject || other.shouldReject,
                shouldAddToCallLog && other.shouldAddToCallLog,
                shouldShowNotification && other.shouldShowNotification);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CallFilteringResult that = (CallFilteringResult) o;

        if (shouldAllowCall != that.shouldAllowCall) return false;
        if (shouldReject != that.shouldReject) return false;
        if (shouldAddToCallLog != that.shouldAddToCallLog) return false;
        return shouldShowNotification == that.shouldShowNotification;
    }

    @Override
    public int hashCode() {
        int result = (shouldAllowCall ? 1 : 0);
        result = 31 * result + (shouldReject ? 1 : 0);
        result = 31 * result + (shouldAddToCallLog ? 1 : 0);
        result = 31 * result + (shouldShowNotification ? 1 : 0);
        return result;
    }
}
+70 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 android.net.Uri;

import com.android.internal.telephony.CallerInfo;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.Log;

public class DirectToVoicemailCallFilter implements IncomingCallFilter.CallFilter {
    private final CallerInfoLookupHelper mCallerInfoLookupHelper;

    public DirectToVoicemailCallFilter(CallerInfoLookupHelper callerInfoLookupHelper) {
        mCallerInfoLookupHelper = callerInfoLookupHelper;
    }

    @Override
    public void startFilterLookup(final Call call, CallFilterResultCallback callback) {
        final Uri callHandle = call.getHandle();
        mCallerInfoLookupHelper.startLookup(callHandle,
                new CallerInfoLookupHelper.OnQueryCompleteListener() {
                    @Override
                    public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) {
                        if (callHandle.equals(handle)) {
                            if (info.shouldSendToVoicemail) {
                                callback.onCallFilteringComplete(call,
                                        new CallFilteringResult(
                                                false, // shouldAllowCall
                                                true, // shouldReject
                                                true, // shouldAddToCallLog
                                                true // shouldShowNotification
                                        ));
                            } else {
                                callback.onCallFilteringComplete(call,
                                        new CallFilteringResult(
                                                true, // shouldAllowCall
                                                false, // shouldReject
                                                true, // shouldAddToCallLog
                                                true // shouldShowNotification
                                        ));
                            }
                        } else {
                            Log.w(this, "CallerInfo lookup returned with a different handle than " +
                                    "what was passed in. Was %s, should be %s", handle, callHandle);
                        }
                    }

                    @Override
                    public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) {
                        // ignore
                    }
                });
    }
}
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.Call;
import com.android.server.telecom.Log;
import com.android.server.telecom.Runnable;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;

import java.util.List;

public class IncomingCallFilter implements CallFilterResultCallback {

    public interface CallFilter {
        void startFilterLookup(Call call, CallFilterResultCallback listener);
    }

    private final TelecomSystem.SyncRoot mLock;
    private final Context mContext;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final List<CallFilter> mFilters;
    private final Call mCall;
    private final CallFilterResultCallback mListener;

    private CallFilteringResult mResult = new CallFilteringResult(
            true, // shouldAllowCall
            false, // shouldReject
            true, // shouldAddToCallLog
            true // shouldShowNotification
    );

    private boolean mIsPending = true;
    private int mNumPendingFilters;

    public IncomingCallFilter(Context context, CallFilterResultCallback listener, Call call,
            TelecomSystem.SyncRoot lock, List<CallFilter> filters) {
        mContext = context;
        mListener = listener;
        mCall = call;
        mLock = lock;
        mFilters = filters;
        mNumPendingFilters = filters.size();
    }

    public void performFiltering() {
        for (CallFilter filter : mFilters) {
            filter.startFilterLookup(mCall, this);
        }
        mHandler.postDelayed(new Runnable("ICF.pFTO") { // performFiltering time-out
            @Override
            public void loggedRun() {
                synchronized (mLock) { // synchronized to prevent a race on mResult
                    if (mIsPending) {
                        Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
                        mListener.onCallFilteringComplete(mCall, mResult);
                        mIsPending = false;
                    }
                }
            }
        }.prepare(), Timeouts.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
    }

    public void onCallFilteringComplete(Call call, CallFilteringResult result) {
        synchronized (mLock) {
            mNumPendingFilters--;
            mResult = result.combine(mResult);
            if (mNumPendingFilters == 0) {
                mHandler.post(new Runnable("ICF.oCFC") {
                    @Override
                    public void loggedRun() {
                        if (mIsPending) {
                            mListener.onCallFilteringComplete(mCall, mResult);
                            mIsPending = false;
                        }
                    }
                }.prepare());
            }
        }
    }

    /**
     * Returns the handler, for testing purposes.
     */
    @VisibleForTesting
    public Handler getHandler() {
        return mHandler;
    }
}
+91 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.tests;

import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.CallerInfo;
import com.android.server.telecom.Call;
import com.android.server.telecom.callfiltering.CallFilterResultCallback;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.callfiltering.CallFilteringResult;
import com.android.server.telecom.callfiltering.DirectToVoicemailCallFilter;

import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class DirectToVoicemailCallFilterTest extends TelecomTestCase {
    @Mock private CallerInfoLookupHelper mCallerInfoLookupHelper;
    @Mock private CallFilterResultCallback mCallback;
    @Mock private Call mCall;

    private static final Uri TEST_HANDLE = Uri.parse("tel:1235551234");

    public void setUp() throws Exception {
        super.setUp();
        when(mCall.getHandle()).thenReturn(TEST_HANDLE);
    }

    @SmallTest
    public void testSendToVoicemail() {
        CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();

        CallerInfo callerInfo = new CallerInfo();
        callerInfo.shouldSendToVoicemail = true;

        queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
        verify(mCallback).onCallFilteringComplete(mCall,
                new CallFilteringResult(
                        false, // shouldAllowCall
                        true, // shouldReject
                        true, // shouldAddToCallLog
                        true // shouldShowNotification
                ));
    }

    @SmallTest
    public void testDontSendToVoicemail() {
        CallerInfoLookupHelper.OnQueryCompleteListener queryListener = verifyLookupStart();

        CallerInfo callerInfo = new CallerInfo();
        callerInfo.shouldSendToVoicemail = false;

        queryListener.onCallerInfoQueryComplete(TEST_HANDLE, callerInfo);
        verify(mCallback).onCallFilteringComplete(mCall,
                new CallFilteringResult(
                        true, // shouldAllowCall
                        false, // shouldReject
                        true, // shouldAddToCallLog
                        true // shouldShowNotification
                ));
    }

    private CallerInfoLookupHelper.OnQueryCompleteListener verifyLookupStart() {
        DirectToVoicemailCallFilter filter =
                new DirectToVoicemailCallFilter(mCallerInfoLookupHelper);
        filter.startFilterLookup(mCall, mCallback);
        ArgumentCaptor<CallerInfoLookupHelper.OnQueryCompleteListener> captor =
                ArgumentCaptor.forClass(CallerInfoLookupHelper.OnQueryCompleteListener.class);
        verify(mCallerInfoLookupHelper).startLookup(eq(TEST_HANDLE), captor.capture());
        return captor.getValue();
    }
}
Loading