口袋模式或者防误触摸式实现方法

 前言,小米手机中,有一个防误触模式,最近领导让我做一下,顺便学习一下Keyguard的流程。 欢迎加Q1875190039
 本文内容:
           1.口袋模式的实现原理
          2.代码实现
          3.注意事项
          4.开机闹钟
          5.图案锁
一 .口袋模式实现原理
        1. 使用距离感应器,感应遮挡情况
        2. 使用SystemProperties 作为开关值
        3.在KeyguardHost 上,加一层FrameLayout 作为遮挡,并且阻止手势事件向下传递
        4.阻止Statusbar 与开启statusbar
二.类间关系与说明
       见博客《锁屏机制及原理》

三.实现方法 
本文重点章节Andrid 4.4 之后锁屏由jar包变为apk ,并且其路径也变为frameworks\base\packages\Keyguard  
KeyguardHostView 是真正处理锁屏机制的View,如pin .图案,滑动 等等,所以我们可以在这里添加代码,来出来锁屏之前的事件。作为 keyguard 防误触的实现。代码如下:
 

 private Sensor mPocketSensor = null;
    private SensorManager mPocketSensorManager = null;
    private void initSensorManager() {
        try {
            if (mContext != null) {
                mPocketSensorManager = (SensorManager) mContext
                        .getSystemService(Context.SENSOR_SERVICE);
                if (mPocketSensorManager != null && !PowerOffAlarmManager.isAlarmBoot()) {
                    // 避免开机闹钟,以及alarm mode 的时候。出现crush
                    mPocketSensor = mPocketSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
                }
            }

        } catch (Exception e) {

        }
    }

    private void registerProximityListener() {
        if (mPocketSensor != null && mPocketSensorManager != null) {
            mPocketSensorManager.registerListener(proximityEventListener,
                mPocketSensor,
                SensorManager.SENSOR_DELAY_GAME);
        }
    }

    private void unregisterProximityListener() {
        if (mPocketSensor != null && mPocketSensorManager != null) {
            mPocketSensorManager.unregisterListener(proximityEventListener);
        }

    }

    private final static float DISTANCE_NEAR = 0.0f;
    private final static float DISTANCE_FAR = 1.0f;
    /**
     * define the poket mode broadcast
     */
    private static final String NOTIFY_POCKET = "com.morncloud.keyguard.pocket";
    private FrameLayout mMistakenTouchFrameLayout = null;
    private SensorEventListener proximityEventListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            Log.d(TAG, "ProximityEventListener");
            Float distance = event.values[0];
            Log.i(TAG, "onSensorChanged() distance = " + distance);
            boolean isPocketModeOn = isPocketModeOn();
            Log.i(TAG, "onSensorChanged() isPocketModeOn = " + isPocketModeOn);
            if (distance == (DISTANCE_NEAR) && isPocketModeOn) {
                Log.i(TAG, "poket is near ");
                showPocktMode(true);
            } else {
                Log.i(TAG, "poket is far ");
                showPocktMode(false);
                enableNotification();
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            // TODO Auto-generated method stub

        }
    };
    /**
     *  the Kikat can't call the collapsePanels() to disbable the notification
     *  but the method of disable can do the job
     */
    private void collapseNotification() {
        try {
            StatusBarManager service = (StatusBarManager) mContext.getSystemService("statusbar");
            if (service != null) {
                Log.i(TAG, "StatusBarManager ");
                // service.collapsePanels();
                // int flags = 0x1090000;
                // flags |= AntiTheftManager.getHideStatusBarIconFlags();
                // service.disable(flags);
                // Log.i(TAG, "StatusBarManager ");
                int flags = StatusBarManager.DISABLE_NONE;
                flags |= StatusBarManager.DISABLE_RECENT;
                flags |= StatusBarManager.DISABLE_EXPAND;
                flags |= StatusBarManager.DISABLE_NOTIFICATION_TICKER;
                Log.d(TAG,Integer.toHexString(flags)+"flags ox");
                flags |= AntiTheftManager.getHideStatusBarIconFlags();
                service.disable(flags);
            }
        } catch (Exception e) {
        }
    }

    private void enableNotification() {
        try {
            // StatusBarManager service = (StatusBarManager)
            // mContext.getSystemService("statusbar");
            // if (service != null) {
            // Log.i(TAG, "StatusBarManager ");
            // // service.collapsePanels();
            // int flags = StatusBarManager.DISABLE_NONE;
            // flags |= AntiTheftManager.getHideStatusBarIconFlags() ;
            // service.disable(flags);
            // // Log.i(TAG, "StatusBarManager ");
            // }
            mContext.sendBroadcast(new Intent("com.keyguard.pocket"), null);
        } catch (Exception e) {
        }
    }

    private boolean isPocketModeOn() {
        Log.e(TAG, "isPocketModeOn is calling");
        Log.e(TAG, "isPocketModeOn" + SystemProperties.getInt(POCKET_MODE_ON_FLAG, 0));
        return SystemProperties.getInt(POCKET_MODE_ON_FLAG, 0) == 1;
    }

    private void showPocktMode(boolean show) {
        Log.e(TAG, "pockt mode is on" + isPocketModeOn());
        if (show) {
            mMistakenTouchFrameLayout.setVisibility(View.VISIBLE);
            collapseNotification();
        } else {
            mMistakenTouchFrameLayout.setVisibility(View.GONE);
        }
    }

同时,我们应该在KeyguardViewMediator 加一个处理机制,因为,这样做会无法解开statusbar 。所以在KeyguardViewMediator 添加如下代码:
 private static final String NOTIFY_POCKET = "com.keyguard.pocket";
    private BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (intent != null && intent.getAction().equals(NOTIFY_POCKET)) {
                adjustStatusBarLocked();
            }
        }
    };


四,注意事项
        口袋模式的实现还是存在许多坑的,比如,拦截开关机闹钟。Statusbar 问题。还有Systemproperties 中值的问题。文末,如果各位大神有疑问,欢迎留言,拍砖,大家一起进步。

你可能感兴趣的:(android)