您的位置:首页 > 移动开发 > Android开发

仿QQ黑屏,锁屏,程序切换之后的手势密码锁定,加强版

2014-12-28 12:43 337 查看
这是一篇我个人在EOE发的帖子《仿QQ黑屏,锁屏,程序切换之后的手势密码锁定,》,由于eoe的blog系统实在是无言以对,我就把eoe上面的帖子以及blog是都转到csdn上来,原帖地址:http://www.eoeandroid.com/thread-313331-1-1.html

加强版:原来是不管你怎么操作,都是5分钟锁定一次,但是客户要求,只要不触碰的时候再5分钟锁定一次,看过第一版的同学,直接拉到帖子最后看,加强版的实现吧,没看过的,建议从头看

----------------------------------------------------------------第一版,我是华丽分割线---------------------------------------------------------------------------

需求:项目里要用类似的如题的功能,然后在那基础上加一个5分钟锁定一次

先说下我原来的思路,

黑屏和锁屏,5分钟的切换都好说,黑屏和锁定有广播通知,5分钟自己开线程操作;但是android有长按home(menu)或者home之后再切换回来的功能,这个就要利用activity的生命周期,我开始的思路是错的,没有利用好生命周期,最后反编译qq的apk看代码才看出来的;原思路核心代码如下:

黑屏和锁屏,代码是网上搜索的,也贴出来,看下:

/**

         * screen状态广播接收者

         */

        private class ScreenBroadcastReceiver extends BroadcastReceiver {

                private String action = null;

                @Override

                public void onReceive(Context context, Intent intent) {

                        action = intent.getAction();

                        if (Intent.ACTION_SCREEN_ON.equals(action)) {

                                mScreenStateListener.onScreenStateChange(true);

                        } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {

                                mScreenStateListener.onScreenStateChange(false);

                        }

                }

        }

/**

         * 请求screen状态更新

         */

        public void requestScreenStateUpdate(ScreenStateListener listener) {

                mScreenStateListener = listener;

                startScreenBroadcastReceiver();

                firstGetScreenState();

        }

        /**

         * 第一次请求screen状态

         */

        private void firstGetScreenState() {

                PowerManager manager = (PowerManager) mContext

                                .getSystemService(Activity.POWER_SERVICE);

                if (isScreenOn(manager)) {

                        if (mScreenStateListener != null) {

                                mScreenStateListener.onScreenStateChange(true);

                        }

                } else {

                        if (mScreenStateListener != null) {

                                mScreenStateListener.onScreenStateChange(false);

                        }

                }

        }

        /**

         * 停止screen状态更新

         */

        public void stopScreenStateUpdate() {

                mContext.unregisterReceiver(mScreenReceiver);

        }

        /**

         * 启动screen状态广播接收器

         */

        private void startScreenBroadcastReceiver() {

                IntentFilter filter = new IntentFilter();

                filter.addAction(Intent.ACTION_SCREEN_ON);

                filter.addAction(Intent.ACTION_SCREEN_OFF);

                mContext.registerReceiver(mScreenReceiver, filter);

        }

        /**

         * screen是否打开状态

         *

         * @param pm

         * @return

         */

        private static boolean isScreenOn(PowerManager pm) {

                boolean screenState;

                try {

                        screenState = (Boolean) mReflectScreenState.invoke(pm);

                } catch (Exception e) {

                        screenState = false;

                }

                return screenState;

        }

5分钟一次:

private static Timer timer ;

        private static TimerTask timerTask;

        private static boolean isRunning;

        /**

         * 5分钟一次弹出

         *

         * @param

         *
@return void

         * @throws

         */

        public void startVerify(){

                if(timer == null){

                        timer = new Timer();

                }

                if(timerTask == null){

                        timerTask = new TimerTask() {

                                @Override

                                public void run() {

                                                // 使用handler去通知主线程判断是否开启锁定界面

                                        mHandler.sendEmptyMessage(0);

                                }

                        };

                }

                if(!isRunning){

                        timer.schedule(timerTask, 60*1000, 60*1000);

                        isRunning = true;

                }

        }

private Handler mHandler = new Handler(){

                @Override

                public void handleMessage(Message msg) {

                        super.handleMessage(msg);

                        verify();

                        LogUtil.i("GestureActivity.IS_SHOW-->"+GestureActivity.IS_SHOW);

                }

        };

        /**         * 开启检测界面         *          * @param          * @return void         * @throws         */

public void verify(boolean isPause) {

boolean isTopRunning = isRunningForeground(getApplicationContext());

if(isPause){                        if(!isTopRunning){

// 判断检测界面是否已经运行

if(!GestureActivity.IS_SHOW)

{                                        Intent intent = new Intent();                                        intent.setClass(getApplicationContext(), GestureActivity.class);                                        intent.putExtra(GestureActivity.INTENT_MODE,
GestureActivity.GESTURE_MODE_VERIFY);                                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                                        startActivity(intent);                                }                        }             
  }else{                        // 判断是否在前台运行                        if(isTopRunning){                                // 判断检测界面是否已经运行                                if(!GestureActivity.IS_SHOW){                                        Intent intent = new Intent(); 
                                      intent.setClass(getApplicationContext(), GestureActivity.class);                                        intent.putExtra(GestureActivity.INTENT_MODE, GestureActivity.GESTURE_MODE_VERIFY);                               
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                                        startActivity(intent);                                }                        }                }        }

错误的程序切换核心代码:思路1:onstop中

@Override

        protected void onPause() {

                super.onPause();

                if(isVerify()){

                        mApplication.verify(true);

                }

        }

思路2:在onrestart中

@Override

        protected void onRestart() {

                super.onRestart();

                if (isVerify()) {

                        mApplication.verify(true);

                }

        }

如上代码,按home健没问题,但是长按调出最近程序列表的时候就会有问题,会直接弹出来密码解锁界面

qq已经实现了,就去看看大牛们是怎么做的,晚上回去反编译qq的apk,反编译出来的资源如下



大企业,代码写的一般都会非常规范,一般略懂鸟语的一些常用的东西就能看的明白:

1、首先要看manifest中的activity,首先要定位到解锁界面是那个类



2、因为qq所以界面都会响应这操作,所以这个判断肯定是在一个基类里,可以找到一个baseactivity里面有这个判断的方法,而且必须是在生命周期中,用jd-jui来定位一下代码看看base中有这样的代码,如图



如图确实是有一个方法是开启锁定界面,然后看了下生命周期,有调用到该方法的地方,那么下一步就是把新建一个工程,吧qq的src放进去(主要为了使用eclipse的search功能,也可以用sourceinsight)

3、来分析base的onstart,onresume,onstop(onstart,onresume的操作是一致的)

分析看图中





在这三个生命周期中用到了一个重要的类GesturePWDUtils,一会分析这个类

多余代码我都删掉了,代码中的注释是我加的,纯属个人YY,如果有差错,也请高抬贵手

public class GesturePWDUtils
{
// 应该是判断当前app是否在最前端
public static boolean getAppForground(Context paramContext)
{
boolean bool = getAppSharedPreferences(paramContext).
getBoolean("gesturepassword_appforground", false);
if (QLog.isColorLevel())
{

String str = "getAppForground.uin=,isAppFroground=" + bool;
QLog.d("Q.gesturelock.util", 2, str);
}
return bool;
}
// 应该是判断当前账号的是否设置了 手势密码锁定
public static boolean getJumpLock(Context paramContext, String paramString)
{
boolean bool = true;
SharedPreferences localSharedPreferences = getSharedPreferences(paramContext);
String str1 = "gesturepassword_gesture_mode" + paramString;
int i = localSharedPreferences.getInt(str1, 21);
if (i == 21)
{
String str2 = "gesturepassword_gesture_state" + paramString;
if (localSharedPreferences.getInt(str2, 0) != 2)
break label146;
}
while (true)
{
if (QLog.isColorLevel())
{
String str3 = "getJumpLock.uin=" +
paramString + ",isjumplock=" + bool;
QLog.d("Q.gesturelock.util", 2, str3);
}
return bool;
if ((i == 20) &&
(localSharedPreferences.
getBoolean("gesturepassword_locking", false)))
continue;
label146: bool = false;
}
}
// 判断当前app是否在最前端,可以看代码,qq把一些activity过滤掉了,
public static boolean isAppOnForeground(Context paramContext)
{
ActivityManager localActivityManager = (ActivityManager)paramContext.getApplicationContext().getSystemService("activity");
String str1 = paramContext.getApplicationContext().getPackageName();
Object localObject = localActivityManager.getRunningAppProcesses();
int i;
if (localObject == null)
i = 0;
while (true)
{
return i;
Iterator localIterator = ((List)localObject).iterator();
while (true)
if (localIterator.hasNext())
{
localObject = (ActivityManager.RunningAppProcessInfo)localIterator.next();
if (((ActivityManager.RunningAppProcessInfo)localObject).importance != 100)
continue;
if (!((ActivityManager.RunningAppProcessInfo)localObject).processName.equals(str1))
{
String str2 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str3 = str1 + ":qzone";
if (!str2.equals(str3))
{
String str4 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str5 = str1 + ":picture";
if (!str4.equals(str5))
{
String str6 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str7 = str1 + ":web";
if (!str6.equals(str7))
{
String str8 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str9 = str1 + ":video";
if (!str8.equals(str9))
{
String str10 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str11 = str1 + ":zebra";
if (!str10.equals(str11))
{
String str12 = ((ActivityManager.RunningAppProcessInfo)localObject).processName;
String str13 = str1 + ":qqreader";
if (!str12.equals(str13))
continue;
}
}
}
}
}
}
i = 1;
break;
}
i = 0;
}
}
// 重点,保存当前app是否在最前端的状态
public static void setAppForground(Context paramContext, boolean paramBoolean)
{
if (QLog.isColorLevel())
{
String str = "setAppForground.uin=,isAppFroground=" + paramBoolean;
QLog.d("Q.gesturelock.util", 2, str);
}
SharedPreferences.Editor localEditor1 = getAppSharedPreferences(paramContext).edit();
SharedPreferences.Editor localEditor2 = localEditor1.putBoolean("gesturepassword_appforground", paramBoolean);
boolean bool = localEditor1.commit();
}
}


ok,分析完了代码,知道了解决方法,来改造我自己的代码,主要是程序切换的代码(生命周期中),代码如下:SpOperationUtil是我对SharedPreferences的封装,大家看方法名就应该明白,getBooleanInfof的意识是获取boolean值,默认值为false

@Override
protected void onStart() {
super.onStart();
isForeGround = SpOperationUtil.getBooleanInfof(CTX, ISFOREGROUND_KEY);
if(!isForeGround){
if (isVerify()) {
mApplication.verify();
}
}
if(!isForeGround){
SpOperationUtil.saveBoolean(CTX, ISFOREGROUND_KEY, true);
}
}

@Override
protected void onResume() {
super.onResume();
isForeGround = SpOperationUtil.getBooleanInfof(CTX, ISFOREGROUND_KEY);
if(!isForeGround){
if (isVerify()) {
mApplication.verify();
}
}
if(!isForeGround){
SpOperationUtil.saveBoolean(CTX, ISFOREGROUND_KEY, true);
}
}
String ISFOREGROUND_KEY = "ISFOREGROUND_KEY";
boolean isForeGround = true;
@Override
protected void onStop() {
super.onStop();
isForeGround = mApplication.isRunningForeground(CTX);

if(!isForeGround){
SpOperationUtil.saveBoolean(CTX, ISFOREGROUND_KEY, isForeGround);
}
}


这样的话,功能就完成......代码分析先到这,中午整理下,写个demo,上传上来

----------------------------------------------------------------第一版,我是华丽分割线---------------------------------------------------------------------------

加强版:只有没操作之后,5分钟锁定一次,注意demo中为了方便测试设置的是30秒,下面是思路和解决方法:

1、监听每一个activity的触碰事件,获取最新一次的触碰时间,和上一次时间相比,如果没超过5分钟,就把监听先停掉然后再重新开启,代码如下:
base中拦截触碰时间
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mApplication.setLastTouchTime();
return super.dispatchTouchEvent(ev);
}
MApplication 中
// 上一次触碰时间
long lastTimeMillis = 0;
/**
* 设置上一次监听时间
*
* @param
* @return void
* @throws
*/
public void setLastTouchTime(){
// 最新的触碰时间
long currentTimeMillis = System.currentTimeMillis();
if(lastTimeMillis == 0){
// 第一次触碰
lastTimeMillis = currentTimeMillis;
// 开启监听
startVerify();
}else{
//时间差
long temp = currentTimeMillis - lastTimeMillis;
// 如果时间差小于5分钟,就先停掉前一次的监听,再重新开启
if(temp < 1000 * 60 * 5){
stopVerify();
startVerify();
}
// else 如果大于,那么上一次的监听在运行着,5分钟之后自然会锁定
}
}


2、注意:MainActivity中

// 过滤掉本activity 这个界面不用监听

        setVerify(false);
       

最后代码地址:http://download.csdn.net/detail/lsmfeixiang/7859569
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐