最近在做一个网络通话的apk,功能和手机打sim卡电话一样。虽然只做java部分,但也遇到很多问题,其中一个就是模拟通话时的状态,要控制屏幕锁屏。我知道是通过手机上的距离感应器来实现,但也搞了好久,今天终于有了结果,拿出来分享一下。下载地址:http://download.csdn.net/detail/luozhi3527/5959023
在eoe上发帖寻问这个问题时,大牛告诉我说点亮屏幕可以做到,但是灭屏需要系统权限,应该无法做到。他说的很对,这里我们确实需要申请权限:
<uses-permission android:name="android.permission.DEVICE_POWER"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
第一个权限加到xml文件中时会报错,但是我会很利索的去clean掉,实现步骤:找到eclipse中的菜单选项project>clean,选择当前项目就ok
接下来看一下一个类的代码:
package com.xluo.sensortest;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;
import android.view.Menu;
import android.view.View;
public class SensorTest extends Activity implements SensorEventListener{
public static final String TAG = "SensorTest";
//调用距离传感器,控制屏幕
private SensorManager mManager;//传感器管理对象
//屏幕开关
private PowerManager localPowerManager = null;//电源管理对象
private PowerManager.WakeLock localWakeLock = null;//电源锁
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sensor);
mManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
//获取系统服务POWER_SERVICE,返回一个PowerManager对象
localPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
//获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
localWakeLock = this.localPowerManager.newWakeLock(32, "MyPower");//第一个参数为电源锁级别,第二个是日志tag
}
public void onResume(){
super.onResume();
mManager.registerListener(this, mManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),// 距离感应器
SensorManager.SENSOR_DELAY_NORMAL);//注册传感器,第一个参数为距离监听器,第二个是传感器类型,第三个是延迟类型
}
public void onStop(){
super.onStop();
Log.d(TAG,"on stop");
}
public void onDestroy(){
super.onDestroy();
Log.d(TAG,"on destroy");
if(mManager != null){
localWakeLock.release();//释放电源锁,如果不释放finish这个acitivity后仍然会有自动锁屏的效果,不信可以试一试
mManager.unregisterListener(this);//注销传感器监听
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
float[] its = event.values;
//Log.d(TAG,"its array:"+its+"sensor type :"+event.sensor.getType()+" proximity type:"+Sensor.TYPE_PROXIMITY);
if (its != null && event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
System.out.println("its[0]:" + its[0]);
//经过测试,当手贴近距离感应器的时候its[0]返回值为0.0,当手离开时返回1.0
if (its[0] == 0.0) {// 贴近手机
System.out.println("hands up");
Log.d(TAG,"hands up in calling activity");
if (localWakeLock.isHeld()) {
return;
} else{
localWakeLock.acquire();// 申请设备电源锁
}
} else {// 远离手机
System.out.println("hands moved");
Log.d(TAG,"hands moved in calling activity");
if (localWakeLock.isHeld()) {
return;
} else{
localWakeLock.setReferenceCounted(false);
localWakeLock.release(); // 释放设备电源锁
}
}
}
}
}
当然,拿出来的例子只是对屏幕锁做了实现,而没有通话的功能的。但是原理大概就是这样,来电或者拨打时手机会切换到一个通话界面,然后这个界面应该具有上面所说的这样的功能。
需要特别注意的是,在onDestroy()函数里需要把对象锁释放掉(localWakeLock.release()),否则这个功能会一直存在知道你清楚应用数据或者删除应用,我就为这个问题困扰了好久。为此我特意在源代码例子里做了一个跳转页面,加了log。
这里我们实例化了两个管理对象,一个是传感器管理对象:SensorManager;另一个是 电源管理对象:localPowerManager。
传感器管理对象负责收集收集与物体之间的距离数据,电源管理对象通过判断传感器收集到数据对屏幕的灭屏和白屏做处理。