• Android实现简单的检测手机自由落体关闭屏幕


    实现功能如下:在背景运行app,检测到自由落体状态时,熄灭屏幕,可重复测试。

    1. 检测自由落体动作 

    需要使用到加速度感应器 TYPE_ACCELEROMETER

    SensorManager mSensorManager;
    private float mLastX;
    private float mLastY;
    private float mLastZ;
    private double force;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
            mSensorManager.registerListener(sensorListener, 
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
                SensorManager.SENSOR_DELAY_GAME);
        }
    
        private final SensorEventListener sensorListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                try {
                    if(event.sensor == null){
                        return;
                    }
                }catch (Exception ex){
    
                }
    
                if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
                    mLastX = event.values[0];
                    mLastY = event.values[1];
                    mLastZ = event.values[2];
                    force = Math.sqrt(mLastX*mLastX+mLastY*mLastY+mLastZ*mLastZ);
    
                }
                if(force < 1 ){
                    Log.i("Kunkka","force < 1 START-------------");
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (force < 1) {
                                Log.i("Kunkka","force < 1 END, SCREEN OFF");
                                screenOff();
                            }
                        }
                    }, 20);
                }
            }
    
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
            }
        };

    标黄的是判断手机失重的依据,即三个方向的合力为0。由于不是那么精确,让其合力<1即可。

    另外为了防止手机平时突然出现符合这个结果的,当第一次出现符合条件的合力时,延迟20ms再检测一次,(最好连续检测多次来确定连续处于失重状态),假如依旧符合失重,就认定此时在失重状态。再做下一步的处理。

    2. 关闭屏幕

    熄灭屏幕代码:

    private void screenOff(){
        DevicePolicyManager policyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
        ComponentName adminReceiver = new ComponentName(DeviceFallDetectService.this, MyAdminReceiver.class);
        boolean admin = policyManager.isAdminActive(adminReceiver);
        if (admin) {
            policyManager.lockNow();
        } else {
            Toast.makeText(this,"没有设备管理权限",
                    Toast.LENGTH_LONG).show();
        }
    }

    息屏主要使用的是DevicePolicyManager 类,此外MyAdminReceiver是一个息屏管理的广播接收器,该接受器非常重要,系统设置中正是通过该接收器才找到的应用程序,该广播接收器在AndroidManifest.xml中的声明如下:

    <receiver
        android:name=".MyAdminReceiver"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/admin"/>
    
        <intent-filter>
            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
        </intent-filter>
    </receiver>
    xml/admin.xml文件内容如下:
    <?xml version="1.0" encoding="utf-8"?>
    <device-admin xmlns:android="http://schemas.android.com/apk/res/android" >
        <uses-policies>
            <force-lock />
        </uses-policies>
    </device-admin>

    Receiver的源码空的就可以,只需要继承DeviceAdminReceiver:

    public class MyAdminReceiver extends DeviceAdminReceiver {
    
    }

    网上说还需要加权限

    <uses-permission android:name="android.permission.USES_POLICY_FORCE_LOCK" />

    但我没加去运行也没出什么问题。

    3. Forground service实现重复运行

    由于运行在background service中的话,屏幕关了再打开,好像background service就被停下了。

    为了每次屏幕亮了都可以继续运行,把service改成O之后的foreground service:

    首先startservice的地方,改成foreground方式启动:

    Intent intent = new Intent(MainActivity.this,
            DeviceFallDetectService.class);
    startForegroundService(intent);
    MainActivity.this.finish();

    然后在service的onStartCommand中,立刻声明startForeground。

    并且android O 以后每个Notification都需要依附一个channel,要不然就报错。加一个简单的channel:

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            initChanel();
            return super.onStartCommand(intent, flags, startId);
        }
    
        private void initChanel(){
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"FallDetect",
                    NotificationManager.IMPORTANCE_HIGH);
    
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
    
            Notification notification = new Notification.Builder(getApplicationContext(),CHANNEL_ID).build();
            startForeground(3210, notification);
        }

    大功告成

     
  • 相关阅读:
    swift 第十四课 可视化view: @IBDesignable 、@IBInspectable
    swift 第十三课 GCD 的介绍和使用
    swift 第十二课 as 的使用方法
    swift 第十一课 结构体定义model类
    swift 第十课 cocopod 网络请求 Alamofire
    swift 第九课 用tableview 做一个下拉菜单Menu
    swift 第八课 CollectView的 添加 footerView 、headerView
    swift 第七课 xib 约束的优先级
    swift 第六课 scrollview xib 的使用
    swift 第五课 定义model类 和 导航栏隐藏返回标题
  • 原文地址:https://www.cnblogs.com/kunkka/p/9779540.html
Copyright © 2020-2023  润新知