基于距离传感器的自动锁屏程序

最近写了一个基于距离传感器锁屏的程序,在这里Mark一下。

手机为了节约能耗,一段时间没有操作就会自动锁屏,这带来了一个问题——你得不断的解锁,当然用了这么多年大家也许都习惯了。现在我想尝试一种既节约能耗,又不用频繁解锁的方法。关于这个问题的详细讨论可以看看这里。

 

1.程序功能

主界面

 

 

主要功能:

在后台创建一个后台服务,用来检测距离传感器是否被触发,如果触发就锁住屏幕。

带来的好处:

打开这个服务后,可以尝试把手机设置为不自动锁屏或者延长自动锁屏的时间,在不想用手机之后直接装到兜里面,由于距离传感器被触发,手机将自动锁屏。如果你的手机放在桌上,没有锁屏恰好有人想看你手机上的内容,你可以直接把手放到手机上,距离传感器被触发,就会锁住屏幕,这也比较符合人下意识的动作。对于像我这样不大喜欢频繁解锁的人,应该可以试试。

带来的问题:

一般的手机距离传感器应该是在听筒位置,在使用手机的时候一般不容易被触发。当然使用微信,或者语音助手的时候除外(我也在想解决这个问题的方案)。另外打电话接电话的时候必然会触发距离传感器。

解决方法:

尽量检测出在使用听筒时触发距离传感器的情况,然后在这种情况下,暂停锁屏服务,在不用听筒之后再将锁屏服务打开。在这个程序中,我只实现了检测来电和去电两种情形的检测,在打电话的时候,停止锁屏服务,在挂断电话后重启锁屏服务。

 

2.实现

2.1最关键的部分:锁屏功能

[java][/java] view plaincopy

  1. public static class Controller extends Activity {
  2.     DevicePolicyManager mDPM;
  3.     ComponentName mDeviceAdminSample;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.     // 首先我们要获得android设备管理代理
  8.     mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
  9.     // LockScreen 继承自 DeviceAdminReceiver
  10.     mDeviceAdminSample = new ComponentName(Controller.this,
  11.         LockScreen.class);
  12.     // 得到当前设备管理器有没有激活(获取权限)
  13.     boolean active = mDPM.isAdminActive(mDeviceAdminSample);
  14.     if (!active) {
  15.         // 如果没有激活的话,就去提示用户激活(第一次运行程序时)
  16.         getAdmin();
  17.     } else {
  18.         // 如果已经激活的话,就执行立即锁屏
  19.         mDPM.lockNow();
  20.     }
  21.     // killMyself ,锁屏之后就立即kill掉我们的Activity,避免资源的浪费;
  22.     //android.os.Process.killProcess(android.os.Process.myPid());
  23.     finish();
  24.     }

 

2.2后台服务

首先继承Android.app.Service类,然后实现 OnCreate、OnStart、OnDestroy方法,然后实现SensorEventListener接口中的两个函数——onAccuracyChanged和onSensorChanged,一个是判断精度变化,一个是判断传感器距离变化。

最后将这个服务在Manifest文件中注册一个名称,然后在MainActivity中直接通过这个名称来启动和停止。

[java][/java] view plaincopy

  1. public class AutoLockService extends Service implements SensorEventListener {
  2. }

 

2.3获取权限

首先在res目录下新建一个xml文件夹,然后在该文件夹下新建文件device_admin_sample.xml文件,其内容:

[html][/html] view plaincopy

  1. <?xml version=”1.0″ encoding=”utf-8″?>
  2. <device-admin xmlns:android=”http://schemas.android.com/apk/res/android”>
  3.     <uses-policies>
  4.         <force-lock />
  5.     </uses-policies>
  6. </device-admin>

然后在Manifest文件中注册一个广播接收者:

 

 

[html][/html] view plaincopy

  1. <!– 接收请求Device Admin广播 –>
[html][/html] view plaincopy

  1. <receiver
  2.             android:name=”org.hq.autolock.LockScreen”
  3.             android:permission=”android.permission.BIND_DEVICE_ADMIN” >
  4.             <meta-data
  5.                 android:name=”android.app.device_admin”
  6.                 android:resource=”@xml/device_admin_sample” />
  7.             <intent-filter>
  8.                 <action android:name=”android.app.action.DEVICE_ADMIN_ENABLED” />
  9.             </intent-filter>
  10.         </receiver>

 

 

2.4判断来电和去电状态

继承BroadcastReceiver,已接收到广播就停止锁屏服务,判断挂机之后重新开启锁屏服务。

[java][/java] view plaincopy

  1. @Override
  2. public void onReceive(Context context, Intent intent) {
  3.     // TODO Auto-generated method stub
  4.     //停止锁屏服务
  5.     if( null == myintent ){
  6.         myintent = new Intent(“org.hq.autoLockService”);
  7.     }
  8.     context.stopService(myintent);
  9.     System.out.println(“action”+intent.getAction());
  10.     if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
  11.         //如果是去电(拨出)
  12.         System.out.println(“拨出”);
  13.     }else{
  14.         //查了下android文档,貌似没有专门用于接收来电的action,所以,非去电即来电
  15.         System.out.println(“来电”);
  16.         TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
  17.         //如果挂断了,开启锁屏服务
  18.         if( TelephonyManager.CALL_STATE_IDLE == tm.getCallState() ){
  19.             if( null == myintent ){
  20.                 myintent = new Intent(“org.hq.autoLockService”);
  21.             }
  22.             context.startService(myintent);
  23.         }
  24.     }
  25. }

 

2.5获取传感器信息

首先获取传感器管理类,通过SensorManager就可以获得手机上所有的传感器信息。要监测传感器参数变化,只需新建一个SensorEvenListener。

[java][/java] view plaincopy

  1. sm = (SensorManager) getSystemService(SENSOR_SERVICE); // 获取传感器管理类
  2. promixty = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY); // 获取距离传感器

 

工程源码

标签