Android项目:手机安全卫士(5)—— 自定义弹窗
1 介绍
前面实现了设置界面中的自动更新选项,接下来先把设置界面放到一边,以后用到了再添加相应的 Item 设置选项。回过头,我们来看看第一个功能:手机防盗,看到这个,一般能够想到的功能无非是:
- SIM 卡发生改变时,能够短信通知,并获取电话好吗
- 手机丢失时,能够远程定位、远程锁机
- 能够远程发送自定义指令
嗯,暂时~,我就想到这么多。当然,进入这个手机防盗功能时需要密码验证,本文要讲的内容就是关于设置密码与验证密码,以及自定义弹窗。
2 自定义密码设置窗口
首先来看看窗口长什么样:
设置密码弹窗:
输入密码弹窗:
不错,这两个弹窗的 UI 基本一样,只是设置密码的弹窗多了一个 EditText 控件,首先,我们来实现它的 UI 部分,创建布局文件:dialog_set_password.xml,具体内容如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@android:color/holo_blue_dark"
android:gravity="center"
android:text="请设置密码"
android:textColor="#000"
android:textSize="18sp" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:inputType="textPassword" />
<EditText
android:id="@+id/et_password_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请再次输入密码"
android:inputType="textPassword" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="确定"
android:textSize="18sp" />
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
做了这么多次的界面,对这些控件已经相当熟悉了,其中有一个标题,用 TextView 实现,两个密码输入框,用 EditText,以及两个按钮。其中 EditText 有两个属性比较有特色:
- hint:表示当没有输入文本时,给予用户的提示
- inputType:用户输入文本的类型,这里设置为 textPassword,表示输入密码,采用密文显示,否则是明文显示,不安全
两个弹窗的 layout 文件基本一样,具体可以去 GitHub 上查看[项目源码](https://github.com/xwdoor/MobileSafe,这里就不浪费文字了。
3 使用弹窗
为 9 宫格的第一个 Item 设置点击事件,代码如下:
case 0://手机防盗界面
showSafeDialog();
break;
然后是显示密码弹窗的逻辑,显示弹窗之前,首先判断用户是否设置密码,如果已设置,就需要先输入密码,如果没有设置,则弹出设置密码的弹窗,代码如下:
/** 显示手机防盗弹窗 */
private void showSafeDialog() {
String password = PrefUtils.getString(PREF_PASSWORD,"",this);
//判断是否存在密码
if(!TextUtils.isEmpty(password)){
//显示输入密码弹窗
showInputPasswordDialog();
}else {
//显示设置密码弹窗
showSetPasswordDialog();
}
}
首先是显示密码设置界面,该界面有几个代码处理逻辑:
- 两次密码若有一个为空,提示用户:密码不能为空
- 两次密码不一致,提示用户:两次密码不一致
- 两次密码一致,则保存密码
这里有几个知识点,调用 AlertDialog.Builder 的 create() 方法生成 AlertDialog 对象,然后调用该对象的 setView() 方法,可以添加自定义的 UI,好了,说了这么多,不如上代码来的一目了然:
/** 设置密码的弹窗 */
private void showSetPasswordDialog() {
final AlertDialog dialog = new AlertDialog.Builder(this).create();
View view = View.inflate(this, R.layout.dialog_set_password, null);
Button btnOk = (Button) view.findViewById(R.id.btn_ok);
Button btnCancel = (Button) view.findViewById(R.id.btn_cancel);
final EditText etPassword = (EditText) view.findViewById(R.id.et_password);
final EditText etPasswordConfirm = (EditText) view.findViewById(R.id.et_password_confirm);
btnOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String password = etPassword.getText().toString().trim();
String passwordConfirm = etPasswordConfirm.getText().toString().trim();
if(!TextUtils.isEmpty(password)&&!TextUtils.isEmpty(passwordConfirm)){
if(password.equals(passwordConfirm)){
PrefUtils.putString(PREF_PASSWORD,password,HomeActivity.this);
dialog.dismiss();
}else {
showToast("两次密码不一致");
}
}else{
showToast("密码不能为空");
}
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setView(view, 0, 0, 0, 0);
dialog.show();
}
说明一下,其中的 showToast() 方法,是我自己对 Toast 进行了简单的封装,因为每次都要写那么多的参数,还可能忘了调用 show() 方法,怪麻烦的。接下来就是输入密码弹窗的代码处理逻辑了,跟上面的差不多,这里直接给代码了:
/** 输入密码的弹窗 */
private void showInputPasswordDialog() {
final AlertDialog dialog = new AlertDialog.Builder(this).create();
View view = View.inflate(this, R.layout.dialog_input_password, null);
Button btnOk = (Button) view.findViewById(R.id.btn_ok);
Button btnCancel = (Button) view.findViewById(R.id.btn_cancel);
final EditText etPassword = (EditText) view.findViewById(R.id.et_password);
btnOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String password = etPassword.getText().toString().trim();
获取保存的密码
String savedPassword = PrefUtils.getString(PREF_PASSWORD,"",HomeActivity.this);
if(!TextUtils.isEmpty(password)){
if(password.equals(savedPassword)){
dialog.dismiss();
}else {
showToast("密码错误");
}
}else{
showToast("密码不能为空");
}
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setView(view, 0, 0, 0, 0);
dialog.show();
}
4 md5 加密
前面涉及到的密码虽然说是用 SharedPreferences 保存的,但是这样很不安全,因为是明文,所以这里介绍一种不可逆的加密方法,它就是鼎鼎有名的 md5 加密,当然,虽说是不可逆的,但如果你的密码太过简单,还是可以通过穷举来破解的。好了,废话说完了,让我们来实现吧,首先创建类:Md5Utils,声明一个静态方法,如代码所示:
public class MD5Utils {
public static String encode(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = digest.digest(password.getBytes());
StringBuffer sb = new StringBuffer();
for (byte b : bytes) {
int i = b & 0xff;// 获取低8位内容
String hexString = Integer.toHexString(i);
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
sb.append(hexString);
}
String md5 = sb.toString();
return md5;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
至于使用方法,对于聪明的你们,就不用我说了吧,都懂得。
5 总结
随着 UI 界面的开发次数增多,已经熟悉了 Android 的 UI 开发风格,已经可以完全掌握了,但还有一些如选择器、自定义控件样式需要深入学习,Android 的代码书写风格也已经完全熟悉,接下来就是知识点与知识面的掌握度了。
本文的主要知识点有两个:
- AlertDialog 的使用,从它的创建到使用,添加自定义 UI 界面,设置系统按钮(setPositiveButton,setNegativeButton 等)
- md5 加密的使用