1.基本思路 ①.創建已加鎖應用的資料庫(欄位:_id,packagename),如果應用已加鎖,將加鎖應用的包名維護到資料庫中 ②.已加鎖+未加鎖 == 手機中所有應用(AppInfoProvider) 2.已加鎖和未加鎖的數據適配器 1 class MyAdapter extends BaseA ...
1.基本思路
①.創建已加鎖應用的資料庫(欄位:_id,packagename),如果應用已加鎖,將加鎖應用的包名維護到資料庫中
②.已加鎖+未加鎖 == 手機中所有應用(AppInfoProvider)
2.已加鎖和未加鎖的數據適配器
1 class MyAdapter extends BaseAdapter{ 2 private boolean isLock; 3 /** 4 * @param isLock 用於區分已加鎖和未加鎖應用的標示 true已加鎖數據適配器 false未加鎖數據適配器 5 */ 6 public MyAdapter(boolean isLock) { 7 this.isLock = isLock; 8 } 9 @Override 10 public int getCount() { 11 if(isLock){ 12 tv_lock.setText("已加鎖應用:"+mLockList.size()); 13 return mLockList.size(); 14 }else{ 15 tv_unlock.setText("未加鎖應用:"+mUnLockList.size()); 16 return mUnLockList.size(); 17 } 18 } 19 20 @Override 21 public AppInfo getItem(int position) { 22 if(isLock){ 23 return mLockList.get(position); 24 }else{ 25 return mUnLockList.get(position); 26 } 27 } 28 29 @Override 30 public long getItemId(int position) { 31 return position; 32 } 33 34 @Override 35 public View getView(int position, View convertView, ViewGroup parent) { 36 ViewHolder holder = null; 37 if(convertView == null){ 38 convertView = View.inflate(getApplicationContext(), R.layout.listview_islock_item, null); 39 holder = new ViewHolder(); 40 holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon); 41 holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name); 42 holder.iv_lock = (ImageView) convertView.findViewById(R.id.iv_lock); 43 44 convertView.setTag(holder); 45 }else{ 46 holder = (ViewHolder) convertView.getTag(); 47 } 48 final AppInfo appInfo = getItem(position); 49 final View animationView = convertView; 50 51 holder.iv_icon.setBackgroundDrawable(appInfo.icon); 52 holder.tv_name.setText(appInfo.name); 53 if(isLock){ 54 holder.iv_lock.setBackgroundResource(R.drawable.lock); 55 }else{ 56 holder.iv_lock.setBackgroundResource(R.drawable.unlock); 57 } 58 holder.iv_lock.setOnClickListener(new OnClickListener() { 59 @Override 60 public void onClick(View v) { 61 //添加動畫效果,動畫預設是非阻塞的,所以執行動畫的同時,動畫以下的代碼也會執行 62 animationView.startAnimation(mTranslateAnimation);//500毫秒 63 //對動畫執行過程做事件監聽,監聽到動畫執行完成後,再去移除集合中的數據,操作資料庫,刷新界面 64 mTranslateAnimation.setAnimationListener(new AnimationListener() { 65 @Override 66 public void onAnimationStart(Animation animation) { 67 //動畫開始的是調用方法 68 } 69 @Override 70 public void onAnimationRepeat(Animation animation) { 71 //動畫重覆時候調用方法 72 } 73 //動畫執行結束後調用方法 74 @Override 75 public void onAnimationEnd(Animation animation) { 76 if(isLock){ 77 //已加鎖------>未加鎖過程 78 //1.已加鎖集合刪除一個,未加鎖集合添加一個,對象就是getItem方法獲取的對象 79 mLockList.remove(appInfo); 80 mUnLockList.add(appInfo); 81 //2.從已加鎖的資料庫中刪除一條數據 82 mDao.delete(appInfo.packageName); 83 //3.刷新數據適配器 84 mLockAdapter.notifyDataSetChanged(); 85 }else{ 86 //未加鎖------>已加鎖過程 87 //1.已加鎖集合添加一個,未加鎖集合移除一個,對象就是getItem方法獲取的對象 88 mLockList.add(appInfo); 89 mUnLockList.remove(appInfo); 90 //2.從已加鎖的資料庫中插入一條數據 91 mDao.insert(appInfo.packageName); 92 //3.刷新數據適配器 93 mUnLockAdapter.notifyDataSetChanged(); 94 } 95 } 96 }); 97 } 98 }); 99 return convertView; 100 } 101 }MyAdapter
mLockAdapter = new MyAdapter(true); lv_lock.setAdapter(mLockAdapter); mUnLockAdapter = new MyAdapter(false); lv_unlock.setAdapter(mUnLockAdapter);
3.已加鎖和未加鎖條目點擊事件處理
holder.iv_lock.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //添加動畫效果,動畫預設是非阻塞的,所以執行動畫的同時,動畫以下的代碼也會執行 animationView.startAnimation(mTranslateAnimation);//500毫秒 //對動畫執行過程做事件監聽,監聽到動畫執行完成後,再去移除集合中的數據,操作資料庫,刷新界面 mTranslateAnimation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { //動畫開始的是調用方法 } @Override public void onAnimationRepeat(Animation animation) { //動畫重覆時候調用方法 } //動畫執行結束後調用方法 @Override public void onAnimationEnd(Animation animation) { if(isLock){ //已加鎖------>未加鎖過程 //1.已加鎖集合刪除一個,未加鎖集合添加一個,對象就是getItem方法獲取的對象 mLockList.remove(appInfo); mUnLockList.add(appInfo); //2.從已加鎖的資料庫中刪除一條數據 mDao.delete(appInfo.packageName); //3.刷新數據適配器 mLockAdapter.notifyDataSetChanged(); }else{ //未加鎖------>已加鎖過程 //1.已加鎖集合添加一個,未加鎖集合移除一個,對象就是getItem方法獲取的對象 mLockList.add(appInfo); mUnLockList.remove(appInfo); //2.從已加鎖的資料庫中插入一條數據 mDao.insert(appInfo.packageName); //3.刷新數據適配器 mUnLockAdapter.notifyDataSetChanged(); } } }); } });
4.程式鎖必須在服務中去維護
①基本思路
1.判斷當前開啟的應用(現在手機可見任務棧)
2.如果開啟的應用在已加鎖的列表中,彈出攔截界面
3.看門狗服務,一直(死迴圈(子線程,可控))對開啟的應用做監聽
1 public class WatchDogService extends Service { 2 private boolean isWatch; 3 private AppLockDao mDao; 4 private List<String> mPacknameList; 5 private InnerReceiver mInnerReceiver; 6 private String mSkipPackagename; 7 private MyContentObserver mContentObserver; 8 @Override 9 public void onCreate() { 10 //維護一個看門狗的死迴圈,讓其時刻監測現在開啟的應用,是否為程式鎖中要去攔截的應用 11 mDao = AppLockDao.getInstance(this); 12 isWatch = true; 13 watch(); 14 15 IntentFilter intentFilter = new IntentFilter(); 16 intentFilter.addAction("android.intent.action.SKIP"); 17 18 mInnerReceiver = new InnerReceiver(); 19 registerReceiver(mInnerReceiver, intentFilter); 20 21 22 //註冊一個內容觀察者,觀察資料庫的變化,一旦數據有刪除或者添加,則需要讓mPacknameList重新獲取一次數據 23 mContentObserver = new MyContentObserver(new Handler()); 24 getContentResolver().registerContentObserver( 25 Uri.parse("content://applock/change"), true, mContentObserver); 26 super.onCreate(); 27 } 28 29 class MyContentObserver extends ContentObserver{ 30 31 public MyContentObserver(Handler handler) { 32 super(handler); 33 } 34 35 //一旦資料庫發生改變時候調用方法,重新獲取包名所在集合的數據 36 @Override 37 public void onChange(boolean selfChange) { 38 new Thread(){ 39 public void run() { 40 mPacknameList = mDao.findAll(); 41 }; 42 }.start(); 43 super.onChange(selfChange); 44 } 45 } 46 47 class InnerReceiver extends BroadcastReceiver{ 48 @Override 49 public void onReceive(Context context, Intent intent) { 50 //獲取發送廣播過程中傳遞過來的包名,跳過次包名檢測過程 51 mSkipPackagename = intent.getStringExtra("packagename"); 52 } 53 } 54 55 private void watch() { 56 //1,子線程中,開啟一個可控死迴圈 57 new Thread(){ 58 public void run() { 59 mPacknameList = mDao.findAll(); 60 while(isWatch){ 61 //2.監測現在正在開啟的應用,任務棧 62 //3.獲取activity管理者對象 63 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 64 //4.獲取正在開啟應用的任務棧 65 List<RunningTaskInfo> runningTasks = am.getRunningTasks(1); 66 RunningTaskInfo runningTaskInfo = runningTasks.get(0); 67 //5.獲取棧頂的activity,然後在獲取此activity所在應用的包名 68 String packagename = runningTaskInfo.topActivity.getPackageName(); 69 70 //如果任務棧指嚮應用有切換,將mSkipPackagename空字元串 71 72 //6.拿此包名在已加鎖的包名集合中去做比對,如果包含次包名,則需要彈出攔截界面 73 if(mPacknameList.contains(packagename)){ 74 //如果現在檢測的程式,以及解鎖了,則不需要去彈出攔截界面 75 if(!packagename.equals(mSkipPackagename)){ 76 //7,彈出攔截界面 77 Intent intent = new Intent(getApplicationContext(),EnterPsdActivity.class); 78 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 79 intent.putExtra("packagename", packagename); 80 startActivity(intent); 81 } 82 } 83 //睡眠一下,時間片輪轉 84 try { 85 Thread.sleep(500); 86 } catch (InterruptedException e) { 87 e.printStackTrace(); 88 } 89 } 90 }; 91 }.start(); 92 93 } 94 @Override 95 public IBinder onBind(Intent arg0) { 96 return null; 97 } 98 @Override 99 public void onDestroy() { 100 //停止看門狗迴圈 101 isWatch = false; 102 //註銷廣播接受者 103 if(mInnerReceiver!=null){ 104 unregisterReceiver(mInnerReceiver); 105 } 106 //註銷內容觀察者 107 if(mContentObserver!=null){ 108 getContentResolver().unregisterContentObserver(mContentObserver); 109 } 110 super.onDestroy(); 111 } 112 }WatchDogService
1 public class EnterPsdActivity extends Activity { 2 private String packagename; 3 private TextView tv_app_name; 4 private ImageView iv_app_icon; 5 private EditText et_psd; 6 private Button bt_submit; 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 //獲取包名 12 packagename = getIntent().getStringExtra("packagename"); 13 setContentView(R.layout.activity_enter_psd); 14 initUI(); 15 initData(); 16 } 17 18 private void initData() { 19 //通過傳遞過來的包名獲取攔截應用的圖標以及名稱 20 PackageManager pm = getPackageManager(); 21 try { 22 ApplicationInfo applicationInfo = pm.getApplicationInfo(packagename,0); 23 Drawable icon = applicationInfo.loadIcon(pm); 24 iv_app_icon.setBackgroundDrawable(icon); 25 tv_app_name.setText(applicationInfo.loadLabel(pm).toString()); 26 } catch (NameNotFoundException e) { 27 e.printStackTrace(); 28 } 29 30 bt_submit.setOnClickListener(new OnClickListener() { 31 @Override 32 public void onClick(View v) { 33 String psd = et_psd.getText().toString(); 34 if(!TextUtils.isEmpty(psd)){ 35 if(psd.equals("123")){ 36 //解鎖,進入應用,告知看門口不要再去監聽以及解鎖的應用,發送廣播 37 Intent intent = new Intent("android.intent.action.SKIP"); 38 intent.putExtra("packagename",packagename); 39 sendBroadcast(intent); 40 41 finish(); 42 }else{ 43 ToastUtil.show(getApplicationContext(), "密碼錯誤"); 44 } 45 }else{ 46 ToastUtil.show(getApplicationContext(), "請輸入密碼"); 47 } 48 } 49 }); 50 } 51 52 private void initUI() { 53 tv_app_name = (TextView) findViewById(R.id.tv_app_name); 54 iv_app_icon = (ImageView) findViewById(R.id.iv_app_icon); 55 56 et_psd = (EditText) findViewById(R.id.et_psd); 57 bt_submit = (Button) findViewById(R.id.bt_submit); 58 } 59 60 @Override 61 public void onBackPressed() { 62 //通過隱式意圖,跳轉到桌面 63 Intent intent = new Intent(Intent.ACTION_MAIN); 64 intent.addCategory(Intent.CATEGORY_HOME); 65 startActivity(intent); 66 super.onBackPressed(); 67 } 68 }EnterPsdActivity
5.隱藏最近打開的activity
<activity android:excludeFromRecents="true" android:name="com.itheima.mobilesafe.EnterPwdActivity" android:launchMode="singleInstance" />