Loading src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.javadeleted 100644 → 0 +0 −180 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.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.BlockedNumberContract; import android.provider.CallLog; import android.telecom.Log; import android.telecom.Logging.Session; import android.telecom.TelecomManager; import android.telecom.CallerInfo; import com.android.server.telecom.Call; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.LogUtils; import com.android.server.telecom.callfiltering.CallFilteringResult.Builder; import com.android.server.telecom.settings.BlockedNumbersUtil; /** * An {@link AsyncTask} that checks if a call needs to be blocked. * <p> An {@link AsyncTask} is used to perform the block check to avoid blocking the main thread. * The block check itself is performed in the {@link AsyncTask#doInBackground(Object[])}. */ public class AsyncBlockCheckFilter extends AsyncTask<String, Void, Boolean> implements IncomingCallFilter.CallFilter { private final Context mContext; private final BlockCheckerAdapter mBlockCheckerAdapter; private final CallBlockListener mCallBlockListener; private Call mIncomingCall; private Session mBackgroundTaskSubsession; private Session mPostExecuteSubsession; private CallFilterResultCallback mCallback; private CallerInfoLookupHelper mCallerInfoLookupHelper; private int mBlockStatus = BlockedNumberContract.STATUS_NOT_BLOCKED; public AsyncBlockCheckFilter(Context context, BlockCheckerAdapter blockCheckerAdapter, CallerInfoLookupHelper callerInfoLookupHelper, CallBlockListener callBlockListener) { mContext = context; mBlockCheckerAdapter = blockCheckerAdapter; mCallerInfoLookupHelper = callerInfoLookupHelper; mCallBlockListener = callBlockListener; } @Override public void startFilterLookup(Call call, CallFilterResultCallback callback) { mCallback = callback; mIncomingCall = call; String number = call.getHandle() == null ? null : call.getHandle().getSchemeSpecificPart(); if (BlockedNumbersUtil.isEnhancedCallBlockingEnabledByPlatform(mContext)) { int presentation = mIncomingCall.getHandlePresentation(); if (presentation == TelecomManager.PRESENTATION_ALLOWED) { mCallerInfoLookupHelper.startLookup(call.getHandle(), new CallerInfoLookupHelper.OnQueryCompleteListener() { @Override public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { boolean contactExists = info == null ? false : info.contactExists; execute(number, String.valueOf(presentation), String.valueOf(contactExists)); } @Override public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { // ignore } }); } else { this.execute(number, String.valueOf(presentation)); } } else { this.execute(number); } } @Override protected void onPreExecute() { mBackgroundTaskSubsession = Log.createSubsession(); mPostExecuteSubsession = Log.createSubsession(); } @Override protected Boolean doInBackground(String... params) { try { Log.continueSession(mBackgroundTaskSubsession, "ABCF.dIB"); Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_INITIATED); Bundle extras = new Bundle(); if (params.length > 1) { extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION, Integer.valueOf(params[1])); } if (params.length > 2) { extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST, Boolean.valueOf(params[2])); } mBlockStatus = mBlockCheckerAdapter.getBlockStatus(mContext, params[0], extras); return mBlockStatus != BlockedNumberContract.STATUS_NOT_BLOCKED; } finally { Log.endSession(); } } @Override protected void onPostExecute(Boolean isBlocked) { Log.continueSession(mPostExecuteSubsession, "ABCF.oPE"); try { CallFilteringResult result; if (isBlocked) { result = new Builder() .setShouldAllowCall(false) .setShouldReject(true) .setShouldAddToCallLog(true) .setShouldShowNotification(false) .setCallBlockReason(convertBlockStatusToReason()) .setCallScreeningAppName(null) .setCallScreeningComponentName(null) .build(); if (mCallBlockListener != null) { String number = mIncomingCall.getHandle() == null ? null : mIncomingCall.getHandle().getSchemeSpecificPart(); mCallBlockListener.onCallBlocked(mBlockStatus, number, mIncomingCall.getInitiatingUser()); } } else { result = new Builder() .setShouldAllowCall(true) .setShouldReject(false) .setShouldAddToCallLog(true) .setShouldShowNotification(true) .build(); } Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_FINISHED, BlockedNumberContract.SystemContract.blockStatusToString(mBlockStatus) + " " + result); mCallback.onCallFilteringComplete(mIncomingCall, result); } finally { Log.endSession(); } } private int convertBlockStatusToReason() { switch (mBlockStatus) { case BlockedNumberContract.STATUS_BLOCKED_IN_LIST: return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER: return CallLog.Calls.BLOCK_REASON_UNKNOWN_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED: return CallLog.Calls.BLOCK_REASON_RESTRICTED_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_PAYPHONE: return CallLog.Calls.BLOCK_REASON_PAY_PHONE; case BlockedNumberContract.STATUS_BLOCKED_NOT_IN_CONTACTS: return CallLog.Calls.BLOCK_REASON_NOT_IN_CONTACTS; default: Log.w(AsyncBlockCheckFilter.class.getSimpleName(), "There's no call log block reason can be converted"); return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER; } } } src/com/android/server/telecom/callfiltering/CallFilteringResult.java +2 −2 Original line number Diff line number Diff line Loading @@ -135,8 +135,8 @@ public class CallFilteringResult { /** * Combine this CallFilteringResult with another, returning a CallFilteringResult with the more * restrictive properties of the two. Where there are multiple call filtering components which * block a call, the first filter from {@link AsyncBlockCheckFilter}, * {@link DirectToVoicemailCallFilter}, {@link CallScreeningServiceFilter} which blocked a call * block a call, the first filter from {@link BlockCheckerFilter}, * {@link DirectToVoicemailFilter}, {@link NewCallScreeningServiceFilter} which blocked a call * shall be used to populate the call block reason, component name, etc. */ public CallFilteringResult combine(CallFilteringResult other) { Loading src/com/android/server/telecom/callfiltering/CallScreeningServiceController.javadeleted 100644 → 0 +0 −283 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.ComponentName; import android.content.Context; import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.PersistableBundle; import android.provider.CallLog; import android.telecom.Log; import android.telecom.Logging.Runnable; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.text.TextUtils; import android.telecom.CallerInfo; import com.android.server.telecom.AppLabelProxy; import com.android.server.telecom.Call; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.CallsManager; import com.android.server.telecom.LogUtils; import com.android.server.telecom.ParcelableCallUtils; import com.android.server.telecom.PhoneAccountRegistrar; import com.android.server.telecom.TelecomServiceImpl; import com.android.server.telecom.TelecomSystem; import com.android.server.telecom.callfiltering.CallFilteringResult.Builder; /** * This class supports binding to the various {@link android.telecom.CallScreeningService}: * carrier, default dialer and user chosen. Carrier's CallScreeningService implementation will be * bound first, and then default dialer's and user chosen's. If Carrier's CallScreeningService * blocks a call, no further CallScreeningService after it will be bound. */ public class CallScreeningServiceController implements IncomingCallFilter.CallFilter, CallScreeningServiceFilter.CallScreeningFilterResultCallback { private final Context mContext; private final CallsManager mCallsManager; private final PhoneAccountRegistrar mPhoneAccountRegistrar; private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter; private final TelecomSystem.SyncRoot mTelecomLock; private final TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter; private final CallerInfoLookupHelper mCallerInfoLookupHelper; private final AppLabelProxy mAppLabelProxy; private final int CARRIER_CALL_FILTERING_TIMED_OUT = 2000; // 2 seconds private final int CALL_FILTERING_TIMED_OUT = 4500; // 4.5 seconds private final Handler mHandler = new Handler(Looper.getMainLooper()); private Call mCall; private CallFilterResultCallback mCallback; private CallFilteringResult mResult = new Builder() .setShouldAllowCall(true) .setShouldReject(false) .setShouldAddToCallLog(true) .setShouldShowNotification(true) .build(); private boolean mIsFinished; private boolean mIsCarrierFinished; private boolean mIsDefaultDialerFinished; private boolean mIsUserChosenFinished; public CallScreeningServiceController( Context context, CallsManager callsManager, PhoneAccountRegistrar phoneAccountRegistrar, ParcelableCallUtils.Converter parcelableCallUtilsConverter, TelecomSystem.SyncRoot lock, TelecomServiceImpl.SettingsSecureAdapter settingsSecureAdapter, CallerInfoLookupHelper callerInfoLookupHelper, AppLabelProxy appLabelProxy) { mContext = context; mCallsManager = callsManager; mPhoneAccountRegistrar = phoneAccountRegistrar; mParcelableCallUtilsConverter = parcelableCallUtilsConverter; mTelecomLock = lock; mSettingsSecureAdapter = settingsSecureAdapter; mCallerInfoLookupHelper = callerInfoLookupHelper; mAppLabelProxy = appLabelProxy; } @Override public void startFilterLookup(Call call, CallFilterResultCallback callBack) { mCall = call; mCallback = callBack; mIsFinished = false; mIsCarrierFinished = false; mIsDefaultDialerFinished = false; mIsUserChosenFinished = false; bindCarrierService(); // Call screening filtering timed out mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { @Override public void loggedRun() { if (!mIsFinished) { Log.i(CallScreeningServiceController.this, "Call screening has timed out."); finishCallScreening(); } } }.prepare(), CALL_FILTERING_TIMED_OUT); } @Override public void onCallScreeningFilterComplete(Call call, CallFilteringResult result, String packageName) { synchronized (mTelecomLock) { mResult = result.combine(mResult); if (!TextUtils.isEmpty(packageName) && packageName.equals(getCarrierPackageName())) { mIsCarrierFinished = true; if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE) { finishCallScreening(); } else { checkContactExistsAndBindService(); } } else if (!TextUtils.isEmpty(packageName) && packageName.equals(getDefaultDialerPackageName())) { // Default dialer defined CallScreeningService cannot skip the call log. mResult.shouldAddToCallLog = true; mIsDefaultDialerFinished = true; if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE || mIsUserChosenFinished) { finishCallScreening(); } } else if (!TextUtils.isEmpty(packageName) && packageName.equals(getUserChosenPackageName())) { // User defined CallScreeningService cannot skip the call log. mResult.shouldAddToCallLog = true; mIsUserChosenFinished = true; if (mIsDefaultDialerFinished) { finishCallScreening(); } } } } private void bindCarrierService() { String carrierPackageName = getCarrierPackageName(); if (TextUtils.isEmpty(carrierPackageName)) { mIsCarrierFinished = true; bindDefaultDialerAndUserChosenService(); } else { createCallScreeningServiceFilter().startCallScreeningFilter(mCall, this, carrierPackageName, mAppLabelProxy.getAppLabel(carrierPackageName), CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_CARRIER); } // Carrier filtering timed out mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { @Override public void loggedRun() { if (!mIsCarrierFinished) { mIsCarrierFinished = true; checkContactExistsAndBindService(); } } }.prepare(), CARRIER_CALL_FILTERING_TIMED_OUT); } private void bindDefaultDialerAndUserChosenService() { if (mIsCarrierFinished) { String dialerPackageName = getDefaultDialerPackageName(); String systemDialerPackageName = getSystemDialerPackageName(); if (TextUtils.isEmpty(dialerPackageName)) { mIsDefaultDialerFinished = true; } else { int dialerType = dialerPackageName.equals(systemDialerPackageName) ? CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_SYSTEM_DIALER : CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_DEFAULT_DIALER; createCallScreeningServiceFilter().startCallScreeningFilter(mCall, CallScreeningServiceController.this, dialerPackageName, mAppLabelProxy.getAppLabel(dialerPackageName), dialerType); } String userChosenPackageName = getUserChosenPackageName(); if (TextUtils.isEmpty(userChosenPackageName)) { mIsUserChosenFinished = true; } else { // If the user chosen call screening service is the same as the default dialer, then // we have already bound to it above and don't need to do so again here. if (userChosenPackageName.equals(dialerPackageName)) { Log.addEvent(mCall, LogUtils.Events.SCREENING_SKIPPED, "user pkg same as dialer: " + userChosenPackageName); mIsUserChosenFinished = true; } else { createCallScreeningServiceFilter().startCallScreeningFilter(mCall, CallScreeningServiceController.this, userChosenPackageName, mAppLabelProxy.getAppLabel(userChosenPackageName), CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED); } } if (mIsDefaultDialerFinished && mIsUserChosenFinished) { finishCallScreening(); } } } private CallScreeningServiceFilter createCallScreeningServiceFilter() { return new CallScreeningServiceFilter( mContext, mCallsManager, mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mTelecomLock, mSettingsSecureAdapter); } private void checkContactExistsAndBindService() { mCallerInfoLookupHelper.startLookup(mCall.getHandle(), new CallerInfoLookupHelper.OnQueryCompleteListener() { @Override public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { boolean contactExists = info != null && info.contactExists; Log.i(CallScreeningServiceController.this, "Contact exists: " + contactExists); if (!contactExists) { bindDefaultDialerAndUserChosenService(); } else { finishCallScreening(); } } @Override public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { // ignore } }); } private void finishCallScreening() { Log.addEvent(mCall, LogUtils.Events.CONTROLLER_SCREENING_COMPLETED, mResult); mCallback.onCallFilteringComplete(mCall, mResult); mIsFinished = true; } 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; } private String getDefaultDialerPackageName() { return TelecomManager.from(mContext).getDefaultDialerPackage(); } private String getSystemDialerPackageName() { return TelecomManager.from(mContext).getSystemDialerPackage(); } private String getUserChosenPackageName() { return mCallsManager.getRoleManagerAdapter().getDefaultCallScreeningApp(); } } Loading
src/com/android/server/telecom/callfiltering/AsyncBlockCheckFilter.javadeleted 100644 → 0 +0 −180 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.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.BlockedNumberContract; import android.provider.CallLog; import android.telecom.Log; import android.telecom.Logging.Session; import android.telecom.TelecomManager; import android.telecom.CallerInfo; import com.android.server.telecom.Call; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.LogUtils; import com.android.server.telecom.callfiltering.CallFilteringResult.Builder; import com.android.server.telecom.settings.BlockedNumbersUtil; /** * An {@link AsyncTask} that checks if a call needs to be blocked. * <p> An {@link AsyncTask} is used to perform the block check to avoid blocking the main thread. * The block check itself is performed in the {@link AsyncTask#doInBackground(Object[])}. */ public class AsyncBlockCheckFilter extends AsyncTask<String, Void, Boolean> implements IncomingCallFilter.CallFilter { private final Context mContext; private final BlockCheckerAdapter mBlockCheckerAdapter; private final CallBlockListener mCallBlockListener; private Call mIncomingCall; private Session mBackgroundTaskSubsession; private Session mPostExecuteSubsession; private CallFilterResultCallback mCallback; private CallerInfoLookupHelper mCallerInfoLookupHelper; private int mBlockStatus = BlockedNumberContract.STATUS_NOT_BLOCKED; public AsyncBlockCheckFilter(Context context, BlockCheckerAdapter blockCheckerAdapter, CallerInfoLookupHelper callerInfoLookupHelper, CallBlockListener callBlockListener) { mContext = context; mBlockCheckerAdapter = blockCheckerAdapter; mCallerInfoLookupHelper = callerInfoLookupHelper; mCallBlockListener = callBlockListener; } @Override public void startFilterLookup(Call call, CallFilterResultCallback callback) { mCallback = callback; mIncomingCall = call; String number = call.getHandle() == null ? null : call.getHandle().getSchemeSpecificPart(); if (BlockedNumbersUtil.isEnhancedCallBlockingEnabledByPlatform(mContext)) { int presentation = mIncomingCall.getHandlePresentation(); if (presentation == TelecomManager.PRESENTATION_ALLOWED) { mCallerInfoLookupHelper.startLookup(call.getHandle(), new CallerInfoLookupHelper.OnQueryCompleteListener() { @Override public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { boolean contactExists = info == null ? false : info.contactExists; execute(number, String.valueOf(presentation), String.valueOf(contactExists)); } @Override public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { // ignore } }); } else { this.execute(number, String.valueOf(presentation)); } } else { this.execute(number); } } @Override protected void onPreExecute() { mBackgroundTaskSubsession = Log.createSubsession(); mPostExecuteSubsession = Log.createSubsession(); } @Override protected Boolean doInBackground(String... params) { try { Log.continueSession(mBackgroundTaskSubsession, "ABCF.dIB"); Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_INITIATED); Bundle extras = new Bundle(); if (params.length > 1) { extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION, Integer.valueOf(params[1])); } if (params.length > 2) { extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST, Boolean.valueOf(params[2])); } mBlockStatus = mBlockCheckerAdapter.getBlockStatus(mContext, params[0], extras); return mBlockStatus != BlockedNumberContract.STATUS_NOT_BLOCKED; } finally { Log.endSession(); } } @Override protected void onPostExecute(Boolean isBlocked) { Log.continueSession(mPostExecuteSubsession, "ABCF.oPE"); try { CallFilteringResult result; if (isBlocked) { result = new Builder() .setShouldAllowCall(false) .setShouldReject(true) .setShouldAddToCallLog(true) .setShouldShowNotification(false) .setCallBlockReason(convertBlockStatusToReason()) .setCallScreeningAppName(null) .setCallScreeningComponentName(null) .build(); if (mCallBlockListener != null) { String number = mIncomingCall.getHandle() == null ? null : mIncomingCall.getHandle().getSchemeSpecificPart(); mCallBlockListener.onCallBlocked(mBlockStatus, number, mIncomingCall.getInitiatingUser()); } } else { result = new Builder() .setShouldAllowCall(true) .setShouldReject(false) .setShouldAddToCallLog(true) .setShouldShowNotification(true) .build(); } Log.addEvent(mIncomingCall, LogUtils.Events.BLOCK_CHECK_FINISHED, BlockedNumberContract.SystemContract.blockStatusToString(mBlockStatus) + " " + result); mCallback.onCallFilteringComplete(mIncomingCall, result); } finally { Log.endSession(); } } private int convertBlockStatusToReason() { switch (mBlockStatus) { case BlockedNumberContract.STATUS_BLOCKED_IN_LIST: return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER: return CallLog.Calls.BLOCK_REASON_UNKNOWN_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED: return CallLog.Calls.BLOCK_REASON_RESTRICTED_NUMBER; case BlockedNumberContract.STATUS_BLOCKED_PAYPHONE: return CallLog.Calls.BLOCK_REASON_PAY_PHONE; case BlockedNumberContract.STATUS_BLOCKED_NOT_IN_CONTACTS: return CallLog.Calls.BLOCK_REASON_NOT_IN_CONTACTS; default: Log.w(AsyncBlockCheckFilter.class.getSimpleName(), "There's no call log block reason can be converted"); return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER; } } }
src/com/android/server/telecom/callfiltering/CallFilteringResult.java +2 −2 Original line number Diff line number Diff line Loading @@ -135,8 +135,8 @@ public class CallFilteringResult { /** * Combine this CallFilteringResult with another, returning a CallFilteringResult with the more * restrictive properties of the two. Where there are multiple call filtering components which * block a call, the first filter from {@link AsyncBlockCheckFilter}, * {@link DirectToVoicemailCallFilter}, {@link CallScreeningServiceFilter} which blocked a call * block a call, the first filter from {@link BlockCheckerFilter}, * {@link DirectToVoicemailFilter}, {@link NewCallScreeningServiceFilter} which blocked a call * shall be used to populate the call block reason, component name, etc. */ public CallFilteringResult combine(CallFilteringResult other) { Loading
src/com/android/server/telecom/callfiltering/CallScreeningServiceController.javadeleted 100644 → 0 +0 −283 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.ComponentName; import android.content.Context; import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.PersistableBundle; import android.provider.CallLog; import android.telecom.Log; import android.telecom.Logging.Runnable; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.text.TextUtils; import android.telecom.CallerInfo; import com.android.server.telecom.AppLabelProxy; import com.android.server.telecom.Call; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.CallsManager; import com.android.server.telecom.LogUtils; import com.android.server.telecom.ParcelableCallUtils; import com.android.server.telecom.PhoneAccountRegistrar; import com.android.server.telecom.TelecomServiceImpl; import com.android.server.telecom.TelecomSystem; import com.android.server.telecom.callfiltering.CallFilteringResult.Builder; /** * This class supports binding to the various {@link android.telecom.CallScreeningService}: * carrier, default dialer and user chosen. Carrier's CallScreeningService implementation will be * bound first, and then default dialer's and user chosen's. If Carrier's CallScreeningService * blocks a call, no further CallScreeningService after it will be bound. */ public class CallScreeningServiceController implements IncomingCallFilter.CallFilter, CallScreeningServiceFilter.CallScreeningFilterResultCallback { private final Context mContext; private final CallsManager mCallsManager; private final PhoneAccountRegistrar mPhoneAccountRegistrar; private final ParcelableCallUtils.Converter mParcelableCallUtilsConverter; private final TelecomSystem.SyncRoot mTelecomLock; private final TelecomServiceImpl.SettingsSecureAdapter mSettingsSecureAdapter; private final CallerInfoLookupHelper mCallerInfoLookupHelper; private final AppLabelProxy mAppLabelProxy; private final int CARRIER_CALL_FILTERING_TIMED_OUT = 2000; // 2 seconds private final int CALL_FILTERING_TIMED_OUT = 4500; // 4.5 seconds private final Handler mHandler = new Handler(Looper.getMainLooper()); private Call mCall; private CallFilterResultCallback mCallback; private CallFilteringResult mResult = new Builder() .setShouldAllowCall(true) .setShouldReject(false) .setShouldAddToCallLog(true) .setShouldShowNotification(true) .build(); private boolean mIsFinished; private boolean mIsCarrierFinished; private boolean mIsDefaultDialerFinished; private boolean mIsUserChosenFinished; public CallScreeningServiceController( Context context, CallsManager callsManager, PhoneAccountRegistrar phoneAccountRegistrar, ParcelableCallUtils.Converter parcelableCallUtilsConverter, TelecomSystem.SyncRoot lock, TelecomServiceImpl.SettingsSecureAdapter settingsSecureAdapter, CallerInfoLookupHelper callerInfoLookupHelper, AppLabelProxy appLabelProxy) { mContext = context; mCallsManager = callsManager; mPhoneAccountRegistrar = phoneAccountRegistrar; mParcelableCallUtilsConverter = parcelableCallUtilsConverter; mTelecomLock = lock; mSettingsSecureAdapter = settingsSecureAdapter; mCallerInfoLookupHelper = callerInfoLookupHelper; mAppLabelProxy = appLabelProxy; } @Override public void startFilterLookup(Call call, CallFilterResultCallback callBack) { mCall = call; mCallback = callBack; mIsFinished = false; mIsCarrierFinished = false; mIsDefaultDialerFinished = false; mIsUserChosenFinished = false; bindCarrierService(); // Call screening filtering timed out mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { @Override public void loggedRun() { if (!mIsFinished) { Log.i(CallScreeningServiceController.this, "Call screening has timed out."); finishCallScreening(); } } }.prepare(), CALL_FILTERING_TIMED_OUT); } @Override public void onCallScreeningFilterComplete(Call call, CallFilteringResult result, String packageName) { synchronized (mTelecomLock) { mResult = result.combine(mResult); if (!TextUtils.isEmpty(packageName) && packageName.equals(getCarrierPackageName())) { mIsCarrierFinished = true; if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE) { finishCallScreening(); } else { checkContactExistsAndBindService(); } } else if (!TextUtils.isEmpty(packageName) && packageName.equals(getDefaultDialerPackageName())) { // Default dialer defined CallScreeningService cannot skip the call log. mResult.shouldAddToCallLog = true; mIsDefaultDialerFinished = true; if (result.mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE || mIsUserChosenFinished) { finishCallScreening(); } } else if (!TextUtils.isEmpty(packageName) && packageName.equals(getUserChosenPackageName())) { // User defined CallScreeningService cannot skip the call log. mResult.shouldAddToCallLog = true; mIsUserChosenFinished = true; if (mIsDefaultDialerFinished) { finishCallScreening(); } } } } private void bindCarrierService() { String carrierPackageName = getCarrierPackageName(); if (TextUtils.isEmpty(carrierPackageName)) { mIsCarrierFinished = true; bindDefaultDialerAndUserChosenService(); } else { createCallScreeningServiceFilter().startCallScreeningFilter(mCall, this, carrierPackageName, mAppLabelProxy.getAppLabel(carrierPackageName), CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_CARRIER); } // Carrier filtering timed out mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { @Override public void loggedRun() { if (!mIsCarrierFinished) { mIsCarrierFinished = true; checkContactExistsAndBindService(); } } }.prepare(), CARRIER_CALL_FILTERING_TIMED_OUT); } private void bindDefaultDialerAndUserChosenService() { if (mIsCarrierFinished) { String dialerPackageName = getDefaultDialerPackageName(); String systemDialerPackageName = getSystemDialerPackageName(); if (TextUtils.isEmpty(dialerPackageName)) { mIsDefaultDialerFinished = true; } else { int dialerType = dialerPackageName.equals(systemDialerPackageName) ? CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_SYSTEM_DIALER : CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_DEFAULT_DIALER; createCallScreeningServiceFilter().startCallScreeningFilter(mCall, CallScreeningServiceController.this, dialerPackageName, mAppLabelProxy.getAppLabel(dialerPackageName), dialerType); } String userChosenPackageName = getUserChosenPackageName(); if (TextUtils.isEmpty(userChosenPackageName)) { mIsUserChosenFinished = true; } else { // If the user chosen call screening service is the same as the default dialer, then // we have already bound to it above and don't need to do so again here. if (userChosenPackageName.equals(dialerPackageName)) { Log.addEvent(mCall, LogUtils.Events.SCREENING_SKIPPED, "user pkg same as dialer: " + userChosenPackageName); mIsUserChosenFinished = true; } else { createCallScreeningServiceFilter().startCallScreeningFilter(mCall, CallScreeningServiceController.this, userChosenPackageName, mAppLabelProxy.getAppLabel(userChosenPackageName), CallScreeningServiceFilter.CALL_SCREENING_FILTER_TYPE_USER_SELECTED); } } if (mIsDefaultDialerFinished && mIsUserChosenFinished) { finishCallScreening(); } } } private CallScreeningServiceFilter createCallScreeningServiceFilter() { return new CallScreeningServiceFilter( mContext, mCallsManager, mPhoneAccountRegistrar, mParcelableCallUtilsConverter, mTelecomLock, mSettingsSecureAdapter); } private void checkContactExistsAndBindService() { mCallerInfoLookupHelper.startLookup(mCall.getHandle(), new CallerInfoLookupHelper.OnQueryCompleteListener() { @Override public void onCallerInfoQueryComplete(Uri handle, CallerInfo info) { boolean contactExists = info != null && info.contactExists; Log.i(CallScreeningServiceController.this, "Contact exists: " + contactExists); if (!contactExists) { bindDefaultDialerAndUserChosenService(); } else { finishCallScreening(); } } @Override public void onContactPhotoQueryComplete(Uri handle, CallerInfo info) { // ignore } }); } private void finishCallScreening() { Log.addEvent(mCall, LogUtils.Events.CONTROLLER_SCREENING_COMPLETED, mResult); mCallback.onCallFilteringComplete(mCall, mResult); mIsFinished = true; } 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; } private String getDefaultDialerPackageName() { return TelecomManager.from(mContext).getDefaultDialerPackage(); } private String getSystemDialerPackageName() { return TelecomManager.from(mContext).getSystemDialerPackage(); } private String getUserChosenPackageName() { return mCallsManager.getRoleManagerAdapter().getDefaultCallScreeningApp(); } }