本帖最后由 小鲁哥哥 于 2020-1-8 21:57 编辑
【济南中心】Android课程同步笔记day05:Android应用之安全卫士
短信接收广播之锁屏
发送一条特殊指令*lockscreen*到丢失的手机上,手机会锁屏,并且设置锁屏的开启密码,只有输入正确的秘密之后,手机才会解锁,具体的代码在短信广播中实现,如下所示:[Java] 纯文本查看 复制代码 if ("#*lockscreen*#".equals(content)) {
Log.d(TAG, "远程锁屏");
DevicePolicyManager dpm = (DevicePolicyManager) context .getSystemService(Context.DEVICE_POLICY_SERVICE);
// 设置锁屏密码
dpm.resetPassword("123", 0);
// 锁屏
dpm.lockNow();
} 修改锁屏密码: [Java] 纯文本查看 复制代码 if (!"#*lockscreen*#".equals(content)
&& content.startsWith("#*lockscreen*#")) {
Log.d(TAG, "远程锁屏");
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
String password = content.substring("#*lockscreen*#".length());
// 设置锁屏密码
dpm.resetPassword(password, 0);
// 锁屏
dpm.lockNow();
} 短信接收广播之清除数据
[Java] 纯文本查看 复制代码 if ("#*wipedata*#".equals(content)) {
Log.d(TAG, "远程消除数据");
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);// 清理内部和外部存储
} 骚扰拦截模块
绘制圆角Shape
[XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<!-- 圆角 -->
<corners android:radius="5dp" />
<!-- 边框 -->
<stroke
android:width="1dp"
android:color="#44000000" />
<!-- 背景 -->
<solid android:color="@android:color/transparent" />
<!-- padding -->
<padding
android:bottom="8dp"
android:left="8dp"
android:right="8dp"
android:top="8dp" />
</shape>
黑名单数据库
要想实现黑名单拦截功能,首先需要根据需求设计一个黑名单数据库(blackNumber.db),该数据库主要用于存储黑名单中的联系人信息,创建包com.itheima.mobilesafe.db,在该包下创建黑名单的数据库,代码如下所示:
[Java] 纯文本查看 复制代码 public class BlackDBHelper extends SQLiteOpenHelper {
public BlackDBHelper(Context context) {
super(context, BlackDB.NAME, null, BlackDB.VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 建表的操作
db.execSQL(BlackDB.TableBlack.SQL_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
为了方便数据的管理单独创建了一个接口类用于保存和修改数据库相关的操作:
[Java] 纯文本查看 复制代码 /**
*
* 黑名单数据库的表结构类
*
*/
public interface BlackDB {
String NAME = "black.db";
int VERSION = 1;
/**
* 表:black
*
*/
public interface TableBlack {
String TABLE_NAME = "black";
// 列
String COLUMN_ID = "_id";
String COLUMN_NUMBER = "number";
String COLUMN_TYPE = "type";// 电话-0,短信-1,全部-2
// sql
String SQL_CREATE = "CREATE TABLE " + TABLE_NAME + "(" + COLUMN_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NUMBER
+ " TEXT UNIQUE," + COLUMN_TYPE + " INTEGER" + ")";
}
}
联系人的实体类
在实现黑名单拦截时,需要保存黑名单中联系人信息,因此需要定义一个黑名单联系人的实体类,该类中包含三个属性,电话号码、联系人姓名、拦截模式,具体代码如下所示:
[Java] 纯文本查看 复制代码 public class BlackBean {
/**电话拦截*/
public final static int TYPE_CALL = 0;
/**短信拦截*/
public final static int TYPE_SMS = 1;
/**全部拦截*/
public final static int TYPE_ALL = 2;
/**电话号码*/
public String number;
/**拦截模式*/
public int type;
}
数据库操作类
[Java] 纯文本查看 复制代码 public class BlackDao {
private BlackDBHelper mHelper;
public BlackDao(Context context) {
mHelper = new BlackDBHelper(context);
}
public boolean add(String number, int type) {
SQLiteDatabase db = mHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BlackDB.TableBlack.COLUMN_NUMBER, number);
values.put(BlackDB.TableBlack.COLUMN_TYPE, type);
long insert = db.insert(BlackDB.TableBlack.TABLE_NAME, null, values);
db.close();
return insert != -1;
}
public boolean update(String number, int type) {
SQLiteDatabase db = mHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BlackDB.TableBlack.COLUMN_TYPE, type);
String whereClause = BlackDB.TableBlack.COLUMN_NUMBER + "=?";
String[] whereArgs = new String[] { number };
int update = db.update(BlackDB.TableBlack.TABLE_NAME, values,
whereClause, whereArgs);
db.close();
return update != 0;
}
public boolean delete(String number) {
SQLiteDatabase db = mHelper.getWritableDatabase();
String whereClause = BlackDB.TableBlack.COLUMN_NUMBER + "=?";
String[] whereArgs = new String[] { number };
int delete = db.delete(BlackDB.TableBlack.TABLE_NAME, whereClause,
whereArgs);
db.close();
return delete != 0;
}
public List<BlackBean> findAll() {
List<BlackBean> list = new ArrayList<BlackBean>();
SQLiteDatabase db = mHelper.getReadableDatabase();
String sql = "select " + BlackDB.TableBlack.COLUMN_NUMBER + ","
+ BlackDB.TableBlack.COLUMN_TYPE + " from "
+ BlackDB.TableBlack.TABLE_NAME;
Cursor cursor = db.rawQuery(sql, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String number = cursor.getString(0);
int type = cursor.getInt(1);
BlackBean bean = new BlackBean();
bean.number = number;
bean.type = type;
list.add(bean);
}
// 关闭
cursor.close();
}
db.close();
return list;
}
public List<BlackBean> findPart(int pageSize, int index) {
// select * from black limit 10 offset 20;
// limit:查询的数量
// offset:从第几条查询
List<BlackBean> list = new ArrayList<BlackBean>();
SQLiteDatabase db = mHelper.getReadableDatabase();
String sql = "select " + BlackDB.TableBlack.COLUMN_NUMBER + ","
+ BlackDB.TableBlack.COLUMN_TYPE + " from "
+ BlackDB.TableBlack.TABLE_NAME + " limit " + pageSize
+ " offset " + index;
Cursor cursor = db.rawQuery(sql, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String number = cursor.getString(0);
int type = cursor.getInt(1);
BlackBean bean = new BlackBean();
bean.number = number;
bean.type = type;
list.add(bean);
}
// 关闭
cursor.close();
}
db.close();
return list;
}
public int findType(String number) {
SQLiteDatabase db = mHelper.getReadableDatabase();
String sql = "select " + BlackDB.TableBlack.COLUMN_TYPE + " from "
+ BlackDB.TableBlack.TABLE_NAME + " where "
+ BlackDB.TableBlack.COLUMN_NUMBER + "=?";
Cursor cursor = db.rawQuery(sql, new String[] { number });
int type = -1;// -1没有这个号码
if (cursor != null) {
if (cursor.moveToNext()) {
type = cursor.getInt(0);
}
}
db.close();
return type;
}
}
add()方法用于向数据库中添加数据,首先获取到数据库对象SQLiteDatabase,然后创建ContentValues 对象,最后将电话号码、拦截模式存入到数据库中,并返回数据是否插入成功的状态。
delete()方法用于删除数据,同样先获取数据库对象SQLiteDatabase 然后调用delete()方法,根据电话号码删除数据,并返回删除结果。
update()方法根据接收的电话号码修改黑名单数据库中的拦截模式
findType()方法是根据传递进来的号码获取黑名单拦截模式,判断是电话拦截、短信拦截或者电话和短信都拦截。
findAll( )方法查询黑名单数据库中的所有数据
findPart( )方法用于分页查询数据库中的黑名单数据
测试数据
在程序开发中,开发者需要对每一个新模块或者方法进行测试,以保证代码可运行没有BUG,由于数据库工具类中操作黑名单数据的方法比较多,而且这些数据需要填充到主界面中,为了避免后期出现错误导致调试困难,最好在使用这些方法之前进行测试。 Android 系统自带了测试框架JUnit,接下来使用该框架对数据库工具类中的方法进行测试,注意在清单文件中配置instrumentation节点和uses-library。需要注意的是,在JUnit 测试框架中,测试方法的异常必须抛出,不能try-catch,否则测试框架捕获不到异常。测试类的代码如下所示: [Java] 纯文本查看 复制代码 public class TestBlackDao extends AndroidTestCase {
public void testAdd() {
BlackDao dao = new BlackDao(getContext());
String number = "110";
int type = 0;
boolean add = dao.add(number, type);
assertEquals(true, add);
}
public void testAddList() {
BlackDao dao = new BlackDao(getContext());
Random rdm = new Random();
for (int i = 0; i < 100; i++) {
String number = 12300 + i + "";
int type = rdm.nextInt(3);
dao.add(number, type);
}
}
public void testUpdate() {
BlackDao dao = new BlackDao(getContext());
String number = "110";
int type = 1;
boolean update = dao.update(number, type);
assertEquals(true, update);
}
public void testDelete(){
BlackDao dao = new BlackDao(getContext());
String number = "110";
boolean delete = dao.delete(number);
assertEquals(true, delete);
}
public void testFindAll() {
BlackDao dao = new BlackDao(getContext());
List<BlackBean> list = dao.findAll();
assertEquals(1, list.size());
assertEquals("110", list.get(0).number);
}
public void testFindType() {
BlackDao dao = new BlackDao(getContext());
String number = "110";
int type = dao.findType(number);
assertEquals(1, type);
}
} 更新黑名单
点击黑名单list条目的时候可以让用户再次更新黑名单的拦截模式,这里点击条目就再次进入到添加黑名单界面,不过里面的title和按钮文字的显示如下
这里直接将修改的号码传递过来进行显示,但是不能再修改号码了,只能修改号码的拦截模式,将EditText设置setEnabled()false就可以。
黑名单加载进度条 由于黑名单数据可能会很多,那在加载大量数据的时候为了给用户一个良好的体验效果,最好是给用户一个加载的进度条显示,但是Android 原生的进度条非常不美观,这里ProgressBar 中的loading_bg是我们自定义的进度条样式,它是旋转的动画效果,代码如下所示: [Java] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/loading"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="3600" /> 空数据的展示当没有黑名单数据的时候为了给用户一个良好的体验,这里在listview数据为空的时候显示一个提示的图片:
添加一个ImageView [XML] 纯文本查看 复制代码 <ImageView
android:id="@+id/css_iv_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/empty"
android:visibility="gone" /> 设置空界面, 需要在给ListView设置过Adapter之后, 再去设置空界面 mLvBlacklist.setAdapter(mAdapter); mLvBlacklist.setEmptyView(mIvEmpty); 分页查询
当黑名单数据库数据量特别大的时候,这时候一下子将所有数据都加载出来比较消耗内存和浪费时间,实际开发过程中一般都是进行分页加载。在之前写数据库操作类中大家已经看到了有一个叫做findPart的方法,该方法其实就是指定sql语句的分页查询;通过limit限制每次查询的个数,offset指定从多少条目开始查询来获取到结果。 在主界面代码里面我们只需要将查询的操作改成分页查询即可:
[Java] 纯文本查看 复制代码 // 显示ProgressBar
mPb.setVisibility(View.VISIBLE);
new Thread() {
public void run() {
// 模拟耗时操作
SystemClock.sleep(1000);
// 填充数据
// ArrayList<BlacklistInfo> all = mDao.queryAll();
ArrayList<BlacklistInfo> part = mDao.queryPart(PAGE_SIZE, mDatas.size());
if (part.size() > 0) {
mDatas.addAll(part);
runOnUiThread(new Runnable() {
public void run() {
// 隐藏ProgressBar
mPb.setVisibility(View.INVISIBLE);
// 刷新ListView, 不需要在重新设置Adapter
mAdapter.notifyDataSetChanged();
}
});
} else {
// 没有加载出来数据
runOnUiThread(new Runnable() {
public void run() {
mPb.setVisibility(View.INVISIBLE);
ToastUtil.showToast(getApplicationContext(), "没有更多数据");
}
});
}
};
}.start();
|