前言,小米手机中,有一个防误触模式,最近领导让我做一下,顺便学习一下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 中值的问题。文末,如果各位大神有疑问,欢迎留言,拍砖,大家一起进步。