欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

如何为已有的app添加手势密码,已有app添加手势,下午,客户打来电话,说以

来源: 开发者 投稿于  被查看 17254 次 评论:91

如何为已有的app添加手势密码,已有app添加手势,下午,客户打来电话,说以


无标题.png

9月3日全国放假,心情大好,虽然离过年还有段距离。


下午,客户打来电话,说以前做好的app公司(这个app是给联想做的)安全部门没过,最好加上手势密码,不过这个功能就不在加钱了,长期合作吗。我就是这样被忽悠了。心肠太好,没办法。

参看了京东钱包的做法,当用户离开app或者机子睡眠后开始定时,超过一定时间后(比如十分钟),那么,你在回到app后就显示手势密码,只有通过验证后才能进入app。

由于是每个页面都必须加手势密码,这让我很是想念j2ee中的拦截器。如果每个activity中都重复加上手势密码的代码,这显然是违反了尽量避免重复原则,另外一但有修改,维护起来将是一场灾难。最重要的一点就是,这样的代码,拿出去太丢人了。


能否集中处理那,这让我想起了kyswipeback组件,通过继承一个共有的activity实现:

完整源码:

package com.lenovo.logistics.activity.gusturelock;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.lenovo.logistics.R;
import com.lenovo.logistics.activity.BaseActivity;
import com.lenovo.logistics.activity.LoginActivity;
import com.lenovo.logistics.common.ActivityManager;
import com.lenovo.logistics.common.ConfigInfoUtil;
import com.lenovo.logistics.common.GusturelockUtil;
import com.lenovo.logistics.view.KyGustureLock;
import com.lenovo.logistics.view.KyGustureLock.OnSelectedListener;
import com.lenovo.logistics.wrapper.ConfigInfo;
import com.lenovo.logistics.wrapper.GusturelockInfo;
/**
 * 实现手势密码
 * @author pc
 *
 */
public class GustureLockActivity extends BaseActivity{
	private boolean gustureLockEnable = true;//是否关闭密码锁功能	
	private FrameLayout root;
	private ViewGroup decorChild;
        private RelativeLayout gusturelock;
        /**
        *这是核心原理,其他的可以不看,这个必须看
        *原理:在已有的布局的外层套个FrameLayout,将手势密码布局和以前的布局都加入到这个FrameLayout中,这样
        *就可以很容根据超时是否显示密码手势。
        所有的Activity只要继承GustureLockActivity就可,不必单独添加代码,所有手势密码逻辑都放到GustureLockActivity即可。
        **/
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityManager.addActivity(this);
	ViewGroup decor = (ViewGroup) this.getWindow().getDecorView();
        decorChild = (ViewGroup) decor.getChildAt(0);//已有的布局,即this.setContentView(R.layout.about)设置的
        decor.removeView(decorChild);
        //重新生成个根布局        
        FrameLayout rootLayout = new FrameLayout(this);
        this.root = rootLayout;
        rootLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));        
        rootLayout.addView(decorChild);
        //创建手势密码布局文件
        LayoutInflater inflate = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        gusturelock = (RelativeLayout)(inflate.inflate(R.layout.gusturelock, null));
        gusturelock.setVisibility(View.GONE);
        rootLayout.addView(gusturelock); //将其添加到新建的根布局中
        //将根布局附加到窗口上        
        decor.addView(rootLayout);
        
        setUpdateTime();
        bindEvent();
    }
	
	@Override
	protected void onResume() {
		super.onResume();
		decorChild.setVisibility(View.VISIBLE);
    	        gusturelock.setVisibility(View.GONE);
		if(this.gustureLockEnable && isGusturelock()){
        	decorChild.setVisibility(View.GONE);
        	gusturelock.setVisibility(View.VISIBLE);
        }
	}
	
	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		setUpdateTime();
	}

	/**
	 * 绑定事件
	 */
	private void bindEvent(){
		KyGustureLock kyGustureLock = (KyGustureLock)gusturelock.findViewById(R.id.kyGustureLock);
		final TextView msg = (TextView)gusturelock.findViewById(R.id.msg);
		//手势密码监听
		kyGustureLock.setOnSelectedListener(new OnSelectedListener(){
			int restNum = 5;//剩余次数
			@Override
			public void onSelected(View view, int[] values) {
				msg.setText("");
				if(restNum <= 0){
					msg.setTextColor(0xFFD74A44);
					msg.setText("密码错误次数过多,请重新登录");
					toLoginPage("密码错误次数过多,请重新登录");
					return ;
				}
				msg.setTextColor(0xFFFFFFFF);
				if(values.length < 4){
					msg.setText("至少连续绘制四个点");
					return ;
				}
				StringBuffer sb = new StringBuffer();
				for(int val : values){
					if(sb.length()>0)
						sb.append("_");
					sb.append(val);	
				}
				restNum--;
				GusturelockInfo info = GusturelockUtil.get(GustureLockActivity.this);
				if(sb.toString().equals(info.getPassword())){//登录成功
					decorChild.setVisibility(View.VISIBLE);
		        	gusturelock.setVisibility(View.GONE);
		        	//重置
		        	restNum = 5;
		        	setUpdateTime();
		        	return ;
				}
				if(restNum <= 0){
					msg.setTextColor(0xFFD74A44);
					msg.setText("密码错误次数过多,请重新登录");
					toLoginPage("密码错误次数过多,请重新登录");
					return ;
				}
				msg.setTextColor(0xFFD74A44);
				msg.setText("密码错误,还可以再输入"+restNum+"次");
				return ;
			}			
		});
		//忘记密码监听
		TextView forgetPsw = (TextView)gusturelock.findViewById(R.id.forgetPsw);
		forgetPsw.setClickable(true);
		forgetPsw.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
				toLoginPage("忘记手势密码,需要重新登录");
			}			
		});
	}
    /**
     * 设置更新时间
     */
	private void setUpdateTime(){
		try {
			DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			GusturelockInfo info = GusturelockUtil.get(GustureLockActivity.this);
			info.setUpdateTime(format.format(new Date()));;
			GusturelockUtil.save(GustureLockActivity.this, info);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 是否需要显示手势密码
	 */
	private boolean isGusturelock(){
		try {
			GusturelockInfo info = GusturelockUtil.get(this);
			if(info.getPassword() == null || info.getPassword().trim().equals(""))//未设置密码锁
				return false;
			if(info.getUpdateTime() == null || info.getUpdateTime().trim().equals(""))
				return false;
			DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date updateTime = format.parse(info.getUpdateTime());
			long current = System.currentTimeMillis();
			if(current - updateTime.getTime() > 5 * 60 * 1000)//5分钟
			//if(current - updateTime.getTime() > 5 * 1000)//5分钟
				return true;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}
	/**
	 * 手势密码是否正在显示
	 */
	protected boolean isGusturelockShowing(){
		if(gusturelock.getVisibility() == View.VISIBLE)
			return true;
		return false;
	}
	/**
	 * 退出应用,同时清除密码
	 */
	protected void exitApplication(){
		ConfigInfo info = ConfigInfoUtil.getConfigInfo(this);
		info.setAutoLogin(false);
		info.setPassword("");
		ConfigInfoUtil.saveConfigInfo(this, info);
		ActivityManager.exit();
	}
	/**
	 * 返回到登录页
	 */
	private void toLoginPage(String message){
	    //当手势密码验证没通过时,返回到登录页
	}
	/**
	 * 监听键盘
	 */
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if(keyCode == KeyEvent.KEYCODE_BACK){
			if(isGusturelockShowing()){
				exitApplication();
				return true;
	        }	
		}
		return super.onKeyDown(keyCode, event);
	}	
	
	public boolean isGustureLockEnable() {
		return gustureLockEnable;
    }
	public void setGustureLockEnable(boolean gustureLockEnable) {
		this.gustureLockEnable = gustureLockEnable;
	}
}

KyGustureLock是手势密码控件,从组件中心http://www.see-source.com/androidwidget/list.html可以看到,


啥时候判断是否超时

可以在onResume中,这样无论是第一次进入,还是重新返回到app,或者是从睡眠状态恢复,都能立马进行处理。

@Override
protected void onResume() {
    super.onResume();
    decorChild.setVisibility(View.VISIBLE);
    gusturelock.setVisibility(View.GONE);
    if(this.gustureLockEnable && isGusturelock()){
        decorChild.setVisibility(View.GONE);//隐藏正常的布局
        gusturelock.setVisibility(View.VISIBLE);//显示手势密码布局
    }
}


离开app时开启定时

可以在onPause方法中开启定时,当用户离开app或进入睡眠状态,此时页面的焦点必定消失,onPause方法调用:

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    setUpdateTime();
}

修改下记录的时间戳即可。以这个时间作为判断超时的起始时间。


大功告成,已经发给客户,目前还没反馈说有bug。

用户评论