編輯:關於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" />
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
Android群英傳筆記——第十二章:Android5.X 新特性詳解,Material Design UI的新體驗
這一章很多,但是很有趣,也是這書的最後一章知識點了,我現在還在考慮要不要寫這個拼圖和2048的案例,在此之前,我們先來玩玩Android5.X的新特性吧!Android
寫一個 ButterKnife
ButterKnife 很多人都用過,能節省很多代碼,最多的就是省去了很多 findViewById 語句。接下來自己寫一個,就叫 BBKnife 吧。分析在使用 But
Android Studio安裝後Fetching android sdk component information超時的解決方案
本文為大家講解的是Android Studio安裝後啟動時Fetching android sdk component information超時的解決方案,感興趣的同
android產品研發(二十二)--)android實用調試技巧
上一篇文章中我們講解了android UI優化方面的知識。我們講解了android中的include、marge、ViewStub標簽,在使用這些標簽時可以簡化我們的布局