Android 实现密码键盘的相关知识点

时间:2021-02-19 00:31:41

一、前言

       由于我们是做金融相关的,对账户的密码输入为了安全,实现相应的保护测试,决定自己实现密码键盘替代系统的自带输入键盘。为什么要使用密码安全键盘呢,出于以下几个原因:

       1. 第三方的键盘输入密码, 这个密码会被输入法缓存起来, 不安全,完全暴露给第三方。
       2. 由于android的root过后,可以通过读取系统驱动层dev/input/event1中的信息,获取手机触屏的位置坐标等信息,从而获取相应的信息。
       我们出于上面两个原因我们可以使用自定义view实现或者通过popwindow、dialog等实现密码键盘,这个看大家*选择。虽然这种做法是自定义的软键盘,依然会在event1文件中写入触摸信息,因此为了保证输入更加安全,采用随机键盘。做出的一个样子大概是这样的,先给大家看看效果。

        Android 实现密码键盘的相关知识点

       这个界面有点丑,不过今天的重点不是界面,而是功能。

二、实现密码键盘

1.关键问题

       实现密码键盘我们首先有以下几个问题解决,其它的问题都是小问题:
       1.实现0-9数字随机排列
       2.关闭系统键盘,在输入密码的时候禁止弹出
       3.如果输入框在下面,弹出的密码键盘挡住了输入框,如何像系统键盘一样将布局上移,键盘在输入框的下方

       我们先看看上面的几个问题,实现数字随机排列然后并赋值到按钮上,这个还是相对简单,我们取10个随机数,从0-9中取,并不能出现重复的数字,然后赋值即可:

 private int[] getRandomNum() {
Random random = new Random();
int[] data = new int[10];
boolean b;
boolean b2 = false;
boolean b3 = true;
int x;
for (int i = 0; i < 10; i++) {
b = true;
while (b) {
x = random.nextInt(10);
if (x == 0 && b3) {
b3 = false;
b = false;
}
for (int y : data) {
if (y == x) {
b2 = false;
break;
} else {
b2 = true;
}
}
if (b2) {
data[i] = x;
b = false;
break;
}
}
}
return data;
}

       上面就实现了0-9随机生成的数字,这个方法也有很多,我给出了一个大家参考。
       针对第二个问题禁止弹出系统键盘,我们可以这样设置:

setInputType(InputType.TYPE_NULL);

       这个方法意思是输入类型为没有指定明确的类型的特殊内容类型,系统键盘不会弹出,但是在android4.0以上光标不显示,在android4.0以上我们要用反射修改值,代码来源于网上:

public void hideSoftInputMethod(EditText ed) {
if (android.os.Build.VERSION.SDK_INT <= 10) {//4.0以下
ed.setInputType(InputType.TYPE_NULL);
} else {
activity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
try {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus;
setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus",
boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(ed, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}

       现在这样就是有光标的,但是我们在设置popwindow相关属性的时候,this.setFocusable(false); 不然光标一直不闪烁,如果设置为true,点击外面直接关闭系统键盘,不过用户又点击输入框键盘又弹出来了,正确的做法是,当键盘弹出时,点击输入框应该是不弹出键盘,这种用户体验感觉也不是很好。通过判断popwindow是否显示在屏幕上来决定是否弹出密码键盘,这个感觉是可以的,但是我们popwindow设置焦点为false的时候,popwindow的keyPopwindow.isShowing() 在对输入框监听的时候、先判断keyPopwindow == null ,不为空再去判断popwindow是否显示在屏幕上,但是获取的是false,我想跟焦点有关系吧,我用的是setOnTouchListener监听,popwindow上没有焦点,判断就有问题。目前还没想到好的办法,就先让光标闪烁吧,点击外面popwindow直接消失。后面我会给出源码,大家可以测试。
       如果我们在输入用户名的时候,在去输入密码,系统键盘是没有自动关闭的,这个时候我们就需要去判断一下,如果有系统键盘显示就需要关闭系统键盘,通过如下两个方法就可以实现:

/**
* 关闭系统键盘
* @param mEditText
* @param mContext
*/

public void closeSoftKeybord(EditText mEditText, Context mContext) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}

/**
* 判断是否有系统键盘显示
* @return
*/

public boolean isSystemKeyboardVisible(){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.isActive();
}

       第三个问题其实也不难,我想的解决办法是scrollview来解决,我们计算输入框控件距离屏幕下方的距离如果小于密码键盘的高度,就要被遮住,这时候我们就需要在这个scrollview下添加一个view,这样点击布局就上移了,在关闭的时候,再把添加的view移除就好,关于这个计算涉及到android的坐标系计算,不熟悉的可以看看这篇博文:

http://blog.csdn.net/yanbober/article/details/50419117/

       我的实现后是这样的
Android 实现密码键盘的相关知识点

       这个坐标计算我们先计算控件到屏幕view绘制的上方的距离,通过绝对坐标计算,数组下标0是宽度,下标1是高度,还有一个view.getLocationInWindow(location) 获取的是在父窗口的绝对坐标:

    int[] Location = new int[2];
pw_et.getLocationOnScreen(Location);
int y = Location[1];

       我们算出这个高度,然后通过获取整个view的绘制区域高度,然后通过rect.height()这个就可以获取高度:

      Rect rect = new Rect();
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);

       这样我们就可以计算出到底部的距离,通过这个距离就可以判断是否显示密码键盘,不过计算popwindow的高度要这样计算,直接getHeight是获取不到的,一直为0,因为在实例化的时候绘制还没有完成:

keyPopwindow.getContentView().measure(0, 0);
int keyHeight = keyPopwindow.getContentView().getMeasuredHeight();

       这样就可以计算出来上移的距离了,不过我们还有一点要注意,如果scrollview的高度没有超过屏幕,那么我们加上上面计算的偏移量有可能还达不到scrollview滑动的条件,我们应该在加上scrollview距离屏幕低端的距离,这样就可以了,可以说就可以达到我们上面哪个效果。

2.实现键盘

       实现我们就可以通过editable = password_et.getEditableText(); 然后

    private void insert(Button btn) {
int index = password_et.getSelectionStart();
String str = btn.getText().toString();
editable.insert(index, str);
}

       通过这个就可以实现点击事件输入到输入框,我们在设置一个回调接口,在popwindow关闭的时候调整布局:

public static LayoutAdjustListener mLayoutAdjustListener;

public interface LayoutAdjustListener {
//键盘遮挡布局使用scroll调整布局
void adjustKeyboard();
}

public static void setmLayoutAdjustListener(LayoutAdjustListener layoutAdjustListener) {
KeyPopwindow.mLayoutAdjustListener = layoutAdjustListener;
}

this.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss() {
if (mLayoutAdjustListener != null) {
mLayoutAdjustListener.adjustKeyboard();
}
}
});

       这样就基本上完成了,还有一些东西,大家看源码实现吧,我稍后上传下来,有问题的地方欢迎大家指出。

源码下载地址下载地址