編輯:關於Android編程
本項目是一個比較有趣的項目源碼,可以給其他項目加鎖,程序鎖的原理是一個“看門狗”的服務定時監視頂層activity,如果activity對應的包名是之前上鎖的應用程序的,則彈出一個頁面要求輸入解鎖密碼。
效果如下:
1.基本思路
①.創建已加鎖應用的數據庫(字段:_id,packagename),如果應用已加鎖,將加鎖應用的包名維護到數據庫中
②.已加鎖+未加鎖 == 手機中所有應用(AppInfoProvider)
2.已加鎖和未加鎖的數據適配器
class MyAdapter extends BaseAdapter{ private boolean isLock; /** * @param isLock 用於區分已加鎖和未加鎖應用的標示 true已加鎖數據適配器 false未加鎖數據適配器 */ public MyAdapter(boolean isLock) { this.isLock = isLock; } @Override public int getCount() { if(isLock){ tv_lock.setText("已加鎖應用:"+mLockList.size()); return mLockList.size(); }else{ tv_unlock.setText("未加鎖應用:"+mUnLockList.size()); return mUnLockList.size(); } } @Override public AppInfo getItem(int position) { if(isLock){ return mLockList.get(position); }else{ return mUnLockList.get(position); } } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = View.inflate(getApplicationContext(), R.layout.listview_islock_item, null); holder = new ViewHolder(); holder.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon); holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name); holder.iv_lock = (ImageView) convertView.findViewById(R.id.iv_lock); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } final AppInfo appInfo = getItem(position); final View animationView = convertView; holder.iv_icon.setBackgroundDrawable(appInfo.icon); holder.tv_name.setText(appInfo.name); if(isLock){ holder.iv_lock.setBackgroundResource(R.drawable.lock); }else{ holder.iv_lock.setBackgroundResource(R.drawable.unlock); } 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(); } } }); } }); return convertView; } }
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.程序鎖必須在服務中去維護
①基本思路
public class WatchDogService extends Service { private boolean isWatch; private AppLockDao mDao; private List<String> mPacknameList; private InnerReceiver mInnerReceiver; private String mSkipPackagename; private MyContentObserver mContentObserver; @Override public void onCreate() { //維護一個看門狗的死循環,讓其時刻監測現在開啟的應用,是否為程序鎖中要去攔截的應用 mDao = AppLockDao.getInstance(this); isWatch = true; watch(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("android.intent.action.SKIP"); mInnerReceiver = new InnerReceiver(); registerReceiver(mInnerReceiver, intentFilter); //注冊一個內容觀察者,觀察數據庫的變化,一旦數據有刪除或者添加,則需要讓mPacknameList重新獲取一次數據 mContentObserver = new MyContentObserver(new Handler()); getContentResolver().registerContentObserver( Uri.parse("content://applock/change"), true, mContentObserver); super.onCreate(); } class MyContentObserver extends ContentObserver{ public MyContentObserver(Handler handler) { super(handler); } //一旦數據庫發生改變時候調用方法,重新獲取包名所在集合的數據 @Override public void onChange(boolean selfChange) { new Thread(){ public void run() { mPacknameList = mDao.findAll(); }; }.start(); super.onChange(selfChange); } } class InnerReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { //獲取發送廣播過程中傳遞過來的包名,跳過次包名檢測過程 mSkipPackagename = intent.getStringExtra("packagename"); } } private void watch() { //1,子線程中,開啟一個可控死循環 new Thread(){ public void run() { mPacknameList = mDao.findAll(); while(isWatch){ //2.監測現在正在開啟的應用,任務棧 //3.獲取activity管理者對象 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); //4.獲取正在開啟應用的任務棧 List<RunningTaskInfo> runningTasks = am.getRunningTasks(1); RunningTaskInfo runningTaskInfo = runningTasks.get(0); //5.獲取棧頂的activity,然後在獲取此activity所在應用的包名 String packagename = runningTaskInfo.topActivity.getPackageName(); //如果任務棧指向應用有切換,將mSkipPackagename空字符串 //6.拿此包名在已加鎖的包名集合中去做比對,如果包含次包名,則需要彈出攔截界面 if(mPacknameList.contains(packagename)){ //如果現在檢測的程序,以及解鎖了,則不需要去彈出攔截界面 if(!packagename.equals(mSkipPackagename)){ //7,彈出攔截界面 Intent intent = new Intent(getApplicationContext(),EnterPsdActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra("packagename", packagename); startActivity(intent); } } //睡眠一下,時間片輪轉 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onDestroy() { //停止看門狗循環 isWatch = false; //注銷廣播接受者 if(mInnerReceiver!=null){ unregisterReceiver(mInnerReceiver); } //注銷內容觀察者 if(mContentObserver!=null){ getContentResolver().unregisterContentObserver(mContentObserver); } super.onDestroy(); } }
public class EnterPsdActivity extends Activity { private String packagename; private TextView tv_app_name; private ImageView iv_app_icon; private EditText et_psd; private Button bt_submit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //獲取包名 packagename = getIntent().getStringExtra("packagename"); setContentView(R.layout.activity_enter_psd); initUI(); initData(); } private void initData() { //通過傳遞過來的包名獲取攔截應用的圖標以及名稱 PackageManager pm = getPackageManager(); try { ApplicationInfo applicationInfo = pm.getApplicationInfo(packagename,0); Drawable icon = applicationInfo.loadIcon(pm); iv_app_icon.setBackgroundDrawable(icon); tv_app_name.setText(applicationInfo.loadLabel(pm).toString()); } catch (NameNotFoundException e) { e.printStackTrace(); } bt_submit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String psd = et_psd.getText().toString(); if(!TextUtils.isEmpty(psd)){ if(psd.equals("123")){ //解鎖,進入應用,告知看門口不要再去監聽以及解鎖的應用,發送廣播 Intent intent = new Intent("android.intent.action.SKIP"); intent.putExtra("packagename",packagename); sendBroadcast(intent); finish(); }else{ ToastUtil.show(getApplicationContext(), "密碼錯誤"); } }else{ ToastUtil.show(getApplicationContext(), "請輸入密碼"); } } }); } private void initUI() { tv_app_name = (TextView) findViewById(R.id.tv_app_name); iv_app_icon = (ImageView) findViewById(R.id.iv_app_icon); et_psd = (EditText) findViewById(R.id.et_psd); bt_submit = (Button) findViewById(R.id.bt_submit); } @Override public void onBackPressed() { //通過隱式意圖,跳轉到桌面 Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); startActivity(intent); super.onBackPressed(); } }
5.隱藏最近打開的activity
<activity android:excludeFromRecents="true" android:name="com.itheima.mobilesafe.EnterPwdActivity" android:launchMode="singleInstance" />
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
這一章很多,但是很有趣,也是這書的最後一章知識點了,我現在還在考慮要不要寫這個拼圖和2048的案例,在此之前,我們先來玩玩Android5.X的新特性吧!Android
ButterKnife 很多人都用過,能節省很多代碼,最多的就是省去了很多 findViewById 語句。接下來自己寫一個,就叫 BBKnife 吧。分析在使用 But
本文為大家講解的是Android Studio安裝後啟動時Fetching android sdk component information超時的解決方案,感興趣的同
上一篇文章中我們講解了android UI優化方面的知識。我們講解了android中的include、marge、ViewStub標簽,在使用這些標簽時可以簡化我們的布局