距离感应器实现锁频教程

时间:2020-11-29 20:42:36
首先说一下 android平台下的 11种感应器:
           1. ACCELEROMETER 加速,描述加速度的。
           2.GRAVITY 重力,这个在大家都知道。
           3.GYROSCOPE 陀螺仪,对于物体跌落检测更强大些,开发游戏少了它会有点遗憾的, API Level 9新增的类型。
           4. LIGHT 光线感应器,很多 Android手机的屏幕亮度是根据这个感应器的数组自动调节的。
           5. LINEAR_ACCELERATION 线性加速器, API Level 9新增的。
           6. MAGNETIC_FIELD 磁极感应器。
           7. ORIENTATION 方向感应器。
           8. PRESSURE 压力感应器。   
           9. PROXIMITY 距离感应器,对于通话后关闭屏幕背光很有用。
         10. ROTATION_VECTOR 旋转向量, Android 2.3新增的,如果我们过去处理图像会发现这个还是很有用的,不过这里还是对游戏开发起到辅助。
  11. TEMPERATURE 温度感应器,可以获取手机的内部温度,不过和周边的有些差距,毕竟手机内部一般温度比较高。
要善于应用这些资源,今天要说的就是距离感应器。其这个锁频的原理也很简单,就是当有物体靠近距离感应器的时候,会触发事件,然后在事件里面申请设备电源锁,让屏幕处于黑屏出台,然后当物体离开距离感应器,释放设备电源锁,就 ok了。下面看看代码
MainActivity.java  这个类很简单,就是启动一个Service。
?
public  class  MainActivity extends  Activity {
 
/** Called when the activity is first created. */
 
@Override
public  void  onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
 
setContentView(R.layout.main);
 
Intent intent = new  Intent(MainActivity. this , MyService. class );
startService(intent);
 
}
}

   然后就是MyService.java   主要内容

?
public  class  MyService extends  Service {
 
private  SensorManager mManager;
 
private  Sensor mSensor = null ;
 
private  SensorEventListener mListener = null ;
 
private  PowerManager localPowerManager = null ;
private  PowerManager.WakeLock localWakeLock = null ;
 
 
@Override
public  void  onCreate() {
 
//获取系统服务POWER_SERVICE,返回一个PowerManager对象
localPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
//获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
localWakeLock = this .localPowerManager.newWakeLock( 32 , "MyPower" );
 
//获取系统服务SENSOR_SERVICE,返回一个SensorManager对象
mManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//获取距离感应器对象
mSensor = mManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
//注册感应器事件
mListener = new  SensorEventListener() {
 
@Override
public  void  onSensorChanged(SensorEvent event) {
 
float [] its = event.values;
 
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( "手放上去了..." );
 
if  (localWakeLock.isHeld()) {
return ;
} else
localWakeLock.acquire(); // 申请设备电源锁
 
} else  { // 远离手机
 
System.out.println( "手拿开了..." );
 
if  (localWakeLock.isHeld()) {
return ;
} else
localWakeLock.setReferenceCounted( false );
localWakeLock.release(); // 释放设备电源锁
} }
}
 
@Override
public  void  onAccuracyChanged(Sensor sensor, int  accuracy) {
 
}
};
}
 
@Override
public  int  onStartCommand(Intent intent, int  flags, int  startId) {
 
//注册监听
mManager.registerListener(mListener, mSensor,
SensorManager.SENSOR_DELAY_GAME);
 
return  super .onStartCommand(intent, flags, startId);
}
 
@Override
public  void  onDestroy() {
 
//取消监听
mManager.unregisterListener(mListener);
 
super .onDestroy();
}
 
@Override
public  IBinder onBind(Intent intent) {
return  null ;
}
 
}

  

AndroidManifest.xml 中需要添加权限
< uses-permission android:name = "android.permission.DEVICE_POWER" />
<uses-permission android:name= "android.permission.WAKE_LOCK"/>

 

由于时间原因,我这里只是实现了功能,还有很多要优化的地方,有需要的话自己可以加上。
     优化 1:当按下的时候,屏幕会锁住,但是感应器事件依然会触发,也就是说,当你挡住距离感应器,然后再放开,屏幕依然会亮。
     解决方法:当系统锁屏或黑屏会广播两个消息分别是:ACTION_SCREEN_OFFACTION_SCREEN_ON,所以我们可以自己写个BroadcastReceiver来接受这个广播,并且做相应的处理。具体处理方法大家可以在黑屏的时候停止service,然后在屏幕亮后再启动service。或者更简单的定义个boolean变量,黑屏为false,亮的时候为true,然后判断在true的情况下才 申请设备电源锁,应该都可以。大概代码如下
?
public  class  MyReceiver extends  BroadcastReceiver {
 
@Override
public  void  onReceive(Context context, Intent intent) {
 
String action = intent.getAction();
 
if  (action.equals( "android.intent.action.SCREEN_OFF" )) {
 
 
} else  if  (action.equals( "android.intent.action.SCREEN_ON" )) {
 
 
}
 
}
 
}

  

优化2:实现可以手动关闭和启动service。在MainActivity中可以添加个checkBox,以便开启和停止服务。这个应该很简单就不详细说明了。

 

优化3:开机自启动。这个就不说了,网上大把大把的资料。



最后再讲解下 PowerManager这个类。
PowerManager这个类主要是用来控制电源状态的. 通过使用该类提供的api可以控制电池的待机时间,一般情况下不要使用。如果确实需要使用,那么尽可能的使用最低级别的WakeLocks锁。并且确保使用完后释放它。你可以通过context.getSystemService(Context.POWER_SERVICE)的方式获得PowerManager的实例。在PowerManager中,最主要的newWakeLock方法,SDK源码如下
?
/**
* Get a wake lock at the level of the flags parameter. Call
* {@link WakeLock#acquire() acquire()} on the object to acquire the
* wake lock, and {@link WakeLock#release release()} when you are done.
*
* {@samplecode
*PowerManager pm = (PowerManager)mContext.getSystemService(
* Context.POWER_SERVICE);
*PowerManager.WakeLock wl = pm.newWakeLock(
* PowerManager.SCREEN_DIM_WAKE_LOCK
* | PowerManager.ON_AFTER_RELEASE,
* TAG);
*wl.acquire();
* // ...
*wl.release();
* }
*
* @param flags Combination of flag values defining the requested behavior of the WakeLock.
* @param tag Your class name (or other tag) for debugging purposes.
*
* @see WakeLock#acquire()
* @see WakeLock#release()
*/
public  WakeLock newWakeLock( int  flags, String tag)
{
return  new  WakeLock(flags, tag);
}

  这个方法将创建WakeLock对象,通过调用此对象的方法你就可以方便的去控制电源的状态。方法如下:

?
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag" );
wl.acquire();
屏幕将停留在设定的状态,一般为亮、暗状态
wl.release();
释放掉正在运行的cpu或关闭屏幕。

  

flags参数说明:
                         *                                                   cpu       screen       keyboard
                         * PARTIAL_WAKE_LOCK                   on         off             off
                         * SCREEN_DIM_WAKE_LOCK            on         dim             off
                         * SCREEN_BRIGHT_WAKE_LOCK      on         bright          off
                         * FULL_WAKE_LOCK                        on         bright          bright

 

如果你持有PARTIAL_WAKE_LOCK锁,不论任何定时器甚至是按下电源按钮,cpu都将继续运行,无法进入休眠状态。除非你释放掉它。 其他锁的话,虽然cpu也在运行,但是当用户按下电源按钮时,设备将立刻进入休眠状态。