Android程序鎖的實(shí)現(xiàn)以及邏輯
本項(xiàng)目是一個(gè)比較有趣的項(xiàng)目源碼,可以給其他項(xiàng)目加鎖,程序鎖的原理是一個(gè)“看門狗”的服務(wù)定時(shí)監(jiān)視頂層activity,如果activity對應(yīng)的包名是之前上鎖的應(yīng)用程序的,則彈出一個(gè)頁面要求輸入解鎖密碼。
效果如下:

1.基本思路
①.創(chuàng)建已加鎖應(yīng)用的數(shù)據(jù)庫(字段:_id,packagename),如果應(yīng)用已加鎖,將加鎖應(yīng)用的包名維護(hù)到數(shù)據(jù)庫中
②.已加鎖+未加鎖 == 手機(jī)中所有應(yīng)用(AppInfoProvider)
2.已加鎖和未加鎖的數(shù)據(jù)適配器
class MyAdapter extends BaseAdapter{
private boolean isLock;
/**
* @param isLock 用于區(qū)分已加鎖和未加鎖應(yīng)用的標(biāo)示 true已加鎖數(shù)據(jù)適配器 false未加鎖數(shù)據(jù)適配器
*/
public MyAdapter(boolean isLock) {
this.isLock = isLock;
}
@Override
public int getCount() {
if(isLock){
tv_lock.setText("已加鎖應(yīng)用:"+mLockList.size());
return mLockList.size();
}else{
tv_unlock.setText("未加鎖應(yīng)用:"+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) {
//添加動畫效果,動畫默認(rèn)是非阻塞的,所以執(zhí)行動畫的同時(shí),動畫以下的代碼也會執(zhí)行
animationView.startAnimation(mTranslateAnimation);//500毫秒
//對動畫執(zhí)行過程做事件監(jiān)聽,監(jiān)聽到動畫執(zhí)行完成后,再去移除集合中的數(shù)據(jù),操作數(shù)據(jù)庫,刷新界面
mTranslateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//動畫開始的是調(diào)用方法
}
@Override
public void onAnimationRepeat(Animation animation) {
//動畫重復(fù)時(shí)候調(diào)用方法
}
//動畫執(zhí)行結(jié)束后調(diào)用方法
@Override
public void onAnimationEnd(Animation animation) {
if(isLock){
//已加鎖------>未加鎖過程
//1.已加鎖集合刪除一個(gè),未加鎖集合添加一個(gè),對象就是getItem方法獲取的對象
mLockList.remove(appInfo);
mUnLockList.add(appInfo);
//2.從已加鎖的數(shù)據(jù)庫中刪除一條數(shù)據(jù)
mDao.delete(appInfo.packageName);
//3.刷新數(shù)據(jù)適配器
mLockAdapter.notifyDataSetChanged();
}else{
//未加鎖------>已加鎖過程
//1.已加鎖集合添加一個(gè),未加鎖集合移除一個(gè),對象就是getItem方法獲取的對象
mLockList.add(appInfo);
mUnLockList.remove(appInfo);
//2.從已加鎖的數(shù)據(jù)庫中插入一條數(shù)據(jù)
mDao.insert(appInfo.packageName);
//3.刷新數(shù)據(jù)適配器
mUnLockAdapter.notifyDataSetChanged();
}
}
});
}
});
return convertView;
}
}
mLockAdapter = new MyAdapter(true); lv_lock.setAdapter(mLockAdapter); mUnLockAdapter = new MyAdapter(false); lv_unlock.setAdapter(mUnLockAdapter);
3.已加鎖和未加鎖條目點(diǎn)擊事件處理
holder.iv_lock.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//添加動畫效果,動畫默認(rèn)是非阻塞的,所以執(zhí)行動畫的同時(shí),動畫以下的代碼也會執(zhí)行
animationView.startAnimation(mTranslateAnimation);//500毫秒
//對動畫執(zhí)行過程做事件監(jiān)聽,監(jiān)聽到動畫執(zhí)行完成后,再去移除集合中的數(shù)據(jù),操作數(shù)據(jù)庫,刷新界面
mTranslateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//動畫開始的是調(diào)用方法
}
@Override
public void onAnimationRepeat(Animation animation) {
//動畫重復(fù)時(shí)候調(diào)用方法
}
//動畫執(zhí)行結(jié)束后調(diào)用方法
@Override
public void onAnimationEnd(Animation animation) {
if(isLock){
//已加鎖------>未加鎖過程
//1.已加鎖集合刪除一個(gè),未加鎖集合添加一個(gè),對象就是getItem方法獲取的對象
mLockList.remove(appInfo);
mUnLockList.add(appInfo);
//2.從已加鎖的數(shù)據(jù)庫中刪除一條數(shù)據(jù)
mDao.delete(appInfo.packageName);
//3.刷新數(shù)據(jù)適配器
mLockAdapter.notifyDataSetChanged();
}else{
//未加鎖------>已加鎖過程
//1.已加鎖集合添加一個(gè),未加鎖集合移除一個(gè),對象就是getItem方法獲取的對象
mLockList.add(appInfo);
mUnLockList.remove(appInfo);
//2.從已加鎖的數(shù)據(jù)庫中插入一條數(shù)據(jù)
mDao.insert(appInfo.packageName);
//3.刷新數(shù)據(jù)適配器
mUnLockAdapter.notifyDataSetChanged();
}
}
});
}
});
4.程序鎖必須在服務(wù)中去維護(hù)

①基本思路
- 判斷當(dāng)前開啟的應(yīng)用(現(xiàn)在手機(jī)可見任務(wù)棧)
- 如果開啟的應(yīng)用在已加鎖的列表中,彈出攔截界面
- 看門狗服務(wù),一直(死循環(huán)(子線程,可控))對開啟的應(yīng)用做監(jiān)聽
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() {
//維護(hù)一個(gè)看門狗的死循環(huán),讓其時(shí)刻監(jiān)測現(xiàn)在開啟的應(yīng)用,是否為程序鎖中要去攔截的應(yīng)用
mDao = AppLockDao.getInstance(this);
isWatch = true;
watch();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SKIP");
mInnerReceiver = new InnerReceiver();
registerReceiver(mInnerReceiver, intentFilter);
//注冊一個(gè)內(nèi)容觀察者,觀察數(shù)據(jù)庫的變化,一旦數(shù)據(jù)有刪除或者添加,則需要讓mPacknameList重新獲取一次數(shù)據(jù)
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);
}
//一旦數(shù)據(jù)庫發(fā)生改變時(shí)候調(diào)用方法,重新獲取包名所在集合的數(shù)據(jù)
@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) {
//獲取發(fā)送廣播過程中傳遞過來的包名,跳過次包名檢測過程
mSkipPackagename = intent.getStringExtra("packagename");
}
}
private void watch() {
//1,子線程中,開啟一個(gè)可控死循環(huán)
new Thread(){
public void run() {
mPacknameList = mDao.findAll();
while(isWatch){
//2.監(jiān)測現(xiàn)在正在開啟的應(yīng)用,任務(wù)棧
//3.獲取activity管理者對象
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
//4.獲取正在開啟應(yīng)用的任務(wù)棧
List<RunningTaskInfo> runningTasks = am.getRunningTasks(1);
RunningTaskInfo runningTaskInfo = runningTasks.get(0);
//5.獲取棧頂?shù)腶ctivity,然后在獲取此activity所在應(yīng)用的包名
String packagename = runningTaskInfo.topActivity.getPackageName();
//如果任務(wù)棧指向應(yīng)用有切換,將mSkipPackagename空字符串
//6.拿此包名在已加鎖的包名集合中去做比對,如果包含次包名,則需要彈出攔截界面
if(mPacknameList.contains(packagename)){
//如果現(xiàn)在檢測的程序,以及解鎖了,則不需要去彈出攔截界面
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);
}
}
//睡眠一下,時(shí)間片輪轉(zhuǎn)
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onDestroy() {
//停止看門狗循環(huán)
isWatch = false;
//注銷廣播接受者
if(mInnerReceiver!=null){
unregisterReceiver(mInnerReceiver);
}
//注銷內(nèi)容觀察者
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() {
//通過傳遞過來的包名獲取攔截應(yīng)用的圖標(biāo)以及名稱
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")){
//解鎖,進(jìn)入應(yīng)用,告知看門口不要再去監(jiān)聽以及解鎖的應(yīng)用,發(fā)送廣播
Intent intent = new Intent("android.intent.action.SKIP");
intent.putExtra("packagename",packagename);
sendBroadcast(intent);
finish();
}else{
ToastUtil.show(getApplicationContext(), "密碼錯(cuò)誤");
}
}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() {
//通過隱式意圖,跳轉(zhuǎn)到桌面
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" />
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 中Crash時(shí)如何獲取異常信息詳解及實(shí)例
這篇文章主要介紹了Android 中Crash時(shí)如何獲取異常信息詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
詳解Android USB轉(zhuǎn)串口通信開發(fā)基本流程
本篇文章主要介紹了Android USB轉(zhuǎn)串口通信開發(fā)基本流程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
android簡易文件管理器實(shí)例(列表式文件目錄)
下面小編就為大家?guī)硪黄猘ndroid簡易文件管理器實(shí)例(列表式文件目錄)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
Android項(xiàng)目實(shí)戰(zhàn)之百度地圖地點(diǎn)簽到功能
這篇文章主要介紹了Android項(xiàng)目實(shí)戰(zhàn)之百度地圖地點(diǎn)簽到功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
Android 中build.prop 文件與 getprop 命令
這篇文章主要介紹了Android 中build.prop 文件與 getprop 命令的相關(guān)資料,需要的朋友可以參考下2017-06-06
android 使用okhttp可能引發(fā)OOM的一個(gè)點(diǎn)
這篇文章主要介紹了android 使用okhttp可能引發(fā)OOM的一個(gè)點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
基于Android如何實(shí)現(xiàn)將數(shù)據(jù)庫保存到SD卡
有時(shí)候?yàn)榱诵枰?,會將?shù)據(jù)庫保存到外部存儲或者SD卡中(對于這種情況可以通過加密數(shù)據(jù)來避免數(shù)據(jù)被破解),本文給大家分享Android如何實(shí)現(xiàn)將數(shù)據(jù)庫保存到SD卡,對android數(shù)據(jù)庫sd卡相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2015-12-12
android實(shí)現(xiàn)人臉識別技術(shù)的示例代碼
本篇文章主要介紹了android人臉識別技術(shù)的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03
Android編程設(shè)置TextView顏色setTextColor用法實(shí)例
這篇文章主要介紹了Android編程設(shè)置TextView顏色setTextColor用法,結(jié)合實(shí)例形式分析了Android設(shè)置TextView顏色setTextColor、ColorStateList等方法的使用技巧與布局文件的設(shè)置方法,需要的朋友可以參考下2016-01-01

