上次寫到在進入手機但·防盜界面時需要有密碼限制,首先第一次進入時會彈出對話框提示用戶設置密碼;再次進入時會要求用戶輸入密碼;這次來具體實現上述功能。
### 首次登錄,設置密碼
首先,我們的密碼是保存在SharePreference中的”password”字段里的,在登錄時后臺需要校驗該字段是否已經設置了密碼,若未設置則彈出對話框讓用戶設置,否則要用戶輸入密碼進入手機防盜界面;
- **校驗是否設置了密碼**
~~~
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sp = getSharedPreferences("config", Context.MODE_PRIVATE);
// 判讀用戶是否已經設置了密碼
if (isPwdSetup()) {
Log.i(TAG, "設置了密碼,彈出輸入密碼的對話框");
} else {
Log.i(TAG, "未設置密碼,彈出設置密碼對話框");
showFirstEntryDialog();
}
}
/**
* 檢查sharedpreference中是否有密碼的設置
*
* @return
*/
private boolean isPwdSetup() {
String password = sp.getString("password", null);
if (password == null) {
return false;
} else {
if ("".equals(password)) {
return false;
} else {
return true;
}
}
}
~~~
- **showFirstEntryDialog(),彈出用戶設置密碼對話框**
~~~
/**
* 第一次進入程序時彈出的設置密碼的對話框
* 使用自定義對話框樣式
*/
private void showFirstEntryDialog() {
dialog = new Dialog(this, R.style.MyDialog);
// dialog.setContentView(R.layout.first_entry_dialog);// 設置要顯示的內容
View view = View.inflate(this, R.layout.first_entry_dialog, null);
et_pwd = (EditText) view.findViewById(R.id.et_first_entry_pwd);
et_pwd_confirm = (EditText) view.findViewById(R.id.et_first_entry_pwd_confirm);
Button bt_confirm = (Button) view.findViewById(R.id.bt_first_dialog_confirm);
Button bt_cancel = (Button) view.findViewById(R.id.bt_first_dialog_cancel);
// 設置按鈕對應的點擊事件
bt_confirm.setOnClickListener(this);
bt_cancel.setOnClickListener(this);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(false);// 設置dialog不可以點擊其他地方時消失
dialog.setCancelable(false);// 設置dialog不可以點返回鍵時消失
dialog.show();
}
~~~
- **用戶輸入后,后臺對用戶的輸入進行處理**
~~~
@Override
public void onClick(View view) {
switch(view.getId()){
// 點擊取消
case R.id.bt_first_dialog_cancel:
dialog.dismiss();
break;
case R.id.bt_first_dialog_confirm:
String pwd = et_pwd.getText().toString().trim();
String pwd_confirm = et_pwd_confirm.getText().toString().trim();
// 輸入的密碼中包好空值
if("".equals(pwd) || "".equals(pwd_confirm)){
Toast.makeText(getApplicationContext(), "輸入不能為空!", Toast.LENGTH_LONG).show();
return;
}else{
if(pwd.equals(pwd_confirm)){
Editor editor = sp.edit();
editor.putString("password", pwd);
editor.commit();
}
// 兩次輸入不一致
else{
Toast.makeText(getApplicationContext(), "兩次輸入密碼不相同!", Toast.LENGTH_LONG).show();
return;
}
}
dialog.dismiss();
break;
}
}
~~~
### 效果如下:
初次進入手機防盜界面:

未輸入時點擊確定:

兩次輸入密碼不相同:

### 再次登錄,輸入密碼
- **彈出對話框樣式:normal_entry_dialog.xml**
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dip"
android:layout_height="280dip"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登錄"
android:textColor="@color/textcolor"
android:textSize="24sp" />
<LinearLayout
android:layout_width="300dip"
android:layout_height="wrap_content"
android:background="#ffc8c8c8"
android:orientation="vertical" >
<EditText
android:id="@+id/et_normal_entry_pwd"
android:layout_width="300dip"
android:layout_height="wrap_content"
android:hint="請輸入密碼"
android:password="true" />
</LinearLayout>
<LinearLayout
android:layout_width="300dip"
android:layout_height="50dip"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="@+id/bt_normal_dialog_confirm"
android:layout_width="140dip"
android:layout_height="40dip"
android:background="@drawable/button_background"
android:text="確定"
android:textColor="#ffffffff" />
<Button
android:id="@+id/bt_normal_dialog_cancel"
android:layout_width="140dip"
android:layout_height="40dip"
android:layout_marginLeft="3dip"
android:background="@drawable/button_background"
android:text="取消" />
</LinearLayout>
</LinearLayout>
~~~
- **showNormalEntryDialog方法**
~~~
/**
* 正常登錄的對話框
*
*/
private void showNormalEntryDialog() {
dialog = new Dialog(this, R.style.MyDialog);
View view = View.inflate(this, R.layout.normal_entry_dialog, null);
et_pwd = (EditText) view.findViewById(R.id.et_normal_entry_pwd);
Button bt_confirm = (Button) view.findViewById(R.id.bt_normal_dialog_confirm);
Button bt_cancel = (Button) view.findViewById(R.id.bt_normal_dialog_cancel);
// 設置按鈕對應的點擊事件
bt_confirm.setOnClickListener(this);
bt_cancel.setOnClickListener(this);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(false);// 設置dialog不可以點擊其他地方時消失
// dialog.setCancelable(false);// 設置dialog不可以點返回鍵時消失
dialog.show();
}
~~~
- **按鍵處理:**
~~~
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.bt_normal_dialog_cancel:
dialog.dismiss();
break;
case R.id.bt_normal_dialog_confirm:
String input_pwd = et_pwd.getText().toString();
if("".equals(input_pwd)){
Toast.makeText(getApplicationContext(), "輸入不能為空!", Toast.LENGTH_LONG).show();
return;
}else{
String password = sp.getString("password", "");
if(!password.equals(input_pwd)){
Toast.makeText(getApplicationContext(), "輸入密碼不正確,請重新輸入!", Toast.LENGTH_LONG).show();
et_pwd.selectAll();// 用戶輸入錯誤后,對文本進行全選,方便用戶進行刪除重新輸入
return;
}
}
Log.i(TAG, "加載手機防盜主界面");
dialog.dismiss();
break;
}
}
~~~
### 效果如下:


### 密碼加密存儲
目前我們的密碼存儲都是以明文存儲在SharePreference中的,因此有點Android開發基礎的人都可以獲取到我們設置的密碼。
考慮使用加密算法對密碼加密后進行存儲。
使用JavaSe提供的MessageDigest類進行加密。MessageDigest支持的加密算法包括:MD5、SHA-1、SHA-256。
~~~
package com.liuhao.mobilesafe.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Encoder {
public static String encode(String pwd) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(pwd.getBytes());
StringBuffer sb = new StringBuffer();
for (byte b : bytes) {
String str = Integer.toHexString(0xff & b);// byte是八位字節存儲的,轉化為16進制數,直接與11111111相與
if (str.length() == 1) {
sb.append("0" + str);
} else {
sb.append(str);
}
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("不存在加密算法");
}
}
}
~~~
這樣在存儲密碼時調用encode()方法即可對密碼進行存儲。在讀取時也要用加密后的密文與已存儲的進行對比。
~~~
editor.putString("password", MD5Encoder.encode(pwd));
if(!password.equals(MD5Encoder.encode(input_pwd))){
Toast.makeText(getApplicationContext(), "輸入密碼不正確,請重新輸入!", Toast.LENGTH_LONG).show();
et_pwd.selectAll();// 用戶輸入錯誤后,對文本進行全選,方便用戶進行刪除重新輸入
return;
}
~~~
其實我們僅僅簡單的一次加密也是很不保險的,雖說從算法實現上來說md5加密是不可逆的,但是有些“別有用心”的人,竟然將所有可預見的字符串對應的密文都算出來了,真是。。。
比如這個網站:[http://www.cmd5.com/](http://www.cmd5.com/)

驚呆了,有木有!
所以,以后在重要的網站設置密碼時一定要設的復雜一點!!!
- 前言
- Appcompat_V7問題
- This Android SDK requires Android Developer Toolkit version 23.0.0 or above
- 創建Android項目不自動生成Activity,layout目錄為空
- 新建android項目gen目錄下未生成R文件
- 手機安全衛士02:splash界面ui
- 知識點:Android控件系列之Toast
- 手機安全衛士03:獲取更新的服務器配置,顯示更新對話框
- 異常處理:android.os.NetworkOnMainThreadException--多線程問題
- 知識點:Android控件系列之對話框AlertDialog.Builder
- 手機安全衛士04_01:界面(Activity)之間的切換,Activity和任務棧
- 知識點:Android控件系列之ProgressDialog與ProgressBar
- 手機安全衛士04_02:從服務器下載并安裝新版本安裝包
- 知識點:Intent
- 知識點:Adapter適配器
- 手機安全衛士05_1:程序主界面
- 手機安全衛士05_2:程序主界面,為每個條目添加事件
- 知識點:動態設置布局LayoutInflater
- 知識點:SharedPreferences
- 手機安全衛士06-手機防盜之自定義對話框
- 手機安全衛士07-手機防盜之進入限制
- 手機安全衛士08-一些布局和顯示的細節:State List
- 手機安全衛士09-手機防盜界面設置向導1
- 手機安全衛士10-設置向導之綁定SIM卡