我正在尝试开发一个应用程序,该应用程序会生成对特定号码的未接来电。我的应用程序询问需要生成的手机号码和未接来电数量。我使用java本机代码来停止呼叫。代码如下
public void stopCall() throws RuntimeException
{
try {
//String serviceManagerName = "android.os.IServiceManager";
String serviceManagerName = "android.os.ServiceManager";
String serviceManagerNativeName = "android.os.ServiceManagerNative";
String telephonyName = "com.android.internal.telephony.ITelephony";
Class telephonyClass;
Class telephonyStubClass;
Class serviceManagerClass;
Class serviceManagerStubClass;
Class serviceManagerNativeClass;
Class serviceManagerNativeStubClass;
Method telephonyCall;
Method telephonyEndCall;
Method telephonyAnswerCall;
Method getDefault;
Method[] temps;
Constructor[] serviceManagerConstructor;
// Method getService;
Object telephonyObject;
Object serviceManagerObject;
telephonyClass = Class.forName(telephonyName);
telephonyStubClass = telephonyClass.getClasses()[0];
serviceManagerClass = Class.forName(serviceManagerName);
serviceManagerNativeClass = Class.forName(serviceManagerNativeName);
Method getService = // getDefaults[29];
serviceManagerClass.getMethod("getService", String.class);
Method tempInterfaceMethod = serviceManagerNativeClass.getMethod(
"asInterface", IBinder.class);
Binder tmpBinder = new Binder();
tmpBinder.attachInterface(null, "fake");
serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
IBinder retbinder = (IBinder)getService.invoke(serviceManagerObject, "phone");
Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);
telephonyObject = serviceMethod.invoke(null, retbinder);
//telephonyCall = telephonyClass.getMethod("call", String.class);
telephonyEndCall = telephonyClass.getMethod("endCall");
//telephonyAnswerCall = telephonyClass.getMethod("answerRingingCall");
telephonyEndCall.invoke(telephonyObject);
} catch (Exception e) {
e.printStackTrace();
Log.e("dialing-example", "FATAL ERROR: could not connect to telephony subsystem",e);
// Log.error(DialerActivity.this,
// "FATAL ERROR: could not connect to telephony subsystem");
//Log.error(DialerActivity.this, "Exception object: " + e);
}
}
我还使用phonelistener重新启动我的应用程序,因为控件转到Dialer App。因此,为了运行它,我必须重新启动我的活动。
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
String LOG_TAG = "LOGGING 123";
@Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// phone ringing
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// active
isPhoneCalling = true;
Log.i(LOG_TAG, "OFFHOOK");
if(counter<(maxCounter-1))
counter++;
else
{
numberToDial="";
counter=0;
maxCounter=-1;
save();
// Toast.makeText(getApplicationContext(),"Application Exiting "+counter, Toast.LENGTH_SHORT).show();
System.exit(0);
// restart app
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// run when class initial and phone call ended,
// need detect flag from CALL_STATE_OFFHOOK
Log.i(LOG_TAG, "IDLE");
if (isPhoneCalling) {
isPhoneCalling = false;
Log.i(LOG_TAG, "restart app");
// restart app
try{
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
catch(RuntimeException ex)
{
Log.i(LOG_TAG, "Exception caught"+ex.getMessage());
}
/*
Intent intent = new Intent(MainActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
*/
/*
Intent intent = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
*/
}
}
}
我使用OnResume函数来监控总计数。我使用shareReferences来存储总计数。如果总计数超过尝试次数,则应用程序退出。剩余代码如下。
package com.example.dialerpro;
import java.lang.reflect.Constructor;
import java.lang.Process;
import java.lang.reflect.Method;
import java.sql.Date;
import java.util.Calendar;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.view.Menu;
public class MainActivity extends Activity implements OnClickListener {
int maxCounter;
int counter=0;
boolean resetFlag=false;
private String numberToDial="";
EditText txt_username;
Button okBtn;
Button resetBtn;
EditText txt_numberOfTries;
long currentDate;
long prevTime;
Date prevDate;
@Override
public void onCreate(Bundle savedInstanceState) {
try{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
maxCounter=-1;
okBtn=(Button)findViewById(R.id.okBtn);
okBtn.setOnClickListener(this);
resetBtn=(Button)findViewById(R.id.resetBtn);
resetBtn.setOnClickListener(this);
txt_username=(EditText)findViewById(R.id.txt_username);
txt_username.setOnClickListener(this);
txt_numberOfTries=(EditText)findViewById(R.id.txt_numberOfTries);
txt_numberOfTries.setOnClickListener(this);
// add PhoneStateListener
PhoneCallListener phoneListener = new PhoneCallListener();
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);
}
catch(RuntimeException ex)
{
Log.i("From Create Method", "Run Time ");
}
}
Intent callIntent=null;
public void launchDialer(String number){
callIntent=null;
try {
String numberToDial = "tel:"+number;
callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse(numberToDial));
this.startActivity(callIntent);
}
catch (ActivityNotFoundException activityException) {
Log.e("dialing-example", "Call failed", activityException);
}
catch (RuntimeException runException) {
Log.e("dialing-example", "launch dialer Call failed 1", runException);
}
try{
Toast.makeText(getApplicationContext(), "Value "+counter, Toast.LENGTH_SHORT).show();
Thread.sleep(4000);
//callIntent.
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (RuntimeException runException) {
Log.e("dialing-example", "launch dialer Call failed 2", runException);
}
stopCall();
try{
Thread.sleep(2000);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// stop call ends
boolean flagReset=false;
@Override
protected void onStart()
{
super.onStart();
}
@Override
public void onPause() {
super.onPause();
if(counter > (maxCounter-1) )
{
numberToDial="";
counter=0;
maxCounter=-1;
}
save();
}
@Override
public void onDestroy()
{
super.onDestroy();
/* killApplicationProcess();
try{
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage(
getBaseContext().getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
catch(RuntimeException ex)
{
Log.i("aa", "Exception caught"+ex.getMessage());
}
*/
Log.e("on destroy","On destroy");
}
private void killApplicationProcess()
{
android.os.Process.killProcess(android.os.Process.myPid());
}
@Override
public void onResume() {
super.onResume();
try{
//Toast.makeText(getApplicationContext(), "hi from resume", Toast.LENGTH_SHORT).show();
//save();
load();
flagReset=false;
long currentTime=System.currentTimeMillis();
//double difference=(double)((currentTime-prevTime)/1000000);
/* try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
// long currentTimeNow=System.currentTimeMillis();
//double difference=(double)((currentTimeNow-currentTime));
double difference=(double)((currentTime-prevTime));
// Toast.makeText(getApplicationContext(), "hi from difference "+difference, Toast.LENGTH_LONG).show();
if(difference> 10000) //10 seconds
{
Toast.makeText(getApplicationContext(), "hi from difference "+difference, Toast.LENGTH_SHORT).show();
counter=0;
numberToDial="";
maxCounter=-1;
save();
}
if(maxCounter==-1)
{
flagReset=true;
counter=0;
numberToDial="";
}
if( (counter<=(maxCounter-1)) && flagReset==false )
{
int ret=numberToDial.compareTo("");
if(ret>0)
{
launchDialer(numberToDial);
}
}
}
catch(RuntimeException ex)
{
Log.i("From Resume", "Exception caught"+ex.getMessage());
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void save() {
Date date=new Date(System.currentTimeMillis());
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("numberToDial", numberToDial);
editor.putInt("counter", counter);
editor.putInt("maxCounter", maxCounter);
long dte=System.currentTimeMillis();
editor.putLong("time",dte);
editor.putLong("date", date.getTime());
editor.commit();
}
private void load() {
SharedPreferences sharedPreferences = getPreferences(Context.MODE_PRIVATE);
numberToDial=sharedPreferences.getString("numberToDial","");
counter=sharedPreferences.getInt("counter",0);
maxCounter=sharedPreferences.getInt("maxCounter",0);
prevTime=0;
prevTime=sharedPreferences.getLong("time",0);
prevDate=new Date(sharedPreferences.getLong("date", 0));
//Toast.makeText(getApplicationContext(), "Load "+prevTime, Toast.LENGTH_SHORT).show();
}
/**
* @author robert.hinds
*
* Utility class for helper methods
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
// Launch the phone dialer
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.okBtn:
numberToDial=txt_username.getText().toString();
String tries=txt_numberOfTries.getText().toString();
int ret=numberToDial.compareTo("");
boolean flag=true;
if(ret==0)
{
Toast.makeText(getApplicationContext(), "Please Enter the number "+numberToDial, Toast.LENGTH_LONG).show();
flag=false;
}
ret=tries.compareTo("");
if(ret==0)
{
Toast.makeText(getApplicationContext(), "Please provide value for tries", Toast.LENGTH_LONG).show();
flag=false;
}
else
{
maxCounter=Integer.parseInt(tries);
}
if(flag)
{
flagReset=false;
launchDialer(numberToDial);
}
break;
case R.id.resetBtn:
flagReset=true;
numberToDial="";
txt_username.setText("");
txt_numberOfTries.setText("");
counter=0;
save();
break;
case R.id.txt_username:
numberToDial=txt_username.getText().toString();
break;
}
}
@Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
}
}
但是经过18次尝试后,我得到了以下运行时异常。
06-03 11:32:54.611: D/AndroidRuntime(332): Shutting down VM
06-03 11:32:54.611: W/dalvikvm(332): threadid=1: thread exiting with uncaught exception (group=0x40015560)
06-03 11:32:54.650: E/AndroidRuntime(332): FATAL EXCEPTION: main
06-03 11:32:54.650: E/AndroidRuntime(332): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@405cbc90 is not valid; is your activity running?
06-03 11:32:54.650: E/AndroidRuntime(332): at android.view.ViewRoot.setView(ViewRoot.java:527)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.view.Window$LocalWindowManager.addView(Window.java:424)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2145)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1643)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.os.Handler.dispatchMessage(Handler.java:99)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.os.Looper.loop(Looper.java:123)
06-03 11:32:54.650: E/AndroidRuntime(332): at android.app.ActivityThread.main(ActivityThread.java:3647)
06-03 11:32:54.650: E/AndroidRuntime(332): at java.lang.reflect.Method.invokeNative(Native Method)
06-03 11:32:54.650: E/AndroidRuntime(332): at java.lang.reflect.Method.invoke(Method.java:507)
06-03 11:32:54.650: E/AndroidRuntime(332): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-03 11:32:54.650: E/AndroidRuntime(332): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-03 11:32:54.650: E/AndroidRuntime(332): at dalvik.system.NativeStart.main(Native Method)
06-03 11:32:55.951: D/dalvikvm(332): GC_CONCURRENT freed 491K, 48% free 3368K/6471K, external 1239K/1526K, paused 4ms+217ms
06-03 11:32:59.350: I/Process(332): Sending signal. PID: 332 SIG: 9
我需要帮助才能找出此异常的原因。