Merge "Use IncomingCallFilterGraph to perform incoming call filters." am: 482556f24a am: 40dba6c807
am: 464e671f7b
Change-Id: If2e4afdce1c3c54788a8dc3caac2a6b0f96cd527
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 31396db..230e890 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -20,6 +20,7 @@
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.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;
@@ -74,14 +76,15 @@
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;
@@ -91,13 +94,13 @@
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;
@@ -357,6 +360,8 @@
private Runnable mStopTone;
+ private LinkedList<HandlerThread> mGraphHandlerThreads;
+
/**
* Listener to PhoneAccountRegistrar events.
*/
@@ -547,6 +552,7 @@
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) {
@@ -630,14 +636,16 @@
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) {
@@ -651,9 +659,53 @@
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
@@ -661,6 +713,8 @@
// 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,
@@ -4768,4 +4822,8 @@
.filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount()))
.forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported));
}
+
+ public LinkedList<HandlerThread> getGraphHandlerThreads() {
+ return mGraphHandlerThreads;
+ }
}
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index 3f64f2c..44d5708 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -182,6 +182,7 @@
.setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
.setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
.setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
+ .setContactExists(contactExists || other.contactExists)
.build();
}
diff --git a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
index b39854c..03d27bd 100644
--- a/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
+++ b/src/com/android/server/telecom/callfiltering/IncomingCallFilterGraph.java
@@ -24,6 +24,7 @@
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 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 @@
synchronized (mLock) {
mFinished = true;
mListener.onCallFilteringComplete(mCall, result);
+ Log.addEvent(mCall, LogUtils.Events.FILTERING_COMPLETED, result);
}
mHandlerThread.quit();
}
@@ -100,7 +103,7 @@
}
public void performFiltering() {
-
+ Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);
CallFilter dummyStart = new CallFilter();
mDummyComplete = new CallFilter();
@@ -118,6 +121,7 @@
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 @@
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;
+ }
}
diff --git a/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java
index aa81a49..80996e5 100644
--- a/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/NewCallScreeningServiceFilter.java
@@ -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 @@
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 @@
.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 @@
.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 @@
.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 @@
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 @@
}
@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 @@
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 @@
}
private boolean packageTypeShouldAdd(int packageType) {
- return packageType == PACKAGE_TYPE_CARRIER;
+ return packageType != PACKAGE_TYPE_CARRIER;
}
-
}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 4fc9ed6..cfc530d 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -21,14 +21,12 @@
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.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 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 @@
@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.