MobileSafeNotes Day10

##Day10##

#10.1.widgets控件# (重点)

AppWidgetProvider  : 广播接受者

创建步骤
	1.第一步创建一个广播接受者AppWidgetProvider
	2.清单文件配置
		<receiver android:name="cn.itcast.mobilesafexian02.receiver.MyWidgets" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/example_appwidget_info" />
   	 	</receiver>
	3.在res -> xml -> example_appwidget_info.xml
		<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
		    android:minWidth="272dp"
		    android:minHeight="72dp"
		    android:updatePeriodMillis="0"
		    android:initialLayout="@layout/example_appwidget"
		    android:resizeMode="horizontal|vertical"
		    android:widgetCategory="home_screen|keyguard"
		    >
		</appwidget-provider>
		
		<!-- 
			minWidth、minHeight :最小的宽度和高度
			updatePeriodMillis : widgets更新时间,毫秒值,但是不能小于30分钟,0其实跟30分钟一样的效果
			previewImage : 预览图片,不设置,就会使用应用程序的图标
			initialLayout : widgets的布局
			configure :可选属性,创建widgets的时候启动的activity
			resizeMode : 设置widget显示尺寸的规则,设置屏幕水平和垂直切换到显示widget的风格
			widgetCategory : widget可以显示的地方,home_screen:桌面  keyguard:键盘
			initialKeyguardLayout : widget在锁屏的时候显示到布局
		-->
	

		带@RemoteView注解的控件都是可以显示在widgets里面,没有就不能显示

#10.2widgets生命周期#

第一次创建
	08-21 01:30:02.197: I/System.out(1677): onEnabled
	08-21 01:30:02.197: I/System.out(1677): onReceive
	08-21 01:30:02.207: I/System.out(1677): onUpdate
	08-21 01:30:02.207: I/System.out(1677): onReceive
	08-21 01:30:04.947: I/System.out(1677): onReceive
第二次创建
	08-21 01:30:50.299: I/System.out(1677): onUpdate
	08-21 01:30:50.299: I/System.out(1677): onReceive
	08-21 01:30:57.099: I/System.out(1677): onReceive
第三次创建
	08-21 01:31:26.969: I/System.out(1677): onUpdate
	08-21 01:31:26.969: I/System.out(1677): onReceive
	08-21 01:31:29.639: I/System.out(1677): onReceive
删除第一个
	08-21 01:32:26.990: I/System.out(1677): onDeleted
	08-21 01:32:26.990: I/System.out(1677): onReceive
删除第二个
	08-21 01:32:54.831: I/System.out(1677): onDeleted
	08-21 01:32:54.831: I/System.out(1677): onReceive
删除最后一个
	08-21 01:33:18.391: I/System.out(1677): onDeleted
	08-21 01:33:18.391: I/System.out(1677): onReceive
	08-21 01:33:18.401: I/System.out(1677): onDisabled
	08-21 01:33:18.401: I/System.out(1677): onReceive

总结:
	1.第一次创建的时候会调用 onEnabled
	2.每次创建都会调用 onUpdate
	3.不管什么操作都会调用onReceive
	4.每次删除都会调用onDeleted
	5.删除最后一个调用onDisabled

#10.3拷贝金山卫士控件布局# (反编译)
1.反编译操作
2.根据action找打清单文件中注册的receiver
3.根据resource找到相应的xml文件
4.根据xml文件中的initialLayout找到相应的布局文件
5.修改错误,完成样式

#10.4.更新widgets中的文本# (重点)

1.创建一个widgetsService
2.在其中的oncreate方法中获取widget管理者
	//1.获取widgets管理者
	appWidgetManager = AppWidgetManager.getInstance(this);
3.更新widgets
	/**
	 * 更新widgets
	 */
	private void updatesWidgets() {
		//		new Thread(){
		//			public void run() {
		//				while(true){
		//					
		//				}
		//			};
		//		}.start();
		Timer timer = new Timer();
		//task : 定时执行的任务
		//when : 延迟执行的时间
		//period : 执行的间隔时间
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() {
				System.out.println("widgets更新了");
				ComponentName provider = new ComponentName(WidgetsService.this, MyWidgets.class);
				//RemoteViews 远程布局
				//packageName: 包名
				//layoutId :widgets的布局文件
				RemoteViews views = new RemoteViews(getPackageName(), R.layout.process_widget);
				//远程布局是不能findviewbyid初始化控件
				//viewId : 要更新控件的id
				//text : 要更新的内容
				views.setTextViewText(R.id.process_count, "正在运行软件:"+ProcessUtils.getAvailableProcess(WidgetsService.this));
				views.setTextViewText(R.id.process_memory, "可用内存:"+Formatter.formatFileSize(WidgetsService.this, ProcessUtils.getAvaliableRam(WidgetsService.this)));
				//更新widgets操作
				appWidgetManager.updateAppWidget(provider, views);
			}
		}, 2000, 2000);
	}
4.在Mywidgets的onEnabled开启服务,在onDisabled关闭服务
	@Override
	public void onEnabled(Context context) {
		super.onEnabled(context);
		System.out.println("onEnabled");
		//开启widgets服务
		Intent intent = new Intent(context,WidgetsService.class);
		context.startService(intent);
	}

	@Override
	public void onDisabled(Context context) {
		super.onDisabled(context);
		System.out.println("onDisabled");
		//关闭服务
		Intent intent = new Intent(context,WidgetsService.class);
		context.stopService(intent);
	}

#10.5widgets点击事件的实现# (重点)

1.在timer中
	//pendingIntent : 延迟意图,包装了一下intent,点击按钮的才会去执行清理的操作,不点击就不会去执行这个intent意图
	views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
2.因为需要一个延迟意图
			Intent intent = new Intent();
			//设置发送的广播事件,action
			intent.setAction("aa.bb.cc");
			//context : 上下文
			//requestCode :请求码
			//intent : 要包装的意图
			//flags : 执行操作的标签
			//发送广播
			PendingIntent pendingIntent = PendingIntent.getBroadcast(WidgetsService.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
			//viewId :执行点击事件的控件的id
			//pendingIntent : 延迟意图,包装了一下intent,点击按钮的才会去执行清理的操作,不点击就不会去执行这个intent意图
			views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
			//更新widgets操作
			appWidgetManager.updateAppWidget(provider, views);
3.因为发送了广播,所以在Oncreate去用代码注册一个广播
	a.创建一个广播接受者
		private class WidgetReceiver extends BroadcastReceiver{

			@Override
			public void onReceive(Context context, Intent intent) {
			}
		}
	b.在oncreate中注册
		widgetReceiver = new WidgetReceiver();
		IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction("aa.bb.cc");
		registerReceiver(widgetReceiver, intentFilter);
	c.在ondestory方法中注销
		@Override
		public void onDestroy() {
			super.onDestroy();
			if (widgetReceiver != null) {
				unregisterReceiver(widgetReceiver);
				widgetReceiver = null;
			}
		}
	d.在广播接受者的onreceive方法中执行清理进程的操作
		@Override
		public void onReceive(Context context, Intent intent) {
			killprocess();
		}
		
		/**
		 * 清理进程
		 */
		public void killprocess() {
			ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
			List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
			for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
				if (!runningAppProcessInfo.processName.equals(getPackageName())) {
					am.killBackgroundProcesses(runningAppProcessInfo.processName);
				}
			}
		}

#10.6锁屏清理进程# (重点)

锁屏和解锁的广播接受者是不能在清单文件中注册的,必须使用代码进行注册,避免一些恶意程序的骚扰

1.隐藏系统进程
	a.创建一个boolean变量,表示是否隐藏系统进程
		//是否显示系统进程
		private boolean isShowSystem = true;
	b.在Myadapter的getCount方法进行判断
		@Override
		public int getCount() {
			//方便我们从不同的集合中拿出数据
			return isShowSystem == true ? userAppInfos.size()+1+systemAppInfos.size()+1 : userAppInfos.size()+1;
		}
	c.在设置的点击事件中更改boolean变量的值
		/**
		 * 设置
		 * @param v
		 */
		public void setting(View v){
			//true改为false   false改为true
			isShowSystem = !isShowSystem;
			//更新界面
			myAdapter.notifyDataSetChanged();
		}
2.锁屏清理进程
	a.在服务中创建一个广播接受者
		private class ScreenOffReceiver extends BroadcastReceiver{

			@Override
			public void onReceive(Context context, Intent intent) {
				killprocess();
				//停止更新widgets
				stopupdate();
			}
		}
	b.在Oncreate方法中注册广播接受者
		//注册锁屏的广播接受者
		screenOffReceiver = new ScreenOffReceiver();
		//设置过滤条件
		IntentFilter screenoffintentfilter = new IntentFilter();
		screenoffintentfilter.addAction(Intent.ACTION_SCREEN_OFF);
		//注册广播接受者
		registerReceiver(screenOffReceiver, screenoffintentfilter);
	c.在ondestory方法中注销广播接受者
		//注销锁屏的广播接受者
		if (screenOffReceiver != null) {
			unregisterReceiver(screenOffReceiver);
			screenOffReceiver = null;
		}
	d.在广播接受者的onreceive方法执行操作
		@Override
		public void onReceive(Context context, Intent intent) {
			killprocess();
			//停止更新widgets
			stopupdate();
		}
3.解锁开启更新的操作
	
	a.在服务中创建一个广播接受者
		private class ScreenOnReceiver extends BroadcastReceiver{

			@Override
			public void onReceive(Context context, Intent intent) {
				updatesWidgets();
			}
		}
	b.在Oncreate方法中注册广播接受者
		//注册解锁的广播接受者
		screenOnReceiver = new ScreenOnReceiver();
		//设置过滤条件
		IntentFilter screenonintentfilter = new IntentFilter();
		screenonintentfilter.addAction(Intent.ACTION_SCREEN_ON);
		//注册广播接受者
		registerReceiver(screenOnReceiver, screenonintentfilter);
	c.在ondestory方法中注销广播接受者
		//注销解锁的广播接受者
		if (screenOnReceiver != null) {
			unregisterReceiver(screenOnReceiver);
			screenOnReceiver = null;
		}
	d.在广播接受者的onreceive方法执行操作
		@Override
		public void onReceive(Context context, Intent intent) {
			updatesWidgets();
		}

#10.7widgets的bug的处理#
bug : 用户从设置中心关闭服务,造成widgets无法更新的问题
updatePeriodMillis 更新时间到了之后就会去调用onUpdate方法
处理方式:将开启服务的操作移植到onUpdate方法

#10.8屏幕适配# (重点,面试)

dp:屏幕像素和屏幕尺寸的比例
px:屏幕像素点

1.使用工具类
	public class DensityUtil {
		/** 
	     * 根据手机的分辨率从 dip 的单位 转成为 px(像素) 
	     */  
	    public static int dip2px(Context context, float dpValue) {  
	        final float scale = context.getResources().getDisplayMetrics().density;  //通过资源获取屏幕的密度
	        return (int) (dpValue * scale + 0.5f); //四舍五入      3.7   3    3.7+0.5 = 4.2   4
	    }  
	  
	    /** 
	     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 
	     */  
	    public static int px2dip(Context context, float pxValue) {  
	        final float scale = context.getResources().getDisplayMetrics().density;  
	        return (int) (pxValue / scale + 0.5f);  
	    }  
	}
2.使用ScrollView
	<!-- ScrollView : 是能让屏幕滚动的控件,但是ScrollView中只能有一个子控件 -->

#10.9创建快捷方式# (重点)

1.可以给软件创建快捷方式
2.可以修改快捷方式的名称
3.可以修改快捷方式的图标
4.设置快方式执行的操作

创建快捷方式的操作
/**
 * 创建快捷方式操作
 */
private void shortCut() {
	
	if (sp.getBoolean("firstEnter", true)) {
		// 添加快捷方式
		// 发送广播
		Intent intent = new Intent(
				"com.android.launcher.action.INSTALL_SHORTCUT");
		// 设置快捷方式的名称
		intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "手机卫士西安2号");
		// 设置快捷方式的图标
		Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.ic_launcher);
		intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
		//隐示意图
		Intent intent2 = new Intent();
		intent2.setAction("cn.itcast.mobilesafexian02.home");
		intent2.addCategory("android.intent.category.DEFAULT");
		// 设置快捷方式要执行的操作
		intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent2);
		// 发送广播
		sendBroadcast(intent);
		
		//更改保存的值
		Editor edit = sp.edit();
		edit.putBoolean("firstEnter", false);
		edit.commit();
	}
}

#10.10监听用户打开的应用程序# (重点)

时时刻刻监听某些操作的行为,watch dog  看门狗
任务栈:管理activity,一个应用就有一个任务栈,打开所有的activity都存放在任务栈

在服务中跳转activity必须给要跳转的activity指明一个任务栈,这样才能跳转

步骤
 在服务oncreate方法中执行
	//1.进程的管理者
	final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
	//2.开启线程时时刻刻监听用户打开的应用程序
	new Thread(){
		public void run() {
			while(isTasks){
				//3.获取正在的运行任务栈
				//maxNum : 获取前几个正在运行的任务栈
				List<RunningTaskInfo> runningTasks = am.getRunningTasks(1);
				for (RunningTaskInfo runningTaskInfo : runningTasks) {
					//4.获取栈底的activity
					ComponentName baseactivity = runningTaskInfo.baseActivity;
					//runningTaskInfo.topActivity;//获取栈顶的activity
					//5.获取应用程序的包名
					String packageName = baseactivity.getPackageName();
					//6.判断获取包名是否是打开的应用程序的包名,是就显示密码输入界面,不是就不管了
					if (packageName.equals("com.android.mms")) {
						Intent intent = new Intent(WatchDogService.this,MainActivity.class);
						//给跳转的activity指明一个任务栈
						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						startActivity(intent);
					}
					System.out.println(packageName);
				}
				SystemClock.sleep(500);
			}
		};
	}.start();

#10.11加锁解锁的操作# (长按事件掌握)

1.在getview的item的布局文件中增加小锁的图标
2.在getview中根据数据库中保存的是否有条目的包名来显示相应的图标
		//根据包名去显示应用是否是已经加锁的操作
		if (watchDogDao.queryLockApp(appInfo.getPackageName())) {
			//显示加锁状态
			viewHolder.iv_itemsoftmanager_islock.setImageResource(R.drawable.lock);
		}else{
			//显示解锁状态
			viewHolder.iv_itemsoftmanager_islock.setImageResource(R.drawable.unlock);
		}
3.给listview增加长按点击事件
		/**
		 * listview的条目长按点击事件
		 */
		private void listviewitemLongClick() {
			lv_softmanager_applications.setOnItemLongClickListener(new OnItemLongClickListener() {
	
				@Override
				public boolean onItemLongClick(AdapterView<?> parent, View view,
						int position, long id) {
					//1.屏蔽用户程序多少个和系统程序多少个
					if (position == 0 || position == userAppInfos.size()+1) {
						return true;
					}
					//2.获取软件信息
					//获取条目对应的信息
					//判断用户程序是否展示完
					if (position <= userAppInfos.size()) {
						//获取用户程序
						appInfo = userAppInfos.get(position-1);
					}else{
						//系统程序
						appInfo = systemAppInfos.get(position - userAppInfos.size()-2);
					}
					ViewHolder viewHolder = (ViewHolder) view.getTag();
					//加锁解锁的操作,原先加锁,再点击就是解锁,原先解锁,在点击就是加锁
					if (watchDogDao.queryLockApp(appInfo.getPackageName())) {
						//解锁
						watchDogDao.deleteLockApp(appInfo.getPackageName());
						//更新界面
						viewHolder.iv_itemsoftmanager_islock.setImageResource(R.drawable.unlock);
					}else{
						//加锁
						//自己不能给自己加锁
						if (!appInfo.getPackageName().equals(getPackageName())) {
							watchDogDao.addLockApp(appInfo.getPackageName());
							//更新界面
							viewHolder.iv_itemsoftmanager_islock.setImageResource(R.drawable.lock);
						}
					}
					//true if the callback consumed the long click, false otherwise
					//true:被消费了,执行了,false:表示被拦截了
					return true;
				}
			});
		}

#10.12将监听用户打开的操作移植到手机卫士中#

1.将demo看门狗中watchdogservice操作移植到手机卫士中
2.修改判断用户打开的应用程序是否应该显示输入密码界面的操作
	//6.判断包名是否在数据库中
	if (watchDogDao.queryLockApp(packageName)) {
			//跳转到密码输入界面
			Intent intent = new Intent(WatchDogService.this,WatchDogActivity.class);
			//给跳转到的activity指定一个任务栈
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			startActivity(intent);
	}
3.在设置中心模仿黑名单操作,进行操作

4.解决进入输入密码界面,点击返回键,有进入输入密码界面的bug
	解决:在输入密码界面重写onkeydown方法
		@Override
		public boolean onKeyDown(int keyCode, KeyEvent event) {
			if (keyCode == KeyEvent.KEYCODE_BACK) {
				//跳转到主界面
				/**
				 *  act=android.intent.action.MAIN   action
					cat=[android.intent.category.HOME] category
					cmp=com.android.launcher/com.android.launcher2.Launcher 
				 */
				Intent intent = new Intent();
				intent.setAction("android.intent.action.MAIN");
				intent.addCategory("android.intent.category.HOME");
				startActivity(intent);
			}
			return super.onKeyDown(keyCode, event);
		}

#10.13修改输入密码界面#

1.修改布局文件,增加图标和名称
2.在Watchdogservice中跳转界面的时候,将包名传递过去
	//6.判断包名是否在数据库中
	if (watchDogDao.queryLockApp(packageName)) {
			//跳转到密码输入界面
			Intent intent = new Intent(WatchDogService.this,WatchDogActivity.class);
			//给跳转到的activity指定一个任务栈
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			//将包名传递给密码输入界面,用于显示图标和名称
			intent.putExtra("packagename", packageName);
			startActivity(intent);
	}
3.在watchDogActivity中根据包名获取打开应用程序的图标和名称,在oncreate方法执行
	//显示打开应用的图标和名称
	Intent intent = getIntent();
	//1.获取传递过来的包名
	String packagename = intent.getStringExtra("packagename");
	//2.根据包名获取图标和名称
	PackageManager pm = getPackageManager();
	try {
		//3.根据包名得到ApplicationInfo的信息
		ApplicationInfo applicationInfo = pm.getApplicationInfo(packagename, 0);
		//4.获取图标
		Drawable icon = applicationInfo.loadIcon(pm);
		//5.获取名称
		String name = applicationInfo.loadLabel(pm).toString();
		//6.设置显示数据
		iv_watchdog_icon.setImageDrawable(icon);
		tv_watchdog_name.setText(name);
	} catch (NameNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值