Android学习笔记_63_手机安全卫士知识点归纳(3)分享 程序锁 服务 进程管理 widget
1、分享:
Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_SUBJECT, "分享"); shareIntent.putExtra(Intent.EXTRA_TEXT,"推荐你使用一个程序" + item.getAppName()); startActivity(shareIntent);
2、程序锁功能 :
1. 用户要开启的这个应用是哪一个应用.
寻找系统里面是不是这样的广播事件,如果这样直接注册一个广播接收者。不过有的应用不行,所以排除 。 我们发现每个应用程序打开的时间ActivityManager都会暴露出来一段Log.
2. 判断这个应用的包名 程序名 是否是要锁定的应用名字一致 。ActvityManager里面有个方法可以得到最近应用,与长按Home键盘得到的东西是一致的。特别好用的。
可以得到当前正在运行的 任务栈里面的信息。
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List<RunningTaskInfo> infos = manager.getRunningTasks(2); for (RunningTaskInfo info : infos) { System.out.println("tt "+info.topActivity.getPackageName()); }
3、服务:
想要调用同一个进程里面服务里的方法,要绑定这个服务。 想要跨进程访问,就用AIDL。 之所以绑定服务能够调用服务里面的方法,主要是因为 在onBinder方法里面能够返回一个IBinder对象。 先自己做试验,常规的。 如果是绑定,同生共死的,如果你退出activity会 出错。
先开启,后绑定方式。 一个服务也只能被解除绑定一次,多次会出异常。 服务总结: 1、startService()开启的服务会长期运行在后台与服务调用者无关, 调用者结束,服务不会结束,不能调用服务里面的方法。 2、bindService()服务和调用者绑定在一起,如果调用者挂掉了,服务 也会终止,调用者可以访问服务里面的方法。 如果我们既要服务长期在后台运行,又要去调用服务里面的方法。 那么,1、startService()保证服务长期在后台运行,2、bindService() 把服务绑定,调用服务里面的方法。 那么这种如何结束服务呢,首先解绑服务,然后再stop服务这样就结束了。 在单独使用绑定服务的时间,如果调用者关了,但是服务没有停止 ,这样 会报出异常,如果你该服务你已经解除绑定过了,再次解绑还会出错。 针对第一种调用者关了,那么应该在调用者的activity里面重写onDestory() 方法,并且在里面调用 unbind()方法,这样当调用者退出时间,它也会自动 退出。
3、看门狗逻辑:
看门狗服务第一创建出的时间,应该去找任务栈中的应用是否在 锁定状态(访问数据库知道) 太厉害了,让一个服务一直反复监听执行,原来是用循环。 服务里面激活任务栈: 在安卓中数据通信就两点, 一是跟后台持久化的东西, 二是前台各个控件之间通信。 掌握到这两点即可。 结束当前activity,finish()、 后台开启一个服务,弄一个死循环,一直在获取当前运行的 activity是不是在锁定表中,如果是果断弹出相应的输入密码界面。 stopService(iservic) 会调用服务中的ondestory()方法。 其实这个看门狗非常简单,就是在发现被锁定的程序运行时间,赶紧自己 弹出一个输入密码的activity去在当前任务栈中新加一个,但是,如果 用户按后退的时间就挂了,会回去要打开的程序中,所以屏蔽后退按钮。 1. 用户输入密码正确. 通知看门狗 临时的停止对这个程序的保护 就需要调用服务里面的方法 。 2. 更新完毕数据库之后 通知看门狗 更新lockapp集合里面的内容
4、进程管理:
为什么需要进程管理,因为它不自动去关闭后台进程。它是一个多任务的, 你退出后,留下一个空进程,不过这些做,在你再次打开的时间就比较快了 这些多个应用切换的时间就比较快了。 activity的Tittle管理(customertitle)。 setText()不以设置为int类型,必须转化成字符串,因为 这是一个重载的方法,如果你传过去一个int类型,它会认为 你传过去的是一个资源的引用,所以你要把它转化成字符串 它会用另外一个重载方法去处理它。 ActivityManger太强大了,能得到任务栈,进程,内存等。。 获取总内存信息是没有API可以得到的。我们已经得到的剩余内存,可以通过加上已用的算出总内存。 安卓中重要的类:Build 自定义activityTitle: super.onCreate(savedInstanceState); //1.隐藏掉系统的title 然后自己的layout的布局 上面做出来一个类似title效果 //2.请求系统的服务,让系统的title 使用我们定义的样式 boolean flag = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); //请求系统使用自定义的title, 这一句代码一定要写到setcontentView之前 setContentView(R.layout.task_manager); if (flag) { getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.task_manager_title); } tv_task_count = (TextView) this.findViewById(R.id.tv_task_count); tv_avail_memory = (TextView) this.findViewById(R.id.tv_avail_memory); 思考所有布局的根本方法,先不要想什么细节,而是直接把大块给划分好。先把块一分好,确定大块的布局即可。 不会说谁会覆盖谁,如果是这样,你就想的太多了。因为可以设置它。 如果ListView控件过多,定义一个静态类,专门去存储它。 对ListView进行分组。复杂的ListView再复杂的就是在getView里面做的复杂的业务逻辑。
public class TaskManagerActivity extends Activity{ private TextView tv_task_count; private TextView tv_avail_memory; private ActivityManager am;//它很强大,可以得到任务栈,内存,进程等。 private List<RunningAppProcessInfo> runingappinfos;//所以正在运行的进程信息 private ListView lv_task_manager;//用来装内容 的 private LinearLayout ll_task_manager_loading;//模态图标 private TaskInfoProvider taskInfoprovider;// private List<TaskInfo> listtaskinfos;//所有任务信息列表 private List<TaskInfo> usertaskinfos;//用户信息列表 private List<TaskInfo> systemtaskinfos;//系统信息列表 private TaskInfoAdapter adapter; private long totalused = 0;// 所有程序占用的内存信息 kb private Handler handler = new Handler(){ @Override public void handleMessage(android.os.Message msg) { ll_task_manager_loading.setVisibility(View.INVISIBLE); long totalmemoryinfo = totalused*1024 + getAvailMemoryInfo();//占用的内存加上可用的内存等于总内存 String strtotalmemory = TextFormater.getDataSize(totalmemoryinfo); String text = tv_avail_memory.getText().toString() + "总内存:"+ strtotalmemory; tv_avail_memory.setText(text); adapter = new TaskInfoAdapter(); lv_task_manager.setAdapter(adapter); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //1.隐藏掉系统的title 然后自己的layout的布局 上面做出来一个类似title效果 //2.请求系统的服务,让系统的title 使用我们定义的样式 boolean flag = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); //请求系统使用自定义的title, 这一句代码一定要写到setcontentView之前 setContentView(R.layout.task_manager); if (flag) { getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.task_manager_title); } //获取am进程服务 am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); tv_task_count = (TextView) this.findViewById(R.id.tv_task_count); tv_avail_memory = (TextView) this.findViewById(R.id.tv_avail_memory); lv_task_manager = (ListView) this.findViewById(R.id.lv_task_manager); ll_task_manager_loading = (LinearLayout) this.findViewById(R.id.ll_task_manager_loading); taskInfoprovider = new TaskInfoProvider(this); //填充listview的数据 fillData(); } //填充listview的数据 private void fillData() { //设置title的数据 setTitleData(); //先让其处于可见状态 ll_task_manager_loading.setVisibility(View.VISIBLE); //起一个线程,找到所有的任务信息 new Thread(){ @Override public void run() { listtaskinfos = taskInfoprovider.getAllTasks(runingappinfos); totalused = 0; // 所有程序占用的内存信息 kb for(TaskInfo taskInfo : listtaskinfos){ totalused += taskInfo.getMemorysize(); } // 通知界面更新数据 handler.sendEmptyMessage(0); }; }.start(); } /** * 设置title的数据 */ private void setTitleData() { tv_task_count.setText("进程数目: " + getProcessCount()); tv_avail_memory.setText("剩余内存" + TextFormater.getDataSize(getAvailMemoryInfo())); } /** * 获取当前正在运行的进程的数目 * @return */ private int getProcessCount(){ runingappinfos = am.getRunningAppProcesses(); return runingappinfos.size(); } /** * 获取当前系统的剩余的可用内存信息 byte long */ private long getAvailMemoryInfo(){ MemoryInfo outInfo = new ActivityManager.MemoryInfo(); am.getMemoryInfo(outInfo); return outInfo.availMem; } /** * * @author chen * 无论 多么复杂的业务逻辑都是通过在getView里面复杂的业务判断出来的。 */ private class TaskInfoAdapter extends BaseAdapter{ /** * 在构造方法里面完成了用户列表和系统程序列表的区分 */ public TaskInfoAdapter() { usertaskinfos = new ArrayList<TaskInfo>(); systemtaskinfos = new ArrayList<TaskInfo>(); for(TaskInfo taskInfo : listtaskinfos){ if (taskInfo.isSystemapp()) { systemtaskinfos.add(taskInfo); }else { usertaskinfos.add(taskInfo); } } } @Override public int getCount() { return listtaskinfos.size() + 2;//因为显示出来的 } @Override public Object getItem(int position) { if (position == 0) { return 0; }else if (position <= usertaskinfos.size()) { return usertaskinfos.get(position - 1); }else if (position == usertaskinfos.size()+1) { return position; }else if (position <= listtaskinfos.size()+2) { return systemtaskinfos.get(position-usertaskinfos.size() -2); }else { return position; } } @Override public long getItemId(int position) { if (position == 0) { return -1;//这只是一个标识,标识这里面显示的TextView, }else if (position <= usertaskinfos.size()) { return position - 1; }else if (position == usertaskinfos.size()+1) { return -1; }else if (position <= listtaskinfos.size()+2) { return position-usertaskinfos.size() -2; }else { return -1; } } @Override public View getView(int position, View convertView, ViewGroup parent) { // 把这些条目信息 做一下分类 系统进程和用户进程区分出来 if (position == 0) { TextView tv_userapp = new TextView(TaskManagerActivity.this); tv_userapp.setTextSize(22); tv_userapp.setText("用户进程 "+usertaskinfos.size()+"个"); return tv_userapp; }else if (position <= usertaskinfos.size()) { int currentpositon = position - 1; TaskInfo taskInfo = usertaskinfos.get(currentpositon); View view = View.inflate(TaskManagerActivity.this, R.layout.task_manager_item, null); ViewHolder holder = new ViewHolder(); holder.iv = (ImageView) view.findViewById(R.id.iv_app_icon); holder.tv_name = (TextView) view.findViewById(R.id.tv_app_name); holder.tv_memory_size = (TextView) view .findViewById(R.id.tv_app_memory_size); holder.cb_task_checked = (CheckBox) view .findViewById(R.id.cb_task_checked); String packname = taskInfo.getPackname(); System.out.println("包名:"+packname); System.out.println("appname " + taskInfo.getAppname()); //如果是以下三个程序 是不可以被清理的 if ("360safe".equals(taskInfo.getAppname())) { holder.cb_task_checked.setVisibility(View.INVISIBLE); } else { holder.cb_task_checked.setVisibility(View.VISIBLE); } holder.iv.setImageDrawable(taskInfo.getAppicon()); holder.tv_name.setText(taskInfo.getAppname()); holder.tv_memory_size.setText("内存占用: " + TextFormater.getKBDataSize(taskInfo.getMemorysize())); holder.cb_task_checked.setChecked(taskInfo.isIschecked()); return view; }else if (position == usertaskinfos.size()+1) { TextView tv_systemapp = new TextView(TaskManagerActivity.this); tv_systemapp.setText("系统进程 " + systemtaskinfos.size() + "个"); tv_systemapp.setTextSize(22); return tv_systemapp; }else if (position <= listtaskinfos.size() + 2) { int systemposition = position - usertaskinfos.size() - 2; TaskInfo taskInfo = systemtaskinfos.get(systemposition); View view = View.inflate(TaskManagerActivity.this, R.layout.task_manager_item, null); ViewHolder holder = new ViewHolder(); holder.iv = (ImageView) view.findViewById(R.id.iv_app_icon); holder.tv_name = (TextView) view.findViewById(R.id.tv_app_name); holder.tv_memory_size = (TextView) view .findViewById(R.id.tv_app_memory_size); holder.cb_task_checked = (CheckBox) view .findViewById(R.id.cb_task_checked); String packname = taskInfo.getPackname(); //如果是以下三个程序 是不可以被清理的 if ("cn.itcast.mobilesafe".equals(packname) || "system".equals(packname) || "android.process.media".equals(packname)) { holder.cb_task_checked.setVisibility(View.INVISIBLE); } else { holder.cb_task_checked.setVisibility(View.VISIBLE); } holder.iv.setImageDrawable(taskInfo.getAppicon()); holder.tv_name.setText(taskInfo.getAppname()); holder.tv_memory_size.setText("内存占用: " + TextFormater.getKBDataSize(taskInfo.getMemorysize())); holder.cb_task_checked.setChecked(taskInfo.isIschecked()); return view; }else { // 肯定不会执行 return null; } } } /** * @author chen * 用于ListView优化。 */ static class ViewHolder { public ImageView iv; public TextView tv_name; public TextView tv_memory_size; public CheckBox cb_task_checked; } }
CheckBox的二个属性应该都写成false,交给程序员来控制。
android:focusable="false"
android:clickable="false"
4、安全权限获取:
//利用反射获取权限,因为安卓没有提供这个API,但是我们知道它一定要手机中,所以我们在运行时间获取,利用反射。 try { Class clazz = getClass().getClassLoader().loadClass("android.widget.AppSecurityPermissions"); Constructor constructor = clazz.getConstructor(new Class[]{Context.class,String.class}); Object object = constructor.newInstance(new Object[]{this,packName}); Method method = clazz.getDeclaredMethod("getPermissionsView", new Class[]{}); View view = (View) method.invoke(object, new Object[]{}); sv_app_detail.addView(view); } catch (Exception e) { e.printStackTrace(); } //完结后我们把全局上下文的内容清空,提高效率。 myApplication.taskInfo = null;
5、Widget开发;
<receiver android:name="ExampleAppWidgetProvider" > <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>
?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="1800000" android:initialLayout="@layout/main" > </appwidget-provider>
/** * 根据配置文件 每隔固定的时间 更新一下界面 * 最小值 半个小时 1800000毫秒 * onRecevie - > onUpdate * * * 注意 widget这个组件不是在我们的应用程序里面 * 显示在桌面的应用程序 * 不同的桌面 他们的widget的创建和销毁对应的 回调的事件可能会有不同 * android luncher / htc sence / 米ui / 360桌面/awt /qq桌面/.... * * */ public class MyWidget extends AppWidgetProvider { @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); System.out.println("onReceive"); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { System.out.println("onUpdate"); super.onUpdate(context, appWidgetManager, appWidgetIds); } @Override public void onDeleted(Context context, int[] appWidgetIds) { System.out.println("onDeleted"); super.onDeleted(context, appWidgetIds); //当某一个widget被删除的时候 会执行ondelete方法 } @Override public void onEnabled(Context context) { System.out.println("onEnabled"); // widget第一次创建的时候 执行的方法 //可以做 初始化widget数据的操作,开启以后后台 super.onEnabled(context); } @Override public void onDisabled(Context context) { super.onDisabled(context); System.out.println("onDisabled"); // 当所有的widget都被删除的时候 执行 ondisable(); // 停止我们开启的服务 // 删除垃圾文件 临时文件 } }
/*虽然说onupdate 和 onreceiver这两个方法在不同的 平台上略有不同,不过相同的是onEnabled会在第一次 创建的时间执行,它只执行一次,以后只会执行onupdate 和onreceiver方法,当这个widget删除的时间才执行ondeled 方法,当所有桌面小控件都删除的时间才执行ondisabled. 方法,当所有桌面小控件都删除的时间才执行 */ public class ProcessWidget extends AppWidgetProvider extends BroadcastReceiver{}; 所以它本质上是一个广播接收者 做这个东西,记清楚一件事,就是它永远是在这里面去调用后台的服务的,这是最基本的思路, 因为它所有的各种东西是在生命周期里面调用的.这是一条主线. /** * 它在不同的生命周期里面只需要调用不同的方法即可。 * @author chen */ public class ProcessWidget extends AppWidgetProvider { Intent intent ; @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); intent = new Intent(context,UpdateWidgetService.class); context.stopService(intent); } @Override public void onEnabled(Context context) { super.onEnabled(context); intent = new Intent(context,UpdateWidgetService.class); context.startService(intent); } }