1

我可以拦截来电和去电。我的问题是它在 2.3.x 版本中不起作用

这是我的代码:

public class PhoneCallReceiver extends BroadcastReceiver {

/**
 * Call back which fires off when the phone changes state.  
 */
@Override
public void onReceive(Context context, Intent intent) {


    //TODO
    //===========
    //here i need to chack the number

    //      Bundle b = intent.getExtras();
    //      String incommingNumber = b.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
    // Additional Step
    // Check whether this number matches with your defined Block List
    // If yes, Reject the Call
    //===========


    /* examine the state of the phone that caused this receiver to fire off */
    String phone_state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
    if (phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING)) 
    {
        //                    if (context.getSharedPreferences(Hc.PREFSNAME,0).getBoolean(Hc.PREF_CALL_ANSWER_TOOLS_KEY, true))
        //                    {
        logMe("Phone Ringing: the phone is ringing, scheduling creation call answer screen activity");
        Intent i = new Intent(context, CallAnswerIntentService.class);
        i.putExtra("delay", 100L);
        context.startService(i);
        logMe("Phone Ringing: started, time to go back to listening");
        //                    } else {
        //                            logMe("Phone Ringing: Call Answer tools disabled by user");
        //                    }
    }
    if (phone_state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
    {
        //                    if (context.getSharedPreferences(Hc.PREFSNAME,0).getBoolean(Hc.PREF_SCREEN_GUARD_TOOLS_KEY, true))
        //                    {

        //TODO
        Intent i = new Intent(context,InCallScreenGuardService.class);
        i.putExtra("delay", 100L);
        logMe("Phone Offhook: starting screen guard service");
        context.startService(i);
        //                    } else {
        //                            logMe("Phone Offhook: In-Call Screen Guard disabled by user");
        //                    }
    }
    if (phone_state.equals(TelephonyManager.EXTRA_STATE_IDLE))
    {
        //                    if (context.getSharedPreferences(Hc.PREFSNAME,0).getBoolean(Hc.PREF_SCREEN_GUARD_TOOLS_KEY, true))
        //                    {
        //TODO
        Intent i = new Intent(context,InCallScreenGuardService.class);
        logMe("Phone Idle: stopping screen guard service");
        context.stopService(i);
        //                    } else {
        //                            logMe("Phone Idle: In-Call Screen Guard disabled by user");
        //                    }
    }

    return;
}

这发送意图到服务和服务发送意图到以下活动:

public class CallAnswerActivity extends Activity {
/**
 * whether or not to use the AIDL technique or 
 * the HEADSET_HOOK/package restart techniques
 */
private static final boolean USE_ITELEPHONY = true;

/**
 * internal phone state broadcast receiver
 */
protected BroadcastReceiver r;

/**
 * TelephonyManager instance used by this activity
 */
private TelephonyManager tm;

/**
 * AIDL access to the telephony service process
 */
private com.android.internal.telephony.ITelephony telephonyService;

// ------------------------------------------------------------------------
// primary life cycle call backs
// ------------------------------------------------------------------------

/**
 * main() :)
 */
@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    debugLog("onCreate called");
    setContentView(R.layout.callanswerscreen);

    // grab an instance of telephony manager
    tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

    // connect to the underlying Android telephony system
    if (USE_ITELEPHONY)
        connectToTelephonyService();

    // turn our idle phone state receiver on
    registerReciever();



    // touch screen return button
    Button returnToCallScreen = (Button) findViewById(R.id.returnToCallScreen);
    returnToCallScreen.setOnClickListener(new ReturnButtonOnClickListener());

    // touch screen reject/ignore call button
    Button rejectCall = (Button) findViewById(R.id.rejectCallButton);
    //            if (getSharedPreferences(Hc.PREFSNAME,0).getBoolean(Hc.PREF_ALLOW_REJECT_KEY, true)) 
    rejectCall.setOnLongClickListener(new RejectCallOnLongClickListener());
    //            else 
    //                    rejectCall.setVisibility(View.GONE);                    

    // touch screen answer button
    Button answerButton = (Button) findViewById(R.id.answerCallButton);
    //            if (getSharedPreferences(Hc.PREFSNAME,0).getBoolean(Hc.PREF_ANSWER_WITH_BUTTON_KEY, true)) 
    answerButton.setOnLongClickListener(new AnswerCallOnLongClickListener());
    //            else 
    //                    answerButton.setVisibility(View.GONE);                  
}

/** 
 * (re)register phone state receiver on resume, exit if the phone is idle 
 */
@Override protected void onResume() {
    super.onResume();

    registerReciever();

    if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
        debugLog("phone is idle, stopping.");
        exitCleanly();
    }
}

/** 
 * unregister phone state receiver, schedule restart if not exiting at the users request 
 */
@Override protected void onPause() {
    super.onPause();

    unHookReceiver();

    if (!isFinishing()) 
    {
        debugLog("system forced pause occured, scheduling delayed restart");
        Intent i = new Intent(getApplicationContext(), CallAnswerIntentService.class);
        i.putExtra("delay", Hc.RESTART_DELAY);
        startService(i);
    }
}

// ------------------------------------------------------------------------
// Input event handler call backs
// ------------------------------------------------------------------------

/** 
 * Track ball press event handler that will answer a call 
 */
@Override public boolean onTrackballEvent(MotionEvent event) {

    switch(event.getAction())
    {
    case MotionEvent.ACTION_MOVE: return true;
    case MotionEvent.ACTION_DOWN: answerCall(); return true;
    default: debugLog("trackball event: "+event);
    }
    return super.dispatchTrackballEvent(event);
}

/**
 * Camera button press event handler that will answer a call
 */
@Override public boolean dispatchKeyEvent(KeyEvent event) {

    switch (event.getKeyCode()) 
    {
    case KeyEvent.KEYCODE_FOCUS: return true;
    case KeyEvent.KEYCODE_CAMERA: answerCall(); return true;
    default: debugLog("Unknown key event: "+event);
    }
    return super.dispatchKeyEvent(event);
}

/**
 * Return button click listener will exit back to the
 * phones stock answer call application.
 */
private class ReturnButtonOnClickListener implements OnClickListener {
    public void onClick(View v) {
        debugLog("returnToCallScreen onClick event");
        exitCleanly();
    }
}

/**
 * Reject button long click listener will reject the
 * incoming call. 
 */
private class RejectCallOnLongClickListener implements OnLongClickListener {
    public boolean onLongClick(View v){
        debugLog("touch screen ignore call button onClick event");
        ignoreCall();
        exitCleanly();
        return true;
    }               
}

/**
 * Answer button long click listener will answer the
 * incoming call.
 */
private class AnswerCallOnLongClickListener implements OnLongClickListener {
    public boolean onLongClick(View v){
        debugLog("touch screen answer button onClick event");
        answerCall();
        return true;
    }               
}

// ------------------------------------------------------------------------
// broadcast receivers
// ------------------------------------------------------------------------

/**
 * register phone state receiver 
 */
private void registerReciever() {
    if (r != null) return;

    r = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent i)      {
            String phone_state = i.getStringExtra(TelephonyManager.EXTRA_STATE);
            if (!phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING)) 
            {
                debugLog("received "+phone_state+", time to go bye bye, thanks for playing!");
                        exitCleanly();
            }
        } 
    };

    registerReceiver(r, new IntentFilter("android.intent.action.PHONE_STATE"));
}

/**
 * unregister phone state receiver 
 */
private void unHookReceiver() {
    if (r != null) 
    {
        unregisterReceiver(r);
        r = null;
    }
}

// ------------------------------------------------------------------------
// application methods
// ------------------------------------------------------------------------

/** 
 * get an instance of ITelephony to talk handle calls with 
 */
@SuppressWarnings("unchecked") private void connectToTelephonyService() {
    try 
    {
        // "cheat" with Java reflection to gain access to TelephonyManager's ITelephony getter
        Class c = Class.forName(tm.getClass().getName());
        Method m = c.getDeclaredMethod("getITelephony");
        m.setAccessible(true);
          telephonyService = (com.android.internal.telephony.ITelephony) m.invoke(tm);
    } catch (Exception e) {
        e.printStackTrace();
        debugLog("FATAL ERROR: could not connect to telephony subsystem");
        debugLog("Exception object: "+e);
        finish();
    }               
}

//
// answer call
//

/** 
 * answer incoming calls
 */
private void answerCall() {
    if (USE_ITELEPHONY)
        try {
            answerCallAidl();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    else
        answerCallHeadsetHook();

    exitCleanly();
}

/**
 * ACTION_MEDIA_BUTTON broadcast technique for answering the phone
 */
private void answerCallHeadsetHook() {
    KeyEvent headsetHook =  new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_HEADSETHOOK);
    Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
    mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, headsetHook);
    sendOrderedBroadcast(mediaButtonIntent, null);
}

/**
 * AIDL/ITelephony technique for answering the phone
 */
private void answerCallAidl() throws RemoteException {
    telephonyService.silenceRinger();
    telephonyService.answerRingingCall();               
}

//
// ignore call
//

/**
 * ignore incoming calls 
 */
private void ignoreCall() {
    if (USE_ITELEPHONY)
        try {
            ignoreCallAidl();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    else
        ignoreCallPackageRestart();
}

/**
 * package restart technique for ignoring calls 
 */
private void ignoreCallPackageRestart() {
    ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
    am.restartPackage("com.android.providers.telephony");
    am.restartPackage("com.android.phone");
}

/** 
 * AIDL/ITelephony technique for ignoring calls
 */
private void ignoreCallAidl() throws RemoteException {
    telephonyService.silenceRinger();
    telephonyService.endCall();
}       

/** 
 * cleanup and exit routine
 */
private void exitCleanly() {
    unHookReceiver();
    moveTaskToBack(true);           
    finish();
}

我需要帮助才能使其在 2.3 上运行
谢谢

这个例外:

java.lang.SecurityException: Neither user 10156 nor current process has android.permission.MODIFY_PHONE_STATE.
at android.os.Parcel.readException(Parcel.java:1322)
at android.os.Parcel.readException(Parcel.java:1276)
at com.android.internal.telephony.ITelephony$Stub$Proxy.silenceRinger(ITelephony.java:1231)
at com.y_y_full.photo_dailer.CallAnswerActivity.answerCallAidl(CallAnswerActivity.java:281)
at com.y_y_full.photo_dailer.CallAnswerActivity.answerCall(CallAnswerActivity.java:256)
at com.y_y_full.photo_dailer.CallAnswerActivity.access$3(CallAnswerActivity.java:253)
at com.y_y_full.photo_dailer.CallAnswerActivity$AnswerCallOnLongClickListener.onLongClick(CallAnswerActivity.java:181)
at android.view.View.performLongClick(View.java:2556)
at android.widget.TextView.performLongClick(TextView.java:8358)
at android.view.View$CheckForLongPress.run(View.java:9128)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(Native Method)
4

2 回答 2

3

它在 Gingerbread 2.3.x 中不起作用的原因是这个 15031 issue15872 issue Google 更改了围绕电话权限的框架,这让开发人员很烦恼。虽然不能保证,但一些手机制造商保留了许可(想到的是索尼!),其他人已经从谷歌的 AOSP 中删除了代码,并根据他们的制造过程构建了自己的变体,并更改了框架许可到位。

简单地说,另一种方法是让手机植根并在电话套接字层上创建一个 MITM,并在 Android 堆栈看到事件之前进行拦截……但从表面上看,它太复杂了,不值得做。

现在 ICS 已经推出,并且许可仍然没有改变,所以要记住这一点。与此同时,随着谷歌的前进,GB 源代码被尘封,尽管在 15031 问题页面中“请修复此问题”,但几乎没有什么可以做的......

于 2012-06-24T20:04:52.903 回答
0

MODIFY_PHONE_STATE权限仅供系统使用,ITelephony.silenceRinger()需要MODIFY_PHONE_STATE权限。如果需要在通话时使您的手机静音,请使用 AudioManager。但是EndCall()会正常工作。

于 2013-02-17T23:18:14.610 回答