【转】Android的自动拨号程序,订票必备^_^

    看 到同事都用来“自动重播”软件来订火车票了,我也下载一个来看看,下载回来反编译一下看看,好像有广告的啊,有一个好像是Google的还是那个广告类在 里面。索性自己弄一个好了,现在吸金软件很多啊,自己编译的才放心,呵呵!代码不多,又有反编译过来的代码作为才看,虽然反编译过来好像有的小地方不是很 对,不过代码逻辑还大概看得出来的,然后自己看了下Android SDK的文档,Google了两下,大概可以弄个出来。就是那个鬼模拟器和Eclipse太好资源了。在我的机器上几乎跑不动了,浪费点时间。当然看 Android SDK文档理解一下基本概念也花了不少时间。 不过很悲剧啊,早上起来快9点了,然后我用软件一拨进去了,结果我搞错时间了,以为还没到我要买的日期就退了出来。等过一会再拨的时候票已经卖完了,有同事说是分时间段放票出来的,再试试看或者有"软a卧"也买了。   来看程序吧: 整个程序的代码逻辑很简单,就是先启动一个activity界面给用户输入,然后启动一个后台service不停的自动拨打相应的号码,直到拨通为止。Android下面相应的关键功能实现代码: 1. 拨打电话 通 过Intent.ACTION_CALL 来请求系统的拨号Activity就可以了。在Android系统里面一个 Intent其实就相当于一条消息,然后系统就会自动根据的你的请求去找相应的功能模块比如说package里面的那个类来加载了。应用都事先注册了说我 自己能够接受那些Intent的。拨打电话也有他的一个Intent 就是 Intent.ACTION_CALL ,其他的发送短信啊那些也有其他的,自己看下文档就知道了。 ‍ private void PhoneCall() { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } mJustCall = false; Uri localUri = Uri.parse("tel:" + mPhoneNumber); Intent call = new Intent(Intent.ACTION_CALL, localUri); call.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);; startActivity(call); //android.util.Log.v("TeleListener", "start to call"); mDialedCount ++; } 注意这个功能要android.permission.CALL_PHONE的权限才能使用,所以要在AndroidManifest.xml 文件后面加上这句 <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission> 安装程序的时候,有什么“需要收费的服务什么的”提示就是这条了。   2. 手机通话状态的查询        这个程序还有一个功能就是能够判断手机是不是正在拨号啊通话啊,才好控制自动重播的。这个Android有通知事件过来的,就像以前的“位置感应"事件一 样,只要你注册了这个通知事件,手机状态变化的时候就自动调用你Listener了。不过Android手机这个事件没法区分“拨号”和“通话”这两个状 态的,这两者统一都是TelephonyManager.CALL_STATE_OFFHOOK状 态,TelephonyManager.CALL_STATE_RINGING指的是外面拨进来的响铃吧。不过你看他系统里面其实是可以区分“拨号”和“通话”这两个状态的,打通了他就开始计时,界面也显示“正在通话”,只是它没有向外部应用开放这个接口而已。可以去看Android源码的packages/apps/Phone/src/com/android/phone/ 下面的InCallScreen.java  CallCard.java 等文件。鉴于我们的“xxxxx”,可以到http://www.netmite.com/android/mydroid/packages/apps/Phone/src/com/android/phone/  这里去看吧,网上好像有很多提供在线源码的 http://hi-android.info/src/com/android/phone/  http://gitorious.org/0xdroid/packages_apps_phone/trees/5f6f01ecda4336dfb47108e67ff909a65f14b820/src/com/android/phone 另外监a听这个事件需要权限<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> 其实网上那些软件比如说“别人大个电话过来播放随机铃声”应该也是通过这个来做到的吧。 TelephonyManager telephonyMgr = (TelephonyManager)getSystemService("phone"); TeleListener teleListener = new TeleListener(this); telephonyMgr.listen(teleListener, 0);   class TeleListener extends PhoneStateListener { private AutoRedialService manager; public TeleListener(AutoRedialService a) { this.manager = a; } @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); switch (state) { // 当处于待机状态中 case TelephonyManager.CALL_STATE_IDLE: { manager.Log("IDLE"); //android.util.Log.v("TeleListener", "IDLE"); if (manager.ShouldStop() || manager.LastCallSucceed()) { manager.stopSelf(); break; } PhoneCall(); break; } // 当处于正在拨号出去,或者正在通话中 case TelephonyManager.CALL_STATE_OFFHOOK: { manager.Log("OFFHOOK"); //android.util.Log.v("TeleListener", "OFFHOOK"); mJustCall = true; //Timer t = new Timer(); break; } // 外面拨进来,好没有接拨号状态中.. case TelephonyManager.CALL_STATE_RINGING: { manager.Log("RINGING"); //android.util.Log.v("TeleListener", "RINGING"); break; } default: break; } }      3. "通一话一记一录"查询   (妈的这都是关键词啊,搞我半天发不上了) 上 面说了不能区分"接通"与“拨号”状态,所以我想到的办法只有拨完之后再去查看最近的通话记录了,如果最后一条记录的通话时间是大于0的,说明就拨通了, 就不需要再重播了。这个用起来还可以,程序拨通就给我退出了。在Android里面这个信息需要向“content provider内a容提供者”去要,其实就是类似查询数据库,可以查、增、减之类的,自己的程序也可以提供这种接口供别人查询。注意这个也需要权a限 <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission> 我一开始不知道,结果用那个蜗牛一样模拟器调试了半天才调试出来。 private boolean LastCallSucceed () { if ( mJustCall == false) { return false; } String[] projection = new String[] { Calls.NUMBER, Calls.DURATION }; ContentResolver cr = getContentResolver(); final Cursor cur = cr.query(android.provider.CallLog.Calls.CONTENT_URI, projection, null, null, Calls.DEFAULT_SORT_ORDER); if (cur.moveToFirst()) { int duration = cur.getInt(1); //上次通话时间 if (duration > 0 ) { //android.util.Log.v("TeleListener", "|"+ String.valueOf(duration) + "|"); //Log( "|"+ String.valueOf(duration) + "|"); return true; } } return false; }   4. Activity 和Service直接的通讯 在 Android里面activity和service是分别属于两个不同的进程的,要两者交互还挺麻烦的,按照文档说法,要实现bindservice等 大堆接口,弄起来挺麻烦的,我这一个这么小玩意就算了吧。偷看了一下反编译的出来的代码,里面启动service的时候,activity发送出去 Intent消息携带多一点信息过去,然后在service里面可以读出来,但是service想传点数据回activity就不行了。这种简单的办法也 够用了,还有朋友发现什么简单办法可以告诉我一下。 在 activity中 public void onClick(View v) { switch (v.getId()) { case R.id.Button_Start: Intent msg = new Intent(this, AutoRedialService.class); EditText pnumEdit = (EditText) findViewById(R.id.EditText_phoneNumber); EditText retryEdit = (EditText)findViewById(R.id.EditText_RetryCount); String phoneNumber =  pnumEdit.getText().toString(); Integer i = Integer.decode(retryEdit.getText().toString()); int retryCount = i.intValue(); msg.putExtra("RetryCount", retryCount); msg.putExtra("PhoneNumber",phoneNumber); //retryEdit.setText(String.valueOf(retryCount-1)); startService(msg);   然后在service启动的时候可以读出来 public void onStart(Intent intent, int startID) { super.onStart(intent, startID); mRetryCount = intent.getIntExtra("RetryCount", 0); String tmp  = intent.getStringExtra("PhoneNumber"); if (tmp != null) { mPhoneNumber = tmp; }   写 完之后,我发程序发到我的手机上去试了一下,好像还行啊,有时需要拨几十次才能打通电话,呵呵,真是省去不少功夫了。有点小问题,有时想停止的时候,不那 么好控制,我把重拨间隔定为2秒了,要操作的很快才行啊。还有就是那个“拨号”“通话”两种状态的变化,感觉可以去读取拨号程序的界面来判断,如果能够找 到那个activity的实例,然后就好办了再findViewById就可以读出上面控件的状态了。不过android好像很难获取别的 activity的实例,即使这个应用是自己的同一个application启动起来的。看文档好像通过android 测试接口Instrumentation  下面的的activitymonitor什么也许可以获取的 到其他activity的实例,不过我没有去试,这个需要建一个“android测试”项目然后从那开始吧。   完整的代码 ================AutoRedialService。java================================ package widebright.AutoRedial; import java.util.Timer; import android.app.Service; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; import android.provider.CallLog.Calls; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; public class AutoRedialService extends Service { private int mRetryCount = 0; private int mDialedCount = 0; private String mPhoneNumber= "10086"; private String mDebugLog = ""; private boolean mJustCall = false; public void Log (String text){ //mDebugLog += text; } @Override public IBinder onBind(Intent msg) { // 使用 bind的办法,可以方便的在service和 //activity两个不同的进程直接交互,不过看代码很多啊 return null; } private void PhoneCall() { try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } mJustCall = false; Uri localUri = Uri.parse("tel:" + mPhoneNumber); Intent call = new Intent(Intent.ACTION_CALL, localUri); call.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);; startActivity(call); //android.util.Log.v("TeleListener", "start to call"); mDialedCount ++; } private  boolean ShouldStop() { return  mDialedCount > mRetryCount; } private boolean LastCallSucceed () { if ( mJustCall == false) { return false; } String[] projection = new String[] { Calls.NUMBER, Calls.DURATION }; ContentResolver cr = getContentResolver(); final Cursor cur = cr.query(android.provider.CallLog.Calls.CONTENT_URI, projection, null, null, Calls.DEFAULT_SORT_ORDER); if (cur.moveToFirst()) { int duration = cur.getInt(1); //上次通话时间 if (duration > 0 ) { //android.util.Log.v("TeleListener", "|"+ String.valueOf(duration) + "|"); //Log( "|"+ String.valueOf(duration) + "|"); return true; } } return false; } public void onCreate() { super.onCreate(); } public void onStart(Intent intent, int startID) { super.onStart(intent, startID); //android.util.Log.v("TeleListener", "starting haha"); // 获取电话管理的一个类实例 mRetryCount = intent.getIntExtra("RetryCount", 0); String tmp  = intent.getStringExtra("PhoneNumber"); if (tmp != null) { mPhoneNumber = tmp; } TelephonyManager telephonyMgr = (TelephonyManager) this .getSystemService(Context.TELEPHONY_SERVICE); // 建立一个监听器来实时监听电话的通话状态 telephonyMgr.listen(new TeleListener(this), PhoneStateListener.LISTEN_CALL_STATE); mDialedCount = 0; //PhoneCall(); } public void onDestroy() { TelephonyManager telephonyMgr = (TelephonyManager)getSystemService("phone"); TeleListener teleListener = new TeleListener(this); telephonyMgr.listen(teleListener, 0); mDialedCount = 0; mRetryCount = 0; mPhoneNumber= "10086"; super.onDestroy(); } class TeleListener extends PhoneStateListener { private AutoRedialService manager; public TeleListener(AutoRedialService a) { this.manager = a; } @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); switch (state) { // 当处于待机状态中 case TelephonyManager.CALL_STATE_IDLE: { manager.Log("IDLE"); //android.util.Log.v("TeleListener", "IDLE"); if (manager.ShouldStop() || manager.LastCallSucceed()) { manager.stopSelf(); break; } PhoneCall(); break; } // 当处于正在拨号出去,或者正在通话中 case TelephonyManager.CALL_STATE_OFFHOOK: { manager.Log("OFFHOOK"); //android.util.Log.v("TeleListener", "OFFHOOK"); mJustCall = true; //Timer t = new Timer(); break; } // 外面拨进来,好没有接拨号状态中.. case TelephonyManager.CALL_STATE_RINGING: { manager.Log("RINGING"); //android.util.Log.v("TeleListener", "RINGING"); break; } default: break; } } } } ===============================main.java================================ package widebright.AutoRedial; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class main extends Activity implements OnClickListener { Button buttonStart, buttonStop; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //EditText pnumEdit = (EditText) findViewById(R.id.EditText_phoneNumber); //EditText retryEdit = (EditText)findViewById(R.id.EditText_RetryCount); //retryEdit.setText("10"); buttonStart = (Button) findViewById(R.id.Button_Start); buttonStop = (Button) findViewById(R.id.Button_Stop); buttonStart.setOnClickListener(this); buttonStop.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.Button_Start: Intent msg = new Intent(this, AutoRedialService.class); EditText pnumEdit = (EditText) findViewById(R.id.EditText_phoneNumber); EditText retryEdit = (EditText)findViewById(R.id.EditText_RetryCount); String phoneNumber =  pnumEdit.getText().toString(); Integer i = Integer.decode(retryEdit.getText().toString()); int retryCount = i.intValue(); msg.putExtra("RetryCount", retryCount); msg.putExtra("PhoneNumber",phoneNumber); //retryEdit.setText(String.valueOf(retryCount-1)); startService(msg); break; case R.id.Button_Stop: stopService(new Intent(this, AutoRedialService.class)); break; default: break; } } } =====================AutoRedialManifest.xm=========================================== <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="widebright.AutoRedial" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".main" android:icon="@drawable/icon" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:icon="@drawable/icon" android:label="@string/app_name" android:name=".AutoRedialService"> </service> </application> <uses-sdk android:minSdkVersion="7" /> <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission> <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission> </manifest>     ============================layout/main.xml============================= <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="right"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TextView android:text="@string/number" android:id="@+id/TextView01" android:layout_width="fill_parent" android:layout_height="wrap_content"> </TextView> <EditText android:layout_width="fill_parent" android:singleLine="true" android:layout_height="wrap_content" android:text="10086" android:phoneNumber="true" android:id="@+id/EditText_phoneNumber"> </EditText> <TextView android:text="@string/times" android:id="@+id/TextView02" android:layout_width="wrap_content" android:layout_height="wrap_content"> </TextView> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="100" android:id="@+id/EditText_RetryCount" android:numeric="integer" android:singleLine="true" android:inputType="number"> </EditText> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:text="@string/start" android:id="@+id/Button_Start" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="left"> </Button> <Button android:text="@string/stop" android:id="@+id/Button_Stop" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_width="wrap_content"> </Button> </LinearLayout> </LinearLayout> ==========================================       再发两个网上找到的小实例,没有测试过 1. 模拟键盘按键 final IWindowManager windowManager = IWindowManager.Stub .asInterface(ServiceManager.getService("window")); windowManager.injectchangerchangerKeyEvent(kEvent,true); 2. 拦截拨打电话号码操作 1.第一步,写一个Receiver继承自BroadcastReceiver public class PhoneStatReceiver extends BroadcastReceiver{ private static final String TAG = "PhoneStatReceiver"; //        private static MyPhoneStateListener phoneListener = new MyPhoneStateListener(); private static boolean incomingFlag = false; private static String incoming_number = null; @Override public void onReceive(Context context, Intent intent) { //如果是拨打电话 if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){ incomingFlag = false; String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); Log.i(TAG, "call OUT:"+phoneNumber); }else{ //如果是来电 TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE); switch (tm.getCallState()) { case TelephonyManager.CALL_STATE_RINGING: incomingFlag = true;//标识当前是来电 incoming_number = intent.getStringExtra("incoming_number"); Log.i(TAG, "RINGING :"+ incoming_number); break; case TelephonyManager.CALL_STATE_OFFHOOK: if(incomingFlag){ Log.i(TAG, "incoming ACCEPT :"+ incoming_number); } break; case TelephonyManager.CALL_STATE_IDLE: if(incomingFlag){ Log.i(TAG, "incoming IDLE"); } break; } } } } 第二步:在AndroidManifest.xml,配置写好的Receiver,并拦截相应的BroadCastAction, 另外注意加上相应的权限。 <receiver android:name=".filter.PhoneStatReceiver"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE"/> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver> 另外有拨打紧急号码权限 <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
posted @ 2012-07-16 17:05  adodo1  Views(143)  Comments(0Edit  收藏  举报