- 浏览: 636891 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (314)
- 生活 (2)
- c# (37)
- 技术 (3)
- 400电话 (0)
- 400常见问题 (0)
- 400资费 (0)
- html (7)
- css (0)
- 数据库 (7)
- javascript (16)
- php (33)
- asp.net mvc2 (10)
- mysql (9)
- C# 3.0 LinQ (10)
- vs2005或vs2008 (4)
- flash and as3 (7)
- fms (1)
- dedeCMS (11)
- java (33)
- j2me (1)
- swing (1)
- c++ (1)
- jquery easyui (3)
- jquery (5)
- android (29)
- MongoDB (9)
- VtigerCRM (1)
- test (0)
- linux (30)
- nutch (2)
- SqlServer数据库 (2)
- 数据检索 (2)
- java抓取 (11)
- 乐天 (1)
- 淘宝 (1)
- Silverlight4.0 (6)
- sphinx实时索引 (5)
- ecshop (9)
- codeigniter(CI) (3)
- axure6 (1)
- 京东店铺装修教程 (2)
- xpath (1)
- joomla (2)
- bpm (1)
- Bootstrap (2)
- knockout (4)
- ecstore (4)
- css3 (1)
- 微信 (2)
- dede (0)
- soa_edi (1)
- odoo (0)
- web (1)
最新评论
-
骑着蜗牛超F1:
在ie6下报了个stack overflow at line ...
兼容ie6和ie7 的16进制码流在html中显示为图片代码(base64) -
冰之海洋:
好像少了一句代码吧? FloatingFunc.show(th ...
android 一直在最前面的浮动窗口效果 -
yanzhoupuzhang:
连接有问题!
iis7.0官方下载 IIS 7.0(微软Web服务器组件IIS 7.0) 官方(windows 2003,XP,2000) -
whatable:
唉,楼主你都没有搞清楚重量级和轻量级。。。。既然引用了SWT, ...
java swing 内置浏览器打开网页显示flash图表-swt Browser应用 -
yy_owen:
我晕啊,你链接的什么内容额,我要的iis,你链接个视频什么意思 ...
iis7.0官方下载 IIS 7.0(微软Web服务器组件IIS 7.0) 官方(windows 2003,XP,2000)
在完成全部功能之前,我查询了很多资料,用了一个星期的时间终于陆陆续续的将这些功能全部完成了,为了众多和我一样的菜鸟少走一点弯路,我决定将它贴出来和大家一起分享,仔细一看距上次更新博客已经有半年了 。
一、开发环境
Elispse5.5,JDK1.6,Aadroid 2.1
二、开发中使用到的重点技术点:
距离感应(SENSOR_SERVICE
),音讯管理(AUDIO_SERVICE
),
电话状态监听 (TELEPHONY
_
SERVICE
),
java反射启动自动接听,开机自动启动Service ,
监听来电,在Service 中启动Activity 并传递参数
三、主要开发流程:
1. 在前三步中我们看到有一个公共的辅助类CommonHelper
package com.org.speaker;
import android.content.Context;
import android.content.Intent;
public class CommonHelper {
//保存电话状态
public static int phoneState=0;
//保存音讯管理对象
public static MyAudioManager mam=null;
//保存去点电话号码
public static String outGoingPhoneNumber="";
//启动一个新的Activity
public static void StartCustomerInfoActivity(Context context,String telNo)
{
//第一个参数 启动新的Acitivity的Context; 第二个参数 启动的Acitivity的类
Intent intent = new Intent(context,CustomerInfo.class);
//在Service中启动一个Activity并需添加此Flag
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//启动新的Activity时传递的参数
intent.putExtra("TelNo",telNo);
//启动新的Activity
context.startActivity(intent);
}
}
其实将这个类放到第一步是不合适的,因为这个公共类实在我不断写码过程中完善的,并不是一开始就创建的。
2.首先我们建立我们一个音讯管理的类,用于管理当来电或者去点时扩音器的开关。
import android.content.Context;
import android.media.AudioManager;
import android.widget.Toast;
public class MyAudioManager {
private AudioManager audioManager;
private int currVolume=0;
private Context context;
public MyAudioManager(Object object,Context mc){
//音频管理对象由外部调用时传入(http://www.my400800.cn
)
this.audioManager=(AudioManager)object;
this.context=mc;
//设置音讯模式为对外输出
this.audioManager.setMode(AudioManager.ROUTE_SPEAKER);
//取得当前的音量
currVolume=audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
}
//打开扬声器
public void OpenSpeaker()
{
//设置为true,打开扬声器
audioManager.setSpeakerphoneOn(true);
//设置打开扬声器的音量为最大
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL ),
AudioManager.STREAM_VOICE_CALL);
//Toast.makeText(context,"揚聲器已經打開",Toast.LENGTH_SHORT).show();
}
//关闭扬声器
public void CloseSpeaker(){
//设置为false,关闭已经打开的扬声器
audioManager.setSpeakerphoneOn(false);
//恢复为正常音量
audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,currVolume,
AudioManager.STREAM_VOICE_CALL);
//Toast.makeText(context,"揚聲器已經關閉",Toast.LENGTH_SHORT).show();
}
}
3.建立一个监听电话状态的类
package com.org.speaker;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.android.internal.*;
import com.android.internal.telephony.ITelephony;
import android.content.Context;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;
public class SpeakMananger{
private TelephonyManager teleManager;
private Context context;
public SpeakMananger(Object object,Context p_context) {
//转换从外部传入的Object为TelephonyManager对象
this.teleManager=(TelephonyManager)object;
this.context=p_context;
}
//注册电话状态监听器
public void RegisterListener()
{
teleManager.listen(new MyPhoneStateListener(),PhoneStateListener.LISTEN_CALL_STATE);
}
class MyPhoneStateListener extends PhoneStateListener
{
@Override
public void onCallStateChanged(int state,String incomingNumber)
{
super.onCallStateChanged(state, incomingNumber);
switch(state)
{
//空闲 没有电话打入或者打出 处于挂机空闲状态
case TelephonyManager.CALL_STATE_IDLE:
//Toast.makeText(context,"空閒",Toast.LENGTH_SHORT).show();
break;
//摘机 有电话打出或者打入 按接听接或者其它操作拨打或接听来电
case TelephonyManager.CALL_STATE_OFFHOOK:
//Toast.makeText(context,"摘機",Toast.LENGTH_SHORT).show();
//去電 如果是去電則incomingNumber為null或""
//【因为此处无法监听去电并且无法去电的电话号码,所以当去电时此处的打入电话号码为null或者""】
if(incomingNumber==null || incomingNumber.length()<=0){
//打开扬声器
CommonHelper.mam.OpenSpeaker();
//根据公共类中保存的去电电话号码启动一个新的Activity
CommonHelper.StartCustomerInfoActivity(context,CommonHelper.outGoingPhoneNumber);
}
//else //來電
本人是需要在来电振铃的时候就打开扩音器和启动一个新的Acitivity,所以此处被注释掉
//CommonHelper.StartCustomerInfoActivity(context,incomingNumber);
break;
//振铃
在此处我需要在振铃的时候自动接听电话并且打开扬声器和新启动一个Activity
case TelephonyManager.CALL_STATE_RINGING:
//Toast.makeText(context,"振鈴",Toast.LENGTH_SHORT).show();
try {
/* 以下两种方法都可以使用 都能完成自动接听
但是第一种的异常信息处理的比较完善 */
//StartCall();
answerPhoneAidl();
//新启动一个Activity
CommonHelper.StartCustomerInfoActivity(context,incomingNumber);
} catch (Exception e) {
Toast.makeText(context,"自动接听发生异常:"+e.getMessage(),Toast.LENGTH_LONG).show();
}
break;
}
//保存当前电话状态
CommonHelper.phoneState=state;
}
}
//此自动接听代码来自官方开源Demo
http://code.google.com/p/auto-answer/source/detail?r=17
private void answerPhoneAidl() throws Exception {
Class c = Class.forName(teleManager.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony",(Class[])null);
m.setAccessible(true);
ITelephony telephonyService;
telephonyService = (ITelephony)m.invoke(teleManager,(Object[])null);
// Silence the ringer and answer the call!
telephonyService.silenceRinger();
telephonyService.answerRingingCall();
}
/**
* 利用JAVA反射机制调用ITelephony的answerRingingCall()开始通话。
*/
private void StartCall() {
// 初始化iTelephony
Class<TelephonyManager> c = TelephonyManager.class;
Method getITelephonyMethod = null;
try {
// 获取所有public/private/protected/默认
// 方法的函数,如果只需要获取public方法,则可以调用getMethod.
getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
// 将要执行的方法对象设置是否进行访问检查,也就是说对于public/private/protected/默认
// 我们是否能够访问。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false
// 则指示反射的对象应该实施 Java 语言访问检查。
getITelephonyMethod.setAccessible(true);
} catch (SecurityException e) {
Toast.makeText(context,"安全异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
} catch (NoSuchMethodException e) {
Toast.makeText(context,"未找到方法:"+e.getMessage(),Toast.LENGTH_SHORT).show();
}
try {
ITelephony iTelephony = (ITelephony) getITelephonyMethod.invoke(teleManager, (Object[])null);
//停止响铃
iTelephony.silenceRinger();
//接听来电
iTelephony.answerRingingCall();
} catch (IllegalArgumentException e) {
Toast.makeText(context,"参数异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
} catch (IllegalAccessException e) {
Toast.makeText(context,"进入权限异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
} catch (InvocationTargetException e) {
Toast.makeText(context,"目标异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
Toast.makeText(context,"Remote异常:"+e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
}
4.建立一个用于监听距离感应的类
package com.org.speaker;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.telephony.TelephonyManager;
public class ProximitySensor {
private SensorManager sensorManager;
private Sensor sensor;
private SensorEventListener listener;
public ProximitySensor(Object object)
{
//获得外部传入的SensorManager对象
this.sensorManager=(SensorManager)object;
//取得距离感应类型的感应器
this.sensor=sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
listener=new SensorEventListener()
{
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
if(event.values[0]==1.0){
switch(CommonHelper.phoneState)
{
//空闲 离开耳边并且电话空闲的状态,关闭扬声器
case TelephonyManager.CALL_STATE_IDLE:
CommonHelper.mam.CloseSpeaker();
break;
//摘机 离开耳边并且电话状态为摘机状态,打开扬声器
case TelephonyManager.CALL_STATE_OFFHOOK:
CommonHelper.mam.OpenSpeaker();
break;
}
}else{
//耳边接听电话关闭扬声器
CommonHelper.mam.CloseSpeaker();
}
}
};
}
//注册监听器
public void RegisterListener()
{
this.sensorManager.registerListener(listener, sensor,SensorManager.SENSOR_DELAY_FASTEST);
}
//移除监听器
public void UnRegisterListener(){
this.sensorManager.unregisterListener(listener);
}
}
5.现在我们建立我们的Service
package com.org.speaker;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class PhoneCallStateService extends Service{
@Overide
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate(){
super.onCreate();
}
/*在Service启动的时候,实例化我们刚才建立的所有类*/
@Override
public void onStart(Intent intent,int startId)
{
super.onStart(intent, startId);
//音频管理服务
MyAudioManager am=new MyAudioManager(this.getSystemService(AUDIO_SERVICE),this);
//将音讯管理对象保存到公共类中
CommonHelper.mam=am;
//电话-监听-服务【是否有来电、去电、是否空闲】
SpeakMananger sm=new SpeakMananger(this.getSystemService(TELEPHONY_SERVICE),this);
sm.RegisterListener();
//距离感应
ProximitySensor ps=new ProximitySensor(this.getSystemService(SENSOR_SERVICE));
ps.RegisterListener();
}
@Override
public void onDestroy(){
super.onDestroy();
}
}
6.建立一个广播接收类,用于在开机启动完毕后启动我们的Service,并且监听去电获得去电电话号码
package com.org.speaker;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/*
* 1.首先开机启动后系统会发出一个Standard Broadcast Action,
* 名字叫android.intent.action.BOOT_COMPLETED,这个Action只会发出一次。
* 2.构造一个BroadcastReceiver类,重构其抽象方法onReceive(Context context, Intent intent),
* 在其中启动你想要启动的Service。
* 3.在AndroidManifest.xml中,首先加入
* <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
* 来获得BOOT_COMPLETED的使用许可,然后注册前面重构的IntentReceiver类,
* 在其<intent-filter>中加入<action android:name="android.intent.action.BOOT_COMPLETED" /> ,
* 以使其能捕捉到这个Action。
* 參考文檔:
*/
public class StartReceiver extends BroadcastReceiver
{
/*要接收的intent源*/
static final String ACTION = "android.intent.action.BOOT_COMPLETED";
public void onReceive(Context context, Intent intent)
{
//如果系統已經開機完畢,則啟動电话状态服務
if (intent.getAction().equals(ACTION))
{
//启动电话状态服务
context.startService(new Intent(context,PhoneCallStateService.class));
}
/*
* intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL) 去电
* intent.getAction().equals(Intent.ACTION_CALL)) 来电
*/
//监听去电获得去电电话号码
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL))
{
CommonHelper.outGoingPhoneNumber=intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
}
}
7.由有上述类需要使用到一些权限,所以我们要在我们的AndroidManifest.xml配置文件中做如下修改:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="
http://schemas.android.com/apk/res/android
"
package="com.org.speaker"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon">
<activity android:name="CustomerInfo"></activity>
<receiver android:name="StartReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- 添加过滤条件 监听电话状态 -->
<action android:name="android.intent.action.PHONE_STATE"/>
<!-- 监听电话拨出 -->
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<service android:name="PhoneCallStateService" android:enabled="true"></service>
</application>
<uses-sdk android:minSdkVersion="4" />
<!-- 连接互联网的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 读取手机状态的权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 接收手机开机广播的权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- 更改音讯设置的权限 -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- 使用SD卡的权限 这个是我个人用到的 大家可以不使用 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 监听去电的权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 修改电话状态的权限 -->
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<!-- 监听来电的权限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
</manifest>
在项目中,我们使用反编译来完成自动接听还需要官方提供的两个底层包:
评论
发表评论
-
andorid eclipse断点调试失灵
2013-05-09 15:06 1388在调试android程序的时候发现设置的断点怎么也进不去 ... -
android利用ZXing进行条码扫描二维码扫描源码简化
2012-01-04 09:59 2018导入项目 @Override public v ... -
Android使用ZXing类库进行条码/二维码识别
2011-12-26 11:24 1887Android使用ZXing类库进行条码/二维码识别(转) ... -
如何在开发时可以让Android应用程序支持安装到SD卡
2011-12-16 08:51 1015Android系统在2.1版本之前,应用程序是只能安装到机身内 ... -
用TextView显示带图片的效果及为文本添加链接
2011-12-06 17:13 1868为了实现在TextView中显示图片,有时对图片的宽度与高度有 ... -
android listview 滚动时异步加载图片的问题
2011-12-05 15:05 2428LoadImage.java package com ... -
android apk 为程序增加代码混淆
2011-11-30 10:09 2728概述 在2.3版本的sdk中可以看到在ANDROID_S ... -
Android 程序的安装、卸载和更新
2011-11-22 11:20 1253安装程序:软件从无到有。 卸载程序:软件从有到无。 ... -
atest201111
2011-11-21 17:04 0eeeee SQLite Developer ... -
android-XXX9.png文件拉伸不失真大家注意了
2011-11-17 14:24 1818什么是9.png: 可能做过任务栏美化 ... -
Android中String资源文件的String.format方法(java)
2011-10-25 16:57 1303很多时候我们感性Google ... -
android 一直在最前面的浮动窗口效果
2011-10-21 15:51 15990今天发现一些软件可以 ... -
Android 对于ListView拖动时变黑问题解决方法
2011-10-21 13:08 1605最近用ListView显示一些String数据 ... -
Android SeekBarPreference浅聊
2011-10-19 15:37 1596由于网上有很多人问到SeekBarPreferenc ... -
在Android中创建启动界面
2011-10-14 09:06 8361、制作一张启动图片splash.png,放置在res ... -
Android 菜单(OptionMenu)大全 建立你自己的菜单
2011-10-13 09:11 744菜单是用户界面中最常见的元素之一,使用非常频繁,在Andro ... -
Android中使用Gson解析JSON数据
2011-10-12 13:33 1619在Android中可以使用Gson解析JSON数据 ... -
android解析json小例子
2011-10-12 12:53 1178今天学习了一下解析json的知识,把我学习的的一个小例子拿出来 ... -
解决android http请求带中文参数会乱码(url编码)
2011-09-29 17:23 3290今天在用android 的 URL url = new U ... -
android 选择本地图片并预览
2011-09-29 14:40 1289adv_sdcard_image_upload.xml ...
相关推荐
在Android平台上,监听电话呼叫状态是一项重要的功能,它允许开发者获取到电话的实时状态,例如来电、通话中或挂断等。以下将详细介绍如何在Android应用中实现这一功能,包括必要的权限控制和电话状态监听。 首先,...
在Android应用开发中,实现自动接听和挂断电话的功能是一个高级话题,涉及到系统级权限、来电监听和服务等关键概念。这个源码项目提供了一个实际的示例,可以帮助开发者理解和掌握这些技术。 首先,我们要理解...
本篇将深入探讨 Android 2.1 Launcher 的源码,帮助开发者理解其内部工作原理,并可能为自定义 Launcher 开发提供启示。 1. **Launcher 结构** Android 2.1 的 Launcher 主要由以下几个关键组件组成: - `...
在Android系统中,监听电话状态是一项重要的功能,它允许开发者获取到电话的实时信息,比如来电、去电、通话结束等事件。这项功能通常应用于电话录音、来电管理、短信拦截等场景。本教程将深入探讨如何在Android应用...
在Android平台上,开发一个自动接听电话的程序涉及到多个核心知识点,包括权限管理、来电监听、系统服务、广播接收器以及电话API的使用。下面将详细阐述这些关键点。 首先,**权限管理**是Android应用程序的基础,...
基于Android的监听微信红包+自动抢红包(抢红包必备助手)(利用AccessibilityService这个辅助服务类,监听通知栏微信消息,如果有微信红包,就模拟界面一些控件的点击事件).zip 基于Android的监听微信红包+自动抢...
8. **代码实现**:创建一个AccessibilityService类,重写其`onAccessibilityEvent()`方法来监听电话状态变化。在电话振铃时,计算接听按钮的坐标,然后通过`sendPointerDownUpEvents()`等方法模拟点击。同时,根据...
在Android系统中,监听电话状态是一项重要的功能,它允许开发者获取到电话的实时信息,比如来电、去电、通话结束等事件。这个压缩包“Android程序研发源码Android中监听电话状态.zip”很可能包含了实现这一功能的...
在Android开发中,监听USB连接状态是一个常见需求,尤其是在涉及到需要与USB设备通信的应用场景中。当USB设备插入或者拔出时,应用程序可能需要执行相应的操作,比如启动服务、弹出提示信息等。为了实现这一功能,...
本文将深入探讨基于Android 2.1系统进行蓝牙编程的关键知识点,并提供如何使用这些知识来提高开发效率。 1. **Android Bluetooth API** Android 2.1版本提供了Bluetooth API,允许开发者创建能够发现、连接和交换...
- **监听电话状态**:使用TelephonyManager的listen()方法注册电话状态监听器,当接收到PHONE_STATE变化时,可以判断是否为来电状态。 - **启动Activity并传递参数**:当检测到来电时,通过CommonHelper的...
在Android系统中,开发者可以利用系统的广播机制来监听网络状态的变化。这是一项非常重要的功能,因为应用程序往往需要根据网络连接的状态来决定是否加载在线数据或者执行网络相关的操作。本篇文章将详细探讨如何在...
通过获取到`TelephonyManager`的实例,你可以监听电话状态的变化,如来电、去电、通话结束等。在AndroidManifest.xml文件中,确保添加了必要的权限: ```xml <uses-permission android:name="android.permission....
本篇将深入探讨Android 2.1中的多点触摸功能,并通过具体的代码示例——"ch25_MultiTouchDemo1"来解析其工作原理。 一、Android 2.1的多点触摸支持 在Android 2.1中,系统提供了`MotionEvent`类来处理触摸事件,...
在Android平台上,监听电话状态是开发者常常需要处理的一项任务,特别是在构建特定功能的应用时,比如通话录音、来电提醒或是管理通话记录。这个“Android中监听电话状态”的项目,作为一个毕业设计的学习示例,旨在...
此外,BroadcastReceiver可以用来监听系统事件,比如当系统启动时自动加载通讯录数据。 6. **Activity和Fragment**:主Activity负责管理整个通讯录界面,而每个联系人的详细信息可以通过Fragment来展示。Fragment...
2. **电话状态监听**:使用`PhoneStateListener`监听电话状态变化。创建一个内部类,继承自`PhoneStateListener`,并重写`onCallStateChanged()`方法。在这个方法里,可以根据通话状态(如IDLE、OFFHOOK、RINGING)...
这个项目很可能是基于早期的Android 2.1版本,尽管现在最新的Android版本已经发展到了Android 12,但学习老版本的代码可以帮助我们了解Android开发的历史和演变。 首先,我们要理解的是Android 2.1(API级别7)的...
Android 2.1(Eclair)版本的通讯录源码提供了一个深入理解Android系统如何处理联系人数据、显示联系人列表以及与用户交互的基础。下面将详细探讨这个源码中的关键知识点。 1. **SQLite数据库**: Android 2.1的...
14. **单元测试与自动化测试**:Android 2.1支持JUnit进行单元测试,以及 Espresso 进行UI自动化测试,确保应用的稳定性和质量。 通过对这些知识点的深入理解和实践,开发者可以创建出适应Android 2.1环境的高质量...