Как получить доступ к com.android.internal.telephony.CallManager?

Я пытаюсь получить доступ к объекту класса CallManager из пакета com.android.internal.telephony.

Вот мой код:

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);
}

К сожалению, это выбрасывает ClassNotFoundException. Тот же подход позволяет мне получить доступ к PhoneFactory, но, видимо, мне не разрешен доступ к CallManager.

Если бы я мог достичь класса, то я хотел бы продолжить использование класса следующим образом:

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

Может ли кто-нибудь помочь мне в этом?

Спасибо заранее,
Харша C

Ответ 1

Я могу успешно загрузить CallManager и его методы. Однако, когда я вызываю getState(), getActiveFgCallState(), он всегда возвращает IDLE, даже когда приложение получает разные состояния вызова из TelephonyManager, то есть TelephonyManager.CALL_STATE_IDLE, TelephonyManager.CALL_STATE_OFFHOOK, TelephonyManager.CALL_STATE_RINGING.

Я использовал следующий код для загрузки класса и его методов:

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));

Кстати, я пытаюсь обнаружить, когда телефон начинает звонить. Я видел в исходном коде, что ALERTING - это внутреннее событие, которое я должен слушать. Поэтому я попытался использовать CallManager, чтобы получить Call.State, а не Phone.State. Я также попытался использовать registerForPreciseCallStateChanges() класса CallManager, но ни один из них не работал до сих пор.

Ответ 2

Мне пришлось решить ту же самую проблему - получить причину отключения во время разговора. Мое решение состояло в том, чтобы grep протоколы радиосвязи для соответствующих строк. Кажется, работает - надеюсь, что это поможет.

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

Вы пробовали этот метод, найденный здесь, в этом блоге?

При загрузке Phone.apk может быть ключом к обходу ошибки исключения ClassNotFound...

Ответ 4

Я написал программу, которая распознает телефонные звонки и перечисляет все последние вызовы в списке. Возможно, вы можете взглянуть на этот код, и это может помочь, я думаю. Все, что вам нужно, это:

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

но также проверьте этот пример:

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);
}
}
}

и вот приемник входящего вызова:

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

Я понимаю, что вы хотите определить, когда вызов отключен. Вместо этого вы можете использовать PhoneStateListener.LISTEN_CALL_STATE. Например:

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

Используйте это:

    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

Вы добавили READ_PHONE_STATE в AndroidManifest.xml?

Я думаю, вы пропустили этот.