[安卓]手机管家(十九)软件管理之软件锁
来源:互联网 发布:七龙珠战斗力官方数据 编辑:程序博客网 时间:2024/06/02 11:38
要对已经安装的APP加锁,也就说不能改动这个APP
而要实现这个功能,可以偷巧,在要启动的APP即将启动之前,进入加锁的activity
经典的功能watchdog,看看用户触动了哪个功能,很多软件里都有,尤其是安全软件
不能写在activity里,生命周期的问题,需要启动一个service,在后台监听
manifest注册
<service android:name="com.example.watchdogdemo.WatchDogService"></service>
public class WatchDogService extends Service {@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}}
在main里启用
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent service = new Intent(this,WatchDogService.class);startService(service);}
启动后时时刻监视哪个程序被启用
service里一般不能用while(true)来判断,这样很容易阻塞,应该在外面加一个thread
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// TODO Auto-generated method stubnew Thread(new Runnable(){@Overridepublic void run(){// TODO Auto-generated method stubwhile(true){//获取当前程序,若是加锁的,则启动另一个activity//给CPU一个时间去执行别的程序try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();}
由于要动态监测系统的服务,这里需要权限
这里要获得当前被启动的APP,这就需要任务栈,要任务栈就需要activity管理器
任务栈里面按照执行顺序存放着activity,当你拿一个时,就是当前的activity
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {//通过activityManager拿到系统的service<span style="background-color: rgb(255, 102, 102);">ams = (ActivityManager) getSystemService(ACTIVITY_SERVICE);</span>new Thread(new Runnable(){@Overridepublic void run(){// TODO Auto-generated method stubwhile(true){//获取当前程序,若是加锁的,则启动另一个activity//task任务栈,里面放的是activityList<RunningTaskInfo> runningTasks = ams.getRunningTasks(3); for(RunningTaskInfo runningTaskInfo : runningTasks){ String packagename = runningTaskInfo.baseActivity.getPackageName(); //每隔五秒打印一次 System.out.println("WatchDogService.onStartCommand()"+packagename); }//给CPU一个时间去执行别的程序try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}
如何知道哪一个被我们加锁的的程序被启动呢?以短信为例
判断一下
//每隔五秒打印一次 System.out.println("WatchDogService.onStartCommand()"+packagename); if("com.android.mms".equals(packagename)){ //启动我们的watchdog的mainActivity } }//给CPU一个时间去执行别的程序
注意,由于是service跳转到activity,需要设置一个flag,activity间的跳转不需要
if("com.android.mms".equals(packagename)){ //启动我们的watchdog的mainActivity Intent intent = new Intent(WatchDogService.this,MainActivity.class); //由于是由service跳转到activity,service没有任务栈,他需要一个flag intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }
跳转成功后,在watchdog的activity上可以加上一些东西,输入密码解锁
现在有个问题,跳到watchdog后,退回,又会跳回来
需要在main里加一个onBackPressed
@Overridepublic void onBackPressed() {// 跳回到Home界面Intent intent = new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);startActivity(intent);super.onBackPressed();}
让用户选择,在setting里加入一条自定义控件
<com.rjl.mobilephonemanager.ui.SettingItem android:id="@+id/settingitem_watchdog" android:layout_width="fill_parent" android:layout_height="wrap_content" rjl:itemtitle="软件锁" rjl:desc_checkbox_on="开启软件锁" rjl:desc_checkbox_off="关闭软件锁"/>
声明
private SettingItem settingItem_watchdog;
找到
settingItem_watchdog = (SettingItem) findViewById(R.id.settingitem_watchdog);初始化
private void initWatchDog() {// TODO Auto-generated method stubsettingItem_watchdog.setCheck(ServiceUtils.isRunning(this, "com.rjl.mobilephonemanager.service.WatchDogService"));settingItem_watchdog.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (settingItem_watchdog.getChecked()) {settingItem_watchdog.setCheck(false);settingItem_watchdog.setdescriptionoff(); Intent intent = new Intent (SettingActivity.this, WatchDogService.class); stopService(intent);}else {settingItem_watchdog.setCheck(true);settingItem_watchdog.setdescriptionon();Intent intent = new Intent (SettingActivity.this,WatchDogService.class); startService(intent); }}});}
调用
@Overrideprotected void onResume() {// TODO Auto-generated method stubinitAutoUpdateItem( ); initShowAddressItem(); initSetToastBgItem(); initSetToastPostionItem(); intiSetBlackNumItem(); initWatchDog(); System.out.println("SettingActivity.onResume()");super.onResume();}
这个过程中,manifest里加上了权限、activity、service
现在来完善上锁 判断的时候应该获取包名,看他是不是加锁了,没加锁就锁上,锁了就不动
需要在软件管理的list里面操作下
长按加锁、解锁
item_appmanager_appinfo里加一个imageview
<ImageView android:layout_width="40dp" android:layout_height="40dp" android:id="@+id/iv_watchdog_lockstatus" android:src="@drawable/unlock" android:layout_alignParentRight="true" android:layout_marginTop="10dp"/>
APPmanageractivity里加上OnItemLongClickListener
lv_appmanage_appinfolist.setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {// TODO Auto-generated method stubreturn false;}});refreshData();
也是通过position获得APPinformation
现在实现的功能是长按换图标
private ImageView iv_watchdog_lockstatus;
我们要把 应用 上锁状态改变的情况放到数据库,应用名,上锁情况
openhelper
public class WatchDogOpenHelper extends SQLiteOpenHelper {public WatchDogOpenHelper(Context context, String name,CursorFactory factory, int version) {super(context, name, factory, version);// TODO Auto-generated constructor stub}@Overridepublic void onCreate(SQLiteDatabase db) {// TODO Auto-generated method stubString sql = "create table watchdoginfo (_id integer primary key autoincrement, packagename varchar(50) )";db.execSQL(sql);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub}}
dao接口
</pre><pre name="code" class="java">public class WatchDogDao {//增删改查SQLiteDatabase db ;WatchDogOpenHelper helper ;Context ctx ;public WatchDogDao(Context ctx) {this.ctx =ctx; helper = new WatchDogOpenHelper(ctx, "WatchDog.db", null, 1); this.db = helper.getReadableDatabase();}//add public void addPackageName(String name ){ //db.execSQL(sql); ContentValues values = new ContentValues();values.put("packagename", name); db.insert("watchdoginfo", null, values); } //delete public int deletepackagename(String packagename){ int i = db.delete("watchdoginfo", "packagename = ? ", new String[]{packagename});return i; } //query public boolean queryLockStatus(String packagename){boolean flag = false; Cursor cursor= db.query("watchdoginfo", null, "packagename = ?", new String[]{packagename}, null, null, null); if (cursor.moveToNext()) {flag=true;} return flag; }}
APPmanageractivity里初始化dao
dao = new WatchDogDao(this);
注意不能给自己加锁
<pre name="code" class="java">//软件锁换图标lv_appmanage_appinfolist.setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {// TODO Auto-generated method stub AppInfo appinfo_longclick;if (position< user_appinfolist.size()+1) {appinfo_longclick = user_appinfolist.get(position-1);}else {appinfo_longclick = sys_appinfolist.get(position-user_appinfolist.size()-2);}iv_watchdog_lockstatus = (ImageView) view.findViewById(R.id.iv_watchdog_lockstatus);if (dao.queryLockStatus(appinfo_longclick.getPackagename())) {iv_watchdog_lockstatus.setImageResource(R.drawable.unlock); dao.deletepackagename(appinfo_longclick.getPackagename());} else {if (!appinfo_longclick.getPackagename().equals(getPackageName())) {iv_watchdog_lockstatus.setImageResource(R.drawable.lock); dao.addPackageName(appinfo_longclick.getPackagename());}else {Toast.makeText(AppManagementActivity.this, "不能给手机管家加锁!", 1).show();}}return true;}});
回显问题首先 holder复用
<pre name="code" class="java">holder.iv_watchdog_lockstatus = (ImageView) item_layout.findViewById(R.id.iv_watchdog_lockstatus); //3.添加进view item_layout.setTag(holder); }holder.iv_appmanage_icon.setImageDrawable(appInfo.getIcon());holder.tv_appmanage_appname.setText(appInfo.getAppname());if(appInfo.isIs_sdcard()){holder.tv_appmanage_applocation.setText("SD卡存储");}else{holder.tv_appmanage_applocation.setText("手机内存");} return item_layout;}//1.Holder类搞定 class Holder { ImageView iv_appmanage_icon ;TextView tv_appmanage_appname;TextView tv_appmanage_applocation;ImageView iv_watchdog_lockstatus ; } }
其次 默认未上锁,要查询是否上锁
//查询软件是否上锁if (dao.queryLockStatus(appInfo.getPackagename())) { holder.iv_watchdog_lockstatus.setImageResource(R.drawable.lock);}else { holder.iv_watchdog_lockstatus.setImageResource(R.drawable.unlock);}
来完成跳转后的判断上锁问题
要根据数据库中的状态来判断是否要上锁
private WatchDogDao dao;
dao = new WatchDogDao(this);
if (dao.queryLockStatus(packagename)){ //启动我们的watchdog的mainActivity Intent intent = new Intent(WatchDogService.this,WatchDogActivity.class); //由于是由service跳转到activity,service没有任务栈,他需要一个flag intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }
完善用户体验
跳转后显示之前的软件名和图标
watchdog的activity里要获取到包名,由于是从service里跳过来的,要在service里塞一个
if (dao.queryLockStatus(packagename)){ //启动我们的watchdog的mainActivity Intent intent = new Intent(WatchDogService.this,WatchDogActivity.class); //带上包名,方便在watchdog里接收显示 intent.putExtra("packageName", packagename); //由于是由service跳转到activity,service没有任务栈,他需要一个flag intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }
<pre name="code" class="java">I
public class WatchDogActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_watchdog);ImageView iv_watchdog_icon = (ImageView) findViewById(R.id.iv_watchdog_icon);TextView tv_watchdog_name = (TextView) findViewById(R.id.tv_watchdog_name);//获取某个一应用的icon和name 实际上只需要我们拿到该应用的包名就可以Intent intent = getIntent();final String packageName = intent.getStringExtra("packageName");System.out.println("WatchDogActivity.onCreate()"+packageName);if (packageName!=null) {//获取当前锁定的应用的图标和 名字PackageManager pm = getPackageManager();try {ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0); String name = (String) applicationInfo.loadLabel(pm); Drawable icon= applicationInfo.loadIcon(pm); iv_watchdog_icon.setImageDrawable(icon); tv_watchdog_name.setText(name); } catch (NameNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
button响应
Button bt_watchdog_confirm = (Button) findViewById(R.id.bt_watchdog_confirm);final EditText et = (EditText) findViewById(R.id.et_watchdog_password);
<pre name="code" class="java">bt_watchdog_confirm.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {//判断用户输入的密码 跟我们预设的是否一致,如果是一致的话,放行,否则吐司 String password = et.getText().toString(); if (!password.isEmpty()&&"123".equals(password)) { finish(); }else {Toast.makeText(getApplicationContext(), "密码不正确", 0).show();}}});
OK,有几个bug
进入MobilphoneManager的软件管理,然后点击home
这时候他去了后台,没有清空,这时候任务栈里有两个activity,下面是home,上面是软件管理
现在点一个APP,这时应该跳转到看门狗,也就是在之前的任务栈里又加了一个,这时候填密码点击,等于是把自己,看门狗销毁了
这时候回显的是之前的两个activity,点击两次退回才能看到被点击的APP
要解决这个问题,我们最好能单独给看门狗起一个任务栈
在manifest里给看门狗声明的部分加一个launchmode:singleInstance
<activity android:name=".WatchDogActivity" android:launchMode="singleInstance"> </activity>
<!-- standard : 每次启动Activity的时候,都新建一个放到任务栈 singleTop: 如果该Activity在栈顶,就不会创建新的Activity singleTask: 如果当前的Activity已经在任务栈里面 ,就将其上面的Activity都干掉,让其在栈顶显示 singleInstance: 开启一个新的任务栈, 将Activity放入 -->
另一个问题,解锁后循环加锁解锁
这时候解完锁要设置一个标记,而不是直接销毁
C++ 什么的设置一个全局变量就好
这里考虑activity发一个广播 service里来一个接收者
if (!password.isEmpty()&&"123".equals(password)) { //不能直接销毁,而是给一个广播,否则不断解锁加锁死循环,自定义的内容 Intent intent = new Intent("com.rjl.mobilemanager.unlock"); intent.putExtra("packageName", packageName); sendBroadcast(intent); finish(); }else {
class MyUnlockReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stub} }动态注册
public int onStartCommand(Intent intent, int flags, int startId) {//通过activityManager拿到系统的serviceams = (ActivityManager) getSystemService(ACTIVITY_SERVICE);dao = new WatchDogDao(this); IntentFilter filter = new IntentFilter("com.rjl.mobilephonemanager.unlock");registerReceiver(new MyUnlockReceiver(), filter);
这时候一解锁就发消息,此时就可以判断
先接收
lass MyUnlockReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubunlockPackage = intent.getStringExtra("packageName");} }
判断之
if (!packagename.equals(unlockPackage) && dao.queryLockStatus(packagename)){
另一个bug
对某APP加锁密码输入不对,直接按home键出来了,然后再进一个app,发现图标和名称不对,显示的是前一个APP
还是任务栈和生命周期的问题,按home键后,先onpause,然后onstop,看不见了,然后进去,直接onrestart,onresume,没有oncreate,图标不会更新
把相关代码放到onresume里,或者在onstop里干掉自己,一下次就会oncreate
watchdogactivity
@Overrideprotected void onStop() {finish();super.onStop();}
优化,查询数据库很耗时,将查询结果放在内存录,弄一个list的数据结构,list放在内存里,查了一次后就放进去了
public class WatchDogService extends Service { private ActivityManager ams; private WatchDogDao dao; private String unlockPackage; //将查询操作转换为 查询内存里面的数据结构的操作,这样可以大大的节省时间 提高效率 List<String> lockpackageList ;
要去dao里做添加一个查询list
public List<String> queryallPackageName(){ List<String> list = new ArrayList<String>(); Cursor cursor= db.query("watchdoginfo", null, null, null, null, null, null); while (cursor.moveToNext()) { String packagename = cursor.getString(1); list.add(packagename); } return list; }
去service初始化
<pre name="code" class="java">@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {//通过activityManager拿到系统的serviceams = (ActivityManager) getSystemService(ACTIVITY_SERVICE);dao = new WatchDogDao(this); <span style="color:#ff0000;">lockpackageList = dao.queryallPackageName();</span>for (String string : lockpackageList) {System.out.println("WatchDogService.onStartCommand()"+string);}
节省了时间,有可能会内存不够用,其实还可以优化什么比特。。
然后在判断的时候,进这个list
if (!packagename.equals(unlockPackage) && lockpackageList.contains(packagename)){ //启动我们的watchdog的mainActivity Intent intent = new Intent(WatchDogService.this,WatchDogActivity.class);
OK,现在又出现一个bug
给几个APP加锁后退出,再随便点击别的某个APP,发现不会跳转
因为list被固定了,和数据库不同步
需要数据库的一个内容观察者,在数据库发生变化时通知下
需要一个getcontext
public class WatchDogDao {//增删改查SQLiteDatabase db ;WatchDogOpenHelper helper ;<span style="color:#ff0000;">Context ctx</span> ;public WatchDogDao(Context ctx) {<span style="color:#ff0000;">this.ctx =ctx;</span>
<pre name="code" class="java">public void addPackageName(String name ){ //db.execSQL(sql); ContentValues values = new ContentValues();values.put("packagename", name); db.insert("watchdoginfo", null, values);//数据库发生变化时做通知,自己定义的uri,用来被人监听到ctx.getContentResolver().notifyChange(Uri.parse("content://com.rjl.watchdogdb"), null);} //delete public int deletepackagename(String packagename){ int i = db.delete("watchdoginfo", "packagename = ? ", new String[]{packagename});ctx.getContentResolver().notifyChange(Uri.parse("content://com.rjl.watchdogdb"), null);return i; }
service里需要一个观察者,发生变化时则重新查一下数据库
//监听数据库变化class Mycontentobeserver extends ContentObserver {public Mycontentobeserver(Handler handler) {super(handler);// TODO Auto-generated constructor stub}@Overridepublic void onChange(boolean selfChange) {// TODO Auto-generated method stubsuper.onChange(selfChange);lockpackageList = dao.queryallPackageName();Log.i("onChange", "watchdogdb changed!");}}
要注册下,发生变化,则调用上面的onchange重新查
//注册观察者Mycontentobeserver myobeserver = new Mycontentobeserver(new Handler());getContentResolver().registerContentObserver(Uri.parse("content://com.rjl.watchdogdb"), true, myobeserver);
至此核心功能都已经实现,还可以继续做的主要就是密码的问题,保存啊,是否设置同一个密码啊等等
- [安卓]手机管家(十九)软件管理之软件锁
- [安卓]手机管家(十五)软件管理 NO 1.
- [安卓]手机管家(十五)软件管理 NO 2
- [安卓]手机管家(十六)进程管理
- 安卓软件管家(EasyAppManager)
- 安卓手机间谍软件之现状
- 立波软件管家:方便管理安卓手机应用、应用搬家、快速摇摇卸载应用、应用备份(souapp.com搜应用网推荐)
- [安卓]手机管家(十七)进程管理NO. 2
- 软件数据线:电脑端管理安卓手机
- 小作坊的安全管家之软件管理
- [安卓]手机管家(五)防盗之加密
- [安卓]手机管家(七)防盗之左右划屏
- [安卓]手机管家(八)防盗之业务逻辑
- [安卓]手机管家(十三)通讯卫士之listview优化
- Android手机平台的软件管家
- 立波锁屏管家:安卓手机锁屏变得简简单单
- 安卓手机怎么卸载APP软件
- 安卓手机使用远程软件TeamViewer
- 20150610-Python面试
- 大型商贸系统(进货管理)技术解析(四)自营无订单进仓单
- LeetCode Invert Binary Tree
- .gitignore无效,不能过滤某些文件
- NAT类型及检测方法
- [安卓]手机管家(十九)软件管理之软件锁
- Android实习札记(4)---Fragment(碎片)基本概念解析
- Codeforces554A:Kyoya and Photobooks
- 10. Regular Expression Matching
- 第一章 scala 基本语法
- 学习C++动态链接库基础知识 (主要关于QT项目)
- html5手机 input file 上传图片 调用API
- 傅里叶分析 [作 者:韩 昊]
- ios swift模仿qq登陆界面,xml布局