how to access com.android.internal.telephony.CallManager?

北城余情 提交于 2019-12-18 13:29:37

问题


I am trying to access CallManager class object from com.android.internal.telephony package.

Here is my code:

ClassLoader classLoader = TestActivity.class.getClassLoader();
final ClassLoader classLoader = this.getClass().getClassLoader();
try {
    final Class<?> classCallManager =
        classLoader.loadClass("com.android.internal.telephony.CallManager");
    Log.i("TestActivity", classCallManager);
} catch (final ClassNotFoundException e) {
    Log.e("TestActivity", e);
}

Unfortunately, this is throwing a ClassNotFoundException. The same approach allows me to access PhoneFactory, but apparently I'm not allowed to access CallManager.

If I could reach the class, then I'd want to proceed using the class as follows:

Method method_getInstance;
method_getInstance = classCallManager.getDeclaredMethod("getInstance");
method_getInstance.setAccessible(true);
Object callManagerInstance = method_getInstance.invoke(null);

Can anyone help me on this?

Thanks in advance,
Harsha C


回答1:


I could successfully load CallManager and its methods. However, when I invoke getState(), getActiveFgCallState(), it always return IDLE even when the app receives different call states from TelephonyManager, i.e. TelephonyManager.CALL_STATE_IDLE, TelephonyManager.CALL_STATE_OFFHOOK, TelephonyManager.CALL_STATE_RINGING.

I used the following code to load the class and its methods:

final Class<?> classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
Log.i(TAG, "Class loaded " + classCallManager.toString());

Method methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
Log.i(TAG, "Method loaded " + methodGetInstance.getName());

Object objectCallManager = methodGetInstance.invoke(null);
Log.i(TAG, "Object loaded " + objectCallManager.getClass().getName());


Method methodGetState = classCallManager.getDeclaredMethod("getState");
Log.i(TAG, "Method loaded " + methodGetState.getName());

Log.i(TAG, "Phone state = " + methodGetState.invoke(objectCallManager));

Btw, what I am trying to do is detecting when the phone starts ringing. I saw in the source code that ALERTING is the internal event that I should listen to. Therefore, I tried to use CallManager to get Call.State, rather than Phone.State. I also tried to use registerForPreciseCallStateChanges() of CallManager class but none of approached worked so far.




回答2:


I had to solve the exact same problem - getting the disconnection cause during call hangup. My solution was to grep the radio logs for the relevant lines. Seems to work - hope it helps.

private void startRadioLogListener() {
    new Thread(new Runnable() {
        public void run() {
            Process process = null;
            try {
                // Clear the log first
                String myCommandClear = "logcat -b radio -c";  
                Runtime.getRuntime().exec(myCommandClear);

                String myCommand = "logcat -b radio";  
                process = Runtime.getRuntime().exec(myCommand);
                Log.e(LogHelper.CAL_MON, "RadioLogProc: " + process);

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                while (true) {
                    final String line = bufferedReader.readLine();
                    if (line != null) {
                        if (line.contains("disconnectCauseFromCode") || line.contains("LAST_CALL_FAIL_CAUSE")) {
                            Log.d(LogHelper.CAL_MON, "RadioLog: " + line);
                            radioLogHandler.post(new Runnable() {
                                public void run() {
                                    consolePrint("Radio: " + line + "\n");
                                }
                            });
                        }
                    }
                }
            } catch (IOException e) {
                Log.e(LogHelper.CAL_MON, "Can't get radio log", e);
            } finally {
                if (process != null) {
                    process.destroy();
                }
            }
        }
    }).start();
}



回答3:


Have you tried this method found here on this blog?

By loading the Phone.apk might be the clue to getting around the ClassNotFound exception error...




回答4:


I have written a program that recognize the phone calls and list all recent calls in a list. Maybe you can have a look on this code and it can help I think. All you need is this:

String state = bundle.getString(TelephonyManager.EXTRA_STATE);
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))

but check this example also:

package org.java.sm222bt;

import org.java.sm222bt.R;

import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;

public class MainActivity extends ListActivity {
private CountryDbAdapter db;
private Cursor entrycursor;
private ListAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //setContentView(R.layout.main);
    registerForContextMenu(getListView());
    db = new CountryDbAdapter(this);
   updateEntry();

}
public void updateEntry(){
    db.open();

    entrycursor = db.fetchAllEntries();

    adapter = new SimpleCursorAdapter(this, R.layout.row, entrycursor, new String[] {"phonenumber"}, new int[] {R.id.number});
    setListAdapter(adapter);
    db.close();
}
@Override
protected void onResume() {

    super.onResume();
    updateEntry();
}

public static final int Call = 0;
public static final int SendSMS = 1;
public static final int Share = 2;
public static final int Delete = 3;
public static final int ClearList = 4;



public void onCreateContextMenu(ContextMenu menu, View v, 
ContextMenu.ContextMenuInfo menuInfo) { 
menu.setHeaderTitle("Select:"); 
menu.add(0, Call, 0, "Call");
menu.add(0, SendSMS, 0, "Send SMS");
menu.add(0, Share, 0, "Share");
menu.add(0, Delete, 0, "Delete");
menu.add(0, ClearList, 0, "Clear all contacts");


}

@Override
public boolean onContextItemSelected(MenuItem item) { 
switch (item.getItemId()) {
case Call:
//System.out.println(entrycursor.getString(1));
//EditText number=(EditText)findViewById(R.id.number);
String toDial="tel:"+entrycursor.getString(1);
//start activity for ACTION_DIAL or ACTION_CALL intent
startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(toDial)));
    //update(entryCursor.getLong(0));
return true;
case SendSMS:


    //EditText number=(EditText)findViewById(R.id.number);
    //EditText msg=(EditText)findViewById(R.id.msg);
    String sendUri="smsto:"+entrycursor.getString(1);
    Intent sms=new Intent(Intent.ACTION_SENDTO,
                            Uri.parse(sendUri));
    //sms.putExtra("sms_body", msg.getText().toString());
    startActivity(sms);

return true;
case Share:

    Intent i=new Intent(Intent.ACTION_SEND);
    i.setType("text/plain");
    i.putExtra(Intent.EXTRA_SUBJECT, "Hello");
    i.putExtra(Intent.EXTRA_TEXT, "Sharing this number"+entrycursor.getString(1));
    startActivity(Intent.createChooser(i,
                                  entrycursor.getString(1)));
    return true;

case Delete:

    db.open();
    db.deleteEntry(entrycursor.getLong(0));
    db.close();
    updateEntry();

return true;

case ClearList:

    db.open();
    db.deleteEntry();
    db.close();
    updateEntry();

    return true;

default:
return super.onContextItemSelected(item);
}
}
}

and here is the incomming call receiver:

package org.java.sm222bt;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;

public class IncomingCallReceiver extends BroadcastReceiver {
CountryDbAdapter db;
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Bundle bundle = intent.getExtras();
    if(null == bundle)
            return;
    String state = bundle.getString(TelephonyManager.EXTRA_STATE);
    if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING))
    {
        String phonenumber = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
        System.out.println(phonenumber);

        db = new CountryDbAdapter(context);
        db.open();
        db.insertEntry(phonenumber);
        db.fetchAllEntries();
        db.close();

}
}} 



回答5:


I understand that you want to detect when the call is disconnected. You can instead use the PhoneStateListener.LISTEN_CALL_STATE. For example:

final TelephonyManager telephony = (TelephonyManager)
        getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
    public void onCallStateChanged(final int state,
            final String incomingNumber) {
        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:
            Log.d("TestActivity", "Call disconnected");
            break;
        case TelephonyManager.CALL_STATE_RINGING:
            break;
        default:
            break;
        }
    }
}, PhoneStateListener.LISTEN_CALL_STATE);



回答6:


Use this :

    telephone = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

    private PhoneStateListener psl = new PhoneStateListener() {

    @Override
    public  void onCallStateChanged (int state, String incomingNumber)
    {
        state = telephone.getCallState();

        switch(state) {
        case android.telephony.TelephonyManager.CALL_STATE_IDLE:    
            if (callsucces ) act();

            break;
        case android.telephony.TelephonyManager.CALL_STATE_RINGING:
            callsucces = true; 
            break;
        case android.telephony.TelephonyManager.CALL_STATE_OFFHOOK:
            callsucces = true; 
            break;
        }
    }

};


   private void call(String pnum) {
    try {

        callIntent = new Intent(Intent.ACTION_CALL);

        callsucces = false;
        if (telephone.getNetworkType() != 0) {
        if (telephone.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
        callIntent.setData(Uri.parse("tel:"+pnum)); 
        startActivity(callIntent);
        telephone.listen(psl,PhoneStateListener.LISTEN_CALL_STATE);
        }
        } else act();
        //callIntent.ACTION_NEW_OUTGOING_CALL
    } catch (ActivityNotFoundException activityException) {
         Toast.makeText(getBaseContext(), "Call failed",Toast.LENGTH_SHORT).show();
         act();

    }
}



回答7:


Did you add READ_PHONE_STATE in AndroidManifest.xml ?

I think you miss that one.



来源:https://stackoverflow.com/questions/4745899/how-to-access-com-android-internal-telephony-callmanager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!