【0074】【项目实战】-【手机安全卫士】-【14】高级工具-程序锁
1. 程序锁的效果
【说明】
【1】未加锁和已加锁的功能按钮,可以分类查看是否加锁;
【2】执行加锁之后的条目需要进行再分类;
【3】在下次进入程序中的是否加锁的标志需要读取,使用数据库(程序的数据量大,sp存储不合适)进行记录;




2.数据库
2.1【说明】需要建表


2.2 数据库的操作
【1】插入和删除操作即可;

【源码】/mobilesafe74/src/com/itheima/mobilesafe74/db/dao/AppLockDao.java
1 package com.itheima.mobilesafe74.db.dao; 2 3 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import android.content.ContentValues; 8 import android.content.Context; 9 import android.database.Cursor; 10 import android.database.sqlite.SQLiteDatabase; 11 12 import com.itheima.mobilesafe74.db.AppLockOpenHelper; 13 14 public class AppLockDao { 15 private AppLockOpenHelper appLockOpenHelper; 16 //BlackNumberDao单例模式 17 //1,私有化构造方法 18 private AppLockDao(Context context){ 19 //创建数据库已经其表机构 20 appLockOpenHelper = new AppLockOpenHelper(context); 21 } 22 //2,声明一个当前类的对象 23 private static AppLockDao appLockDao = null; 24 //3,提供一个静态方法,如果当前类的对象为空,创建一个新的 25 public static AppLockDao getInstance(Context context){ 26 if(appLockDao == null){ 27 appLockDao = new AppLockDao(context); 28 } 29 return appLockDao; 30 } 31 32 //插入方法 33 public void insert(String packagename){ 34 SQLiteDatabase db = appLockOpenHelper.getWritableDatabase(); 35 36 ContentValues contentValues = new ContentValues(); 37 contentValues.put("packagename", packagename); 38 39 db.insert("applock", null, contentValues); 40 db.close(); 41 } 42 //删除方法 43 public void delete(String packagename){ 44 SQLiteDatabase db = appLockOpenHelper.getWritableDatabase(); 45 46 ContentValues contentValues = new ContentValues(); 47 contentValues.put("packagename", packagename); 48 49 db.delete("applock", "packagename = ?", new String[]{packagename}); 50 51 db.close(); 52 } 53 //查询所有 54 public List<String> findAll(){ 55 SQLiteDatabase db = appLockOpenHelper.getWritableDatabase(); 56 Cursor cursor = db.query("applock", new String[]{"packagename"}, null, null, null, null, null); 57 List<String> lockPackageList = new ArrayList<String>(); 58 while(cursor.moveToNext()){ 59 lockPackageList.add(cursor.getString(0)); 60 } 61 cursor.close(); 62 db.close(); 63 return lockPackageList; 64 } 65 }
3. 程序锁布局结构
【说明】线性布局、listView;文本框;按钮;
已加锁和未加锁的布局进行切换的显示和隐藏;
已加锁和未加锁的布局一样;

【说明】在高级工具的程序锁中需要注册该按钮的点击事件;

【高级工具-程序锁的布局】

【点击事件的注册】


【新建布局文件】

【背景图片说明】需要使用四张图片,左右两张图片具有不同的圆角;




【布局】分开了未加锁和加锁
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <LinearLayout 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content" 10 android:gravity="center" 11 android:orientation="horizontal" > 12 13 <Button 14 android:id="@+id/bt_unlock" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 android:background="@drawable/tab_left_pressed" 18 android:text="未加锁" 19 android:textColor="#fff" 20 android:textSize="18sp" /> 21 22 <Button 23 android:id="@+id/bt_lock" 24 android:layout_width="wrap_content" 25 android:layout_height="wrap_content" 26 android:text="已加锁" 27 android:background="@drawable/tab_right_default" 28 android:textColor="#fff" 29 android:textSize="18sp" /> 30 </LinearLayout> 31 <LinearLayout 32 android:id="@+id/ll_unlock" 33 android:orientation="vertical" 34 android:layout_width="match_parent" 35 android:layout_height="wrap_content"> 36 <TextView 37 android:id="@+id/tv_unlock" 38 android:layout_width="wrap_content" 39 android:layout_height="wrap_content" 40 android:text="未加锁应用"/> 41 <ListView 42 android:id="@+id/lv_unlock" 43 android:layout_width="match_parent" 44 android:layout_height="match_parent"/> 45 </LinearLayout> 46 <LinearLayout 47 android:id="@+id/ll_lock" 48 android:orientation="vertical" 49 android:visibility="gone" 50 android:layout_width="match_parent" 51 android:layout_height="wrap_content"> 52 <TextView 53 android:id="@+id/tv_lock" 54 android:layout_width="wrap_content" 55 android:layout_height="wrap_content" 56 android:text="未加锁应用"/> 57 <ListView 58 android:id="@+id/lv_lock" 59 android:layout_width="match_parent" 60 android:layout_height="match_parent"/> 61 </LinearLayout> 62 </LinearLayout>
【效果】

4.逻辑编写

4.1【区分是否加锁的应用】

4.2【主线程接收子线程的消息】


4.3 已加锁未加锁数据适配器填充
【说明】通过适配器的构造方法的参数确定是否为加锁程序;


【单个条目的布局】加锁与未加锁的条目布局的区别:右侧图片的锁子的区别;


【布局】/mobilesafe74/res/layout/listview_islock_item.xml
【说明】其中没有增加锁的图片,需要根据是否加锁设置进行临时的修改
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" > 5 <ImageView 6 android:id="@+id/iv_icon" 7 android:layout_width="45dp" 8 android:layout_height="45dp"/> 9 <TextView 10 android:id="@+id/tv_name" 11 android:text="应用名称" 12 android:textSize="18sp" 13 android:layout_centerVertical="true" 14 android:layout_toRightOf="@id/iv_icon" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content"/> 17 <ImageView 18 android:id="@+id/iv_lock" 19 android:layout_alignParentRight="true" 20 android:layout_centerVertical="true" 21 android:layout_width="25dp" 22 android:layout_height="25dp"/> 23 24 </RelativeLayout>

【主线程对消息的处理】

【bug】



【效果】

4.5 未加锁数目的汇总


【bug】问题的原因是将int类型值当做整数使用,在资源文件中找不到;

【修改】

4.6 加锁与未加锁按钮的点击处理
【加锁按钮的事件的处理】


【未加锁按钮的点击事件】


5. 未加锁条目加载到已加锁的界面中的动画
5.1【效果】
【说明】平移动画的效果


5.2 动画的实现


【数据条目的位置的切换】数据条目操作存在两个地方:一个是适配器显示的链表中,一个是数据库中的数据需要删除;


【动画效果的添加】
【小技巧-临时变量的使用】中间赋值,内部类使用外部的对象,需要添加final,但是final修饰的值不能赋值;
技巧:使用中间值,将中间值使用final修饰,也可以在内存类中使用;
之前的值也可以进行赋值;


【动画的完整添加】

【BUG】动画执行到了下一个条目上;

【问题的原因】出现问题的原因:
动画也在执行,数据也在改变;
因此出现了数据已经移除,动画
作用在了下一个顶上来的条目上了;

【解决方法】将动画的执行设置为阻塞式,只有在动画执行结束之后才可以移除数据;
增加动画的事件监听;

【效果】

6.看门狗循环检测开启应用是否为已加锁应用
6.1【BUG】图片的宽高没有设置



6.2 应用分类的互相切换
【ui说明】未加锁的应用加锁之后执行动画跳转到已加锁应用中;
已加锁的应用解锁之后执行动画跳转到未加锁应用中;

6.3【应用逻辑说明】




6.4 程序锁服务的开启


【说明】需要状态和服务进行绑定;

【创建服务】


【监听逻辑】


【注意】

【注意】不能频繁的查询,需要延时;现在写的是1ms循环一次,手机会越运行的越来越卡;

6.5【拦截界面获取应用名称图标过程】

【新建拦截界面】


【加载拦截界面的布局】


【源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <TextView 7 android:id="@+id/tv_app_name" 8 android:text="拦截应用的名称" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content"/> 11 <ImageView 12 android:id="@+id/iv_app_icon" 13 android:background="@drawable/ic_launcher" 14 android:layout_width="45dp" 15 android:layout_height="45dp"/> 16 <EditText 17 android:id="@+id/et_psd" 18 android:hint="请输入解锁密码" 19 android:inputType="textPassword" //文本框的属性 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content"/> 22 <Button 23 android:id="@+id/bt_submit" 24 android:text="提交" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content"/> 27 </LinearLayout>

【拦截界面的逻辑维护】
1 package com.itheima.mobilesafe74.activity; 2 3 import com.itheima.mobilesafe74.R; 4 import com.itheima.mobilesafe74.utils.ToastUtil; 5 6 import android.app.Activity; 7 import android.content.Intent; 8 import android.content.pm.ApplicationInfo; 9 import android.content.pm.PackageManager; 10 import android.content.pm.PackageManager.NameNotFoundException; 11 import android.graphics.drawable.Drawable; 12 import android.os.Bundle; 13 import android.text.TextUtils; 14 import android.view.KeyEvent; 15 import android.view.View; 16 import android.view.View.OnClickListener; 17 import android.widget.Button; 18 import android.widget.EditText; 19 import android.widget.ImageView; 20 import android.widget.TextView; 21 22 public class EnterPsdActivity extends Activity { 23 private String packagename; 24 private TextView tv_app_name; 25 private ImageView iv_app_icon; 26 private EditText et_psd; 27 private Button bt_submit; 28 29 @Override 30 protected void onCreate(Bundle savedInstanceState) { 31 super.onCreate(savedInstanceState); 32 //获取包名 33 packagename = getIntent().getStringExtra("packagename"); 34 setContentView(R.layout.activity_enter_psd); 35 initUI(); 36 initData(); 37 } 38 39 private void initData() { 40 //通过传递过来的包名获取拦截应用的图标以及名称 41 PackageManager pm = getPackageManager(); 42 try { 43 ApplicationInfo applicationInfo = pm.getApplicationInfo(packagename,0); 44 Drawable icon = applicationInfo.loadIcon(pm); 45 iv_app_icon.setBackgroundDrawable(icon); //设置图标 46 tv_app_name.setText(applicationInfo.loadLabel(pm).toString()); //设置应用的名称 47 } catch (NameNotFoundException e) { 48 e.printStackTrace(); 49 } 50 //提交按钮的点击事件 51 bt_submit.setOnClickListener(new OnClickListener() { 52 @Override 53 public void onClick(View v) { 54 String psd = et_psd.getText().toString(); 55 if(!TextUtils.isEmpty(psd)){ 56 if(psd.equals("123")){ 57 //解锁,进入应用,告知看狗口不要再去监听以及解锁的应用,发送广播 58 Intent intent = new Intent("android.intent.action.SKIP"); 59 intent.putExtra("packagename",packagename); 60 sendBroadcast(intent); 61 //解锁:直接结束应用即可; 62 finish(); 63 }else{ 64 ToastUtil.show(getApplicationContext(), "密码错误"); 65 } 66 }else{ 67 ToastUtil.show(getApplicationContext(), "请输入密码"); 68 } 69 } 70 }); 71 } 72 73 private void initUI() { 74 tv_app_name = (TextView) findViewById(R.id.tv_app_name); 75 iv_app_icon = (ImageView) findViewById(R.id.iv_app_icon); 76 77 et_psd = (EditText) findViewById(R.id.et_psd); 78 bt_submit = (Button) findViewById(R.id.bt_submit); 79 } 80 81 @Override 82 public void onBackPressed() { 83 //通过隐式意图,跳转到桌面 84 Intent intent = new Intent(Intent.ACTION_MAIN); 85 intent.addCategory(Intent.CATEGORY_HOME); 86 startActivity(intent); 87 super.onBackPressed(); 88 } 89 }
【BUG】拿栈需要权限



【此时的效果及问题】不输入密码提示输入密码;密码错误提示;输入正确的密码之后进入到下一界面;但是进入了当前的应用界面(有问题!!!);

【问题的原因】栈的原因:
【1】在点击浏览器的时候,当前的应用是浏览器;
【2】当弹出加锁界面的时候,手机卫士成了当前的应用;
【3】手机卫士的拦截界面finish()之后,仍然存在在手机卫士的界面中;


【问题的解决】单独为拦截界面开启一个栈;


[配置拦截界面的栈的开启模式]

【新BUG】弹出浏览器之后又跳回来了;

【问题的原因】看门狗在一直监测,只要进入到加锁的应用就会一直监视进入到输入密码的界面;
【问题的解决】发送广播,通知看门狗,过滤掉该应用,不要再弹出输入密码认证的界面;

[对广播的接收]


【效果】解决了跳回到安全卫士本身的问题;

7.数据库发生改变通知查询数据库所有数据方法重新调用
【存在的bug】在程序锁服务打开的时候,将程序加锁,程序并未真正的加锁;

【说明】在重新关闭-打开加锁服务,此时刚才打开的加锁配置生效了;




【解决的办法】内容观察者





【测试效果】加锁测试:可以弹出应用的密码输入框;
解锁测试:在解锁之后,应用不再弹出输入密码框;
8.程序锁回退按钮处理
8.1【存在的问题】
【1】点开手机卫士的应用,然后点击开浏览器(已加锁)的应用;看到后台具有两个应用;
【2】点击Home按键,将浏览器挂起;
【3】此时点击手机卫士,则会跳转到浏览器中;(此处不合理,可以已经知道是安全卫士为浏览器加的加锁)

【解决的办法】将后台的安全卫士在后台不显示;
【4】现在点击开后台的手机卫士的界面:则显示的是手机卫士的密码输入界面,但是跳转之后的界面是桌面;(没有任何的意义)

8.2 解决的办法


【效果】安全卫士的界面不再显示


9.程序锁回退按钮处理
9.1 存在的问题
【说明】点击回退按钮之后会返回到密码输入框,不是正常的逻辑;

9.2 问题的解决


【效果】

10.程序锁结束服务处理
【说明】在Distroy的方法中进行【1】停止看门狗【2】注销广播接收者;【3】注销内容观察者;

浙公网安备 33010602011771号