Androidで通話自動録音サービスを実現

21398 ワード

この実例では、Androidが通話自動録音サービスを実現するための具体的なコードを共有します。参考にしてください。具体的な内容は以下の通りです。
必要:
①:通話の自動録音;
②:インターフェースがなく、ただ一つのサービスです。
③:録音自動圧縮アップロード;
④:ユーザーがバックグラウンドを整理する時、serviceが殺されてはいけないと要求します。
⑤:安定性:1、ネットワークがない場合;2、アップロードに失敗しました3、サービスのエラー。
ソリューション:
①:通話の自動録音
一つのサービスを起動して、ユーザーの携帯電話の通話状態を監督し、ユーザーが通話状態であることを検知したら、直ちに録音を開始し、通話終了後、録音を停止し、ファイルを保存します。
この機能の前提条件:
1、録音権限、読み書き記憶空間の権限、通話状態の読み取り権限。
2、Serviceは停止されてはいけません。録音できません。
3、起動して起動する(ユーザが起動するたびに自動的にサービスを開くようにしてはいけない)
②:インターフェースがなく、ただ一つのサービスです。
シナリオ①
普通のserviceで、起動放送を傍受し、ユーザーが起動すると、サービスを開始します。しかし、serviceは起動していないことが分かりました。serviceを起動するには、activityが必要です。これを開けなくてもactivityが必要です。
本当にプロジェクトをする時、PMは各種のあなたの理解できない需要を出します。例えば、このシステム、PMはこのアプリケーションが録音サービスだけであることを要求します。インタフェースがあってもいいです。携帯のデスクトップにアプリケーションアイコンが現れてもいいです。したがって、方案①は実行できません。
プラン②
Android携帯はセットの中に補助機能があります。これを利用して強力な機能を実現できます。前提はユーザーが私達の補助機能を開くことです。

③:録音自動圧縮アップロード
アップロードする前にファイルを圧縮処理してからアップロードすればいいです。
④:ユーザーがバックグラウンドを整理する時、serviceが殺されてはいけないと要求します。
殺されないサービスはシステムサービスだけかもしれません。もちろんQQやWeChatのように、彼らが作ったこのような家族用の桶もできます。大手企業はメーカーと協力できるので、彼らの応用は簡単に殺されないです。もちろんこのようにすることを提唱しないで、このようにごみのソフトウェア、Android開発のすばらしい環境を破壊しました。
実際には、サービスをシステムサービスに設定することができますが、ユーザーが補助機能ページでサービスをオフにしない限り、バックグラウンドはクリーンアップされません。私はミニ携帯でテストしましたが、システムレベルのサービスに設定した後、バックグラウンドを整理する時、サービスが殺されても、非常に速く再起動します。興味のある方は試してみてもいいです。
⑤:安定性:1、ネットワークがない場合;2、アップロードに失敗しました3、サービスのエラー
考え方:
ネットワークがない場合は、録音ファイルのアドレスを保存します。アップロード失敗も同じです。ネットワークが切断され、インターフェースが間違っているなど、ネットワークが復旧したときは、再アップロードしてもいいです。録音ファイルは失われません。
コードは簡単です。コメントは詳細です。
プロジェクトの構造:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--                         -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<!--        -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--    wifi    -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

<service
 android:name=".service.RecorderService"
 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
 <intent-filter>
  <action android:name="android.accessibilityservice.AccessibilityService" />
 </intent-filter>
 <meta-data
  android:name="android.accessibilityservice"
  android:resource="@xml/accessible_service_config" />
</service>

/**
 *           (  、         )。
 * Created by wang.ao in 2017/2/24.
 */

public class RecorderService extends AccessibilityService {
 private static final String TAG = "RecorderService";
 private static final String TAG1 = "      ";
 /**
  *     
  */
 private MediaRecorder recorder;
 private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 /**
  *       ,             
  */
 private OutCallReceiver outCallReceiver;
 private IntentFilter intentFilter;
 /**
  *         ,         ,               
  */
 private NetworkConnectChangedReceiver networkConnectChangedReceiver;
 private IntentFilter intentFilter2;
 /**
  *            
  */
 private String currentCallNum = "";
 /**
  *        
  */
 private int previousStats = 0;
 /**
  *          
  */
 private String currentFile = "";
 /**
  *           
  */
 private SharedPreferences unUploadFile;
 private String dirPath = "";
 private boolean isRecording = false;

 @Override
 protected void onServiceConnected() {
  Log.i(TAG, "onServiceConnected");
  Toast.makeText(getApplicationContext(), "         ", Toast.LENGTH_LONG).show();
 }

 @Override
 public void onAccessibilityEvent(AccessibilityEvent event) {
  // TODO Auto-generated method stub
  Log.i(TAG, "eventType " + event.getEventType());
 }

 @Override
 public void onInterrupt() {
  // TODO Auto-generated method stub
  Log.i(TAG, "onServiceConnected");
 }

 @Override
 public boolean onUnbind(Intent intent) {
  return super.onUnbind(intent);
 }

 @Override
 public void onCreate() {
  super.onCreate();
  TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
  //       
  tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
  outCallReceiver = new OutCallReceiver();
  intentFilter = new IntentFilter();
  //        
  intentFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
  registerReceiver(outCallReceiver, intentFilter);
  //         
  networkConnectChangedReceiver = new NetworkConnectChangedReceiver();
  intentFilter2 = new IntentFilter();
  //            
  intentFilter2.addAction("android.net.conn.CONNECTIVITY_CHANGE");
  intentFilter2.addAction("android.net.wifi.WIFI_STATE_CHANGED");
  intentFilter2.addAction("android.net.wifi.STATE_CHANGE");
  //             
  registerReceiver(networkConnectChangedReceiver, intentFilter2);
  unUploadFile = getSharedPreferences("un_upload_file", 0);
  unUploadFile.edit().putString("description", "            ").commit();
  dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/com.ct.phonerecorder/";
 }

 @Override
 public void onDestroy() {
  super.onDestroy();
  Toast.makeText(getApplicationContext(), "     ,      ,       ", Toast.LENGTH_LONG).show();
  if (outCallReceiver != null) {
   unregisterReceiver(outCallReceiver);
  }
  if (networkConnectChangedReceiver != null) {
   unregisterReceiver(networkConnectChangedReceiver);
  }
 }

 class MyListener extends PhoneStateListener {
  @Override
  public void onCallStateChanged(int state, String incomingNumber) {
   // TODO Auto-generated method stub
   Log.d(TAG1, "    " + incomingNumber);
   switch (state) {
    case TelephonyManager.CALL_STATE_IDLE:
     Log.d(TAG1, "  ");
     if (recorder != null && isRecording) {
      recorder.stop();//     
      recorder.release();
      recorder = null;
      Log.d("  ", "    ,    ");
      uploadFile(currentFile);
     }
     isRecording = false;
     break;
    case TelephonyManager.CALL_STATE_RINGING:
     Log.d(TAG1, "    " + incomingNumber);
     //      

     break;
    case TelephonyManager.CALL_STATE_OFFHOOK:
     Log.d(TAG1, "  " + (!incomingNumber.equals("") ? incomingNumber : currentCallNum));
     initRecord(!incomingNumber.equals("") ? incomingNumber : currentCallNum);
     //     
     if (recorder != null) {
      recorder.start();
      isRecording = true;
     }
    default:
     break;
   }
   super.onCallStateChanged(state, incomingNumber);
  }

 }

 /**
  *       ,        。
  * ①    :    ;
  * ②     :      ,             ;
  * ③       ,       ,      。
  */
 public void uploadFile(String file) {
  ZipUtils.zipFile(dirPath + file, dirPath + file + ".zip");
  if (NetWorkUtils.isNetworkConnected(getApplicationContext())) {
   //    
//   OkHttpUtils.postFile()
  } else {
   saveUnUploadFIles(dirPath + file + ".zip");
  }
 }

 /**
  *           
  *
  * @param file           
  */
 private void saveUnUploadFIles(String file) {
  String files = unUploadFile.getString("unUploadFile", "");
  if (files.equals("")) {
   files = file;
  } else {
   StringBuilder sb = new StringBuilder(files);
   files = sb.append(";").append(file).toString();
  }
  unUploadFile.edit().putString("unUploadFile", files).commit();
 }

 /**
  *             ,             ,    
  */
 public void uploadUnUploadedFiles() {
  //           ,        
  String files = unUploadFile.getString("unUploadFile", "");
  unUploadFile.edit().putString("unUploadFile", "").commit();
  if (files.equals("")) {
   return;
  }
  String[] fileArry = files.split(";");
  int len = fileArry.length;
  for (String file : fileArry) {
   upload(file);
  }
 }

 /**
  *     
  *
  * @param file       
  */
 public void upload(final String file) {
  File file1 = new File(file);
  if (file1 == null || !file1.exists()) {
   //     
   return;
  }
  if (!NetWorkUtils.isNetworkConnected(getApplicationContext())) {
   saveUnUploadFIles(file);
   return;
  }
  Map<String, String> map = new HashMap<String, String>();
  map.put("type", "1");
  final String url = "http://192.168.1.158:8082/uploader";
  OkHttpUtils.post()//
    .addFile("mFile", file1.getName(), file1)//
    .url(url)//
    .params(map).build()//
    .execute(new StringCallback() {

     @Override
     public void onResponse(String response, int id) {
      Log.e(TAG, "   response=" + response);
     }

     @Override
     public void onError(Call call, Exception e, int id) {
      Log.e(TAG, "   response=" + e.toString());
      saveUnUploadFIles(file);
     }
    });
 }

 /**
  *       ,         
  *
  * @param incomingNumber     
  */
 private void initRecord(String incomingNumber) {
  previousStats = TelephonyManager.CALL_STATE_RINGING;
  recorder = new MediaRecorder();
  recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// Microphone
  recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);//     3gp  
  File out = new File(dirPath);
  if (!out.exists()) {
   out.mkdirs();
  }
  recorder.setOutputFile(dirPath
    + getFileName((previousStats == TelephonyManager.CALL_STATE_RINGING ? incomingNumber : currentCallNum))
  );
  recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//         
  try {
   recorder.prepare();//     
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 /**
  *          
  *
  * @param incomingNumber     
  * @return          
  */
 private String getFileName(String incomingNumber) {
  Date date = new Date(System.currentTimeMillis());
  currentFile = incomingNumber + " " + dateFormat.format(date) + ".mp3";
  return currentFile;
 }

 /**
  *        ,       
  */
 public class OutCallReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
   Log.d(TAG1, "         :" + currentCallNum);
   if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
    currentCallNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
    Log.d(TAG1, "         :" + currentCallNum);
   } else {
    Log.d(TAG1, "   ,     ");
   }
  }
 }

 /**
  *     change     
  */
 public class NetworkConnectChangedReceiver extends BroadcastReceiver {
  private static final String TAG = "network status";

  @Override
  public void onReceive(Context context, Intent intent) {
   /**
    *            ,  wifi           。.
    *           。wifi    ,  ,                。 log
    *                       ,       wifi,                
    */
   if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
    ConnectivityManager manager = (ConnectivityManager) context
      .getSystemService(Context.CONNECTIVITY_SERVICE);
    Log.i(TAG, "CONNECTIVITY_ACTION");

    NetworkInfo activeNetwork = manager.getActiveNetworkInfo();
    if (activeNetwork != null) { // connected to the internet
     if (activeNetwork.isConnected()) {
      //      
      if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
       // connected to wifi
       Log.e(TAG, "  WiFi     ");
      } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
       // connected to the mobile provider's data plan
       Log.e(TAG, "           ");
      }
      uploadUnUploadedFiles();
     } else {
      Log.e(TAG, "        ,           ");
     }

    } else { // not connected to the internet
     Log.e(TAG, "        ,           ");
    }


   }
  }
 }

}

/**
 *            
 * Created by wang.ao in 2017/2/24.
 */

public class NetWorkUtils {
 /**
  *          
  * @param context
  * @return
  */
 public static boolean isNetworkConnected(Context context) {
  if (context != null) {
   ConnectivityManager mConnectivityManager = (ConnectivityManager) context
     .getSystemService(Context.CONNECTIVITY_SERVICE);
   NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
   if (mNetworkInfo != null) {
    return mNetworkInfo.isAvailable();
   }
  }
  return false;
 }


 /**
  *   WIFI      
  * @param context
  * @return
  */
 public static boolean isWifiConnected(Context context) {
  if (context != null) {
   ConnectivityManager mConnectivityManager = (ConnectivityManager) context
     .getSystemService(Context.CONNECTIVITY_SERVICE);
   NetworkInfo mWiFiNetworkInfo = mConnectivityManager
     .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
   if (mWiFiNetworkInfo != null) {
    return mWiFiNetworkInfo.isAvailable();
   }
  }
  return false;
 }


 /**
  *   MOBILE      
  * @param context
  * @return
  */
 public static boolean isMobileConnected(Context context) {
  if (context != null) {
   ConnectivityManager mConnectivityManager = (ConnectivityManager) context
     .getSystemService(Context.CONNECTIVITY_SERVICE);
   NetworkInfo mMobileNetworkInfo = mConnectivityManager
     .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
   if (mMobileNetworkInfo != null) {
    return mMobileNetworkInfo.isAvailable();
   }
  }
  return false;
 }


 /**
  *              
  * @param context
  * @return
  */
 public static int getConnectedType(Context context) {
  if (context != null) {
   ConnectivityManager mConnectivityManager = (ConnectivityManager) context
     .getSystemService(Context.CONNECTIVITY_SERVICE);
   NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
   if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
    return mNetworkInfo.getType();
   }
  }
  return -1;
 }


 /**
  *           :    0:WIFI  1:3G  2:2G  3
  *
  * @param context
  * @return
  */
 public static int getAPNType(Context context) {
  int netType = 0;
  ConnectivityManager connMgr = (ConnectivityManager) context
    .getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
  if (networkInfo == null) {
   return netType;
  }
  int nType = networkInfo.getType();
  if (nType == ConnectivityManager.TYPE_WIFI) {
   netType = 1;// wifi
  } else if (nType == ConnectivityManager.TYPE_MOBILE) {
   int nSubType = networkInfo.getSubtype();
   TelephonyManager mTelephony = (TelephonyManager) context
     .getSystemService(Context.TELEPHONY_SERVICE);
   if (nSubType == TelephonyManager.NETWORK_TYPE_UMTS
     && !mTelephony.isNetworkRoaming()) {
    netType = 2;// 3G
   } else {
    netType = 3;// 2G
   }
  }
  return netType;
 }
}

public class ZipUtils {
 private static final int BUFF_SIZE = 1024;

 /**
  * @param zos      
  * @param parentDirName    
  * @param file        
  * @param buffer     
  *    
  * @return               ,      
  */
 private static boolean zipFile(ZipOutputStream zos, String parentDirName, File file, byte[] buffer) {
  String zipFilePath = parentDirName + file.getName();
  if (file.isDirectory()) {
   zipFilePath += File.separator;
   for (File f : file.listFiles()) {
    if (!zipFile(zos, zipFilePath, f, buffer)) {
     return false;
    }
   }
   return true;
  } else {
   try {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    ZipEntry zipEntry = new ZipEntry(zipFilePath);
    zipEntry.setSize(file.length());
    zos.putNextEntry(zipEntry);
    while (bis.read(buffer) != -1) {
     zos.write(buffer);
    }
    bis.close();
    return true;
   } catch (FileNotFoundException ex) {
    ex.printStackTrace();
   } catch (IOException ex) {
    ex.printStackTrace();
   }
   return false;
  }
 }

 /**
  * @param srcPath          
  * @param dstPath     zip  
  * @return                        (   windows       )
  */
 public static boolean zipFile(String srcPath, String dstPath) {
  File srcFile = new File(srcPath);
  if (!srcFile.exists()) {
   return false;
  }
  byte[] buffer = new byte[BUFF_SIZE];
  try {
   ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dstPath));
   boolean result = zipFile(zos, "", srcFile, buffer);
   zos.close();
   return result;
  } catch (FileNotFoundException ex) {
   ex.printStackTrace();
  } catch (IOException ex) {
   ex.printStackTrace();
  }
  return false;
 }

 /**
  * @param srcPath     zip  
  * @param dstPath zip         
  * @return            ,        (   windows       )
  */
 public static boolean unzipFile(String srcPath, String dstPath) {
  if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(dstPath)) {
   return false;
  }
  File srcFile = new File(srcPath);
  if (!srcFile.exists() || !srcFile.getName().toLowerCase(Locale.getDefault()).endsWith("zip")) {
   return false;
  }
  File dstFile = new File(dstPath);
  if (!dstFile.exists() || !dstFile.isDirectory()) {
   dstFile.mkdirs();
  }
  try {
   ZipInputStream zis = new ZipInputStream(new FileInputStream(srcFile));
   BufferedInputStream bis = new BufferedInputStream(zis);
   ZipEntry zipEntry = null;
   byte[] buffer = new byte[BUFF_SIZE];
   if (!dstPath.endsWith(File.separator)) {
    dstPath += File.separator;
   }
   while ((zipEntry = zis.getNextEntry()) != null) {
    String fileName = dstPath + zipEntry.getName();
    File file = new File(fileName);
    File parentDir = file.getParentFile();
    if (!parentDir.exists()) {
     parentDir.mkdirs();
    }
    FileOutputStream fos = new FileOutputStream(file);
    while (bis.read(buffer) != -1) {
     fos.write(buffer);
    }
    fos.close();
   }
   bis.close();
   zis.close();
   return true;
  } catch (FileNotFoundException ex) {
   ex.printStackTrace();
  } catch (IOException ex) {
   ex.printStackTrace();
  }
  return false;
 }
}
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。