Bootstrap

Android 来电白名单 只允许联系人呼入电话

客户需求只允许通讯录中联系人可以呼入电话。参考自带的黑名单实现

  1. CallsManager.java类中的onSuccessfulIncomingCall方法有一些过滤器,可以仿照黑名单的方式添加自己的过滤器。

packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

+import com.android.server.telecom.callfiltering.AsyncContactCheckFilter;

 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -505,6 +507,7 @@ public class CallsManager extends Call.ListenerBase
         filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
         filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
                 mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock));
+        filters.add(new AsyncContactCheckFilter(mContext));//mh@[非联系人挂断]
         new IncomingCallFilter(mContext, this, incomingCall, mLock,
                 mTimeoutsAdapter, filters).performFiltering();
     }
  1. 实现过滤器

packages/services/Telecomm/src/com/android/server/telecom/callfiltering/AsyncContactCheckFilter.java

/*
 * 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.AsyncTask;
import android.telecom.Log;

import com.android.server.telecom.Call;
import com.android.server.telecom.LogUtils;
import android.net.Uri;
import android.database.Cursor;

/**
 * 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 AsyncContactCheckFilter extends AsyncTask<String, Void, Boolean>
        implements IncomingCallFilter.CallFilter {
    private final Context mContext;
    private Call mIncomingCall;
    private CallFilterResultCallback mCallback;

    public AsyncContactCheckFilter(Context context) {
        mContext = context;
    }

    @Override
    public void startFilterLookup(Call call, CallFilterResultCallback callback) {
        mCallback = callback;
        mIncomingCall = call;
        String number = call.getHandle() == null ?
                null : call.getHandle().getSchemeSpecificPart();
        this.execute(number);
    }

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected Boolean doInBackground(String... params) {
        try {
            return isContact(mContext, params[0]);
        } finally {
        }
    }

    @Override
    protected void onPostExecute(Boolean isContact) {
        try {
            CallFilteringResult result;
            if (!isContact) {//非联系人直接挂断
                result = new CallFilteringResult(
                        false, // shouldAllowCall
                        true, //shouldReject
                        false, //shouldAddToCallLog
                        false // shouldShowNotification
                );
            } else {
                result = new CallFilteringResult(
                        true, // shouldAllowCall
                        false, // shouldReject
                        true, // shouldAddToCallLog
                        true // shouldShowNotification
                );
            }
            mCallback.onCallFilteringComplete(mIncomingCall, result);
        } finally {
        }
    }
    
    //联系人查询
    private boolean isContact(Context context, String phoneNum) {
        Uri uri = Uri.parse("content://com.android.contacts/data/phones/filter/" + phoneNum);
        Cursor cursor = context.getContentResolver().query(uri, new String[] {android.provider.ContactsContract.Data.DISPLAY_NAME}, null, null, null);
        boolean exists = false;
        if (cursor != null) {
            try {
                if(cursor.moveToFirst()){
                    exists = true;
                    String name = cursor.getString(0);
                    Log.i("mh.log", "incoming phone is contact:" + name);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                cursor.close();
            }
        }
        return exists;
    }
}
  1. 可以添加一个开关,这里使用Settings的方式,也可以用广播。

frameworks/base/packages/SettingsProvider/res/values/defaults.xml

+    <!--mh@ phone blocker -->
+    <bool name="xc_unknow_incall_switch">false</bool>

frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java

@@ -2355,6 +2355,10 @@ class DatabaseHelper extends SQLiteOpenHelper {
                     R.bool.def_screen_brightness_automatic_mode);
 
             loadDefaultAnimationSettings(stmt);
+            
+            //mh@{
+            loadBooleanSetting(stmt, "xc_unknow_incall_blocker",
+                    R.bool.xc_unknow_incall_switch);
+ 			 //mh@}

再修改一下CallsManager.java

public void onSuccessfulIncomingCall(Call incomingCall) {
        Log.d(this, "onSuccessfulIncomingCall");
        if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) {
            Log.i(this, "Skipping call filtering due to ECBM");
            onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));
            return;
        }

        List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
        filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
        filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
        filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
                mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock));
        //mh@{
        boolean blocker = Settings.System.getInt(mContext.getContentResolver(), "xc_unknow_incall_blocker", 0) == 1;
        if(blocker) {
            filters.add(new AsyncContactCheckFilter(mContext));//mh@[非联系人挂断]
        }
        //mh@}
        new IncomingCallFilter(mContext, this, incomingCall, mLock,
                mTimeoutsAdapter, filters).performFiltering();
    }
;