admin管理员组文章数量:1130349
手机卫士涉及的知识点总结
Splash界面
splash: 溅,洒
- 展现产品的logo提升产品的知名度
- 初始化操作(创建数据库,读取配置文件)
- 连接服务器检查软件授权
- 连接服务器检查软件的更新
自动更新的前提
- 包名一致
- 签名一致
状态选择器
整体取消掉标题栏:在清单文件中加一修改主题
android:theme=”@android:style/Theme.Light.NoTitleBar”
PackageManager:获取各种包的信息(版本、应用程序图标、包信息等)
开源项目框架:
xUtils-2.6.8.jar 断点下载
使用:
HttpUtils httputils=new HttpUtils();
httputils.download(url,target,autoResume,callback);
//url:下载的路径
//targer:存放的路径sd
//autoResume:true是否断点续传
//callback:下载回传
new RequestCallBack<File>(){
重写onSuccess();
重写onFailure();
重写onload();//显示下载进度在textview中当前/总进度
}
开源项目断点下载xUtils耗时操作
HttpUtils http=new HttpUtils();
final File file=new File(Environment.getExternalStorageDirectory(),"xxx.apk");
http.download(data.downLoadUrl, file.getAbsolutePath(), true, new RequestCallBack<File>(){
//下载失败
@Override
public void onFailure(HttpException arg0, String arg1) {
}
//下载成功
@Override
public void onSuccess(ResponseInfo arg0) {
//下载成功,替换安装模板代码
ToastUtils.show(SplashActivity.this, "下载成功");
Intent intent=new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}});
下载替换安装只要调用系统的应用就行:(模板代码)
Itent intent=new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
startActivity(intent);
市面上常用界面-九宫格
状态选择器:
就是在res目录下建立一个drawable文件中定义一个xml文件,设置属性background时引用这个xml文件就行。
//背景颜色选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@android:color/darker_gray" android:state_pressed="true"> //按住时
<item android:drawable="@android:color/darker_gray" android:state_focused="true"> //聚焦时
<item android:drawable="@android:color/transparent" > //默认状态
</item>
</item>
</item>
</selector>
按住图标显示不一样的图片,新建一个tupian.xml文件,引用图标时R.drawable.tupian.xml
//图标状态选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@drawable/app_pressed" android:state_pressed="true"> //按住时
<item android:drawable="@drawable/app_focused"
android:state_focused="true"> //聚焦时
<item android:drawable="@drawable/app" > //默认状态
</item>
</item>
</item>
</selector>
走马灯效果按钮
Button可实现,当点击按钮的时候滚动起来
设置属性
android:focusableInTouchMode="true"
android:ellipsize="marquee"
android:text="显示的内容"
TextView也可以实现滚动走马灯:需要自定义TextView,实现里面的所有构造函数并重写isFocused()直接返回true
@Override
@ExportedProperty(category = "focus")
public boolean isFocused() {
return true;
}
并设置下面几个属性
<coma.mobilephone.ui.FocusedTextView
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="希望我所认识的亲戚朋友远离病痛,远离饥饿,走上富康的道路,过上幸福的的生活!"
/>
这样textview跑马灯效果就可以跑起来了
设置一条线可以使用View
自定义组合控件:textView+checkBox 下面还有一条分割线
public class SettingCheckView extends LinearLayout {
public SettingCheckView(Context context, AttributeSet attrs) {
super(context, attrs);
initial(context);
String bigtitle=attrs.getAttributeValue("http://schemas.android/apk/res/coma.mobilephone", "bigtitle");
TextView tv_title=(TextView) findViewById(R.id.tv_ui_setting);
tv_title.setText(bigtitle);
}
public SettingCheckView(Context context) {
super(context);
initial(context);
}
private void initial(Context context) {
this.setOrientation(LinearLayout.VERTICAL);//
this.addView(View.inflate(context, R.layout.ui_setting_view, null));
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android/apk/res/android"
android:id="@+id/rl_set_update"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:background="@drawable/background" >
<TextView
android:id="@+id/tv_ui_setting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:text="开启自动更新"
android:textSize="20sp" />
<CheckBox
android:id="@+id/cb_set_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:clickable="false"
android:focusable="false" />
<View
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:layout_margin="2dp"
android:background="#88000000" />
</RelativeLayout>
使用时:
<coma.mobilephone.ui.SettingCheckView
android:layout_width="match_parent"
android:layout_height="wrap_content"
mobilephone:bigtitle="我是功能2"
/>
自定义属性:
先声明属性命名空间
xmlns:mobilephone="http://schemas.android/apk/res/coma.mobilephone"
在values定义一个attrs.xml文件,在里面声明功能
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SettingCheckView">
<attr name="bigtitle" format="string"/>
</declare-styleable>
//或者
<declare-styleable name="SettingCheckView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
做到这里就可以使用自定义组合控件了,功能可以设置文本内容,想增加其他的属性,在attrs中定义出来就可以使用了。
自定义对话框:
AlertDialog.Builder builder=new Builder(context);
View dialogview=View.inflate(context, R.layout.show_setup_dialog, null);
builder.setView(view);
builder.show();
//高低版本默认的背景色和字体颜色不一样、使高低版本保持一致的样式需
设置其背景色、文本字体色
AlertDialog.Builder builder=new Builder(MainActivity.this);
View dialogview=View.inflate(context, R.layout.show_setup_dialog, null);
AlertDialog dialog=builder.create();
dialog.setView(dialogview,0,0,0,0);//设置对话框上下左右的距离
dialog.show();
show_setup_dialog的xml布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#BFFF01"
android:text="设置密码"
android:textSize="30dp"
android:gravity="center"/>
<EditText
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:inputType="textPassword"/>
<EditText
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="请确定密码"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:inputType="textPassword"/>
<LinearLayout
android:layout_width="300dp"
android:layout_height="wrap_content">
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:background="@drawable/btn_background"
android:text="取消"
android:layout_marginRight="5dp"
android:layout_height="wrap_content"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:background="@drawable/btn_background"
android:text="确定"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
自定义背景选择器:btn_background.xml(要放在drawable文件下)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@android:color/holo_blue_light" android:state_pressed="true">
<item android:drawable="@android:color/holo_blue_light" android:state_focused="true">
<item android:drawable="@android:color/transparent" >
</item></item></item>
</selector>
当有很多个界面有相同的方法,相同的布局时,都要存储数据时,可定义一个父类让其他的类来继承它
动画的切换效果:
//一句代码,必须要放在Activity或者finish()的后面
overridePendingTransition(R.anim.trans_next_in, R.anim.trans_next_out);
在res目录下建立一个anim文件夹:创建两个xml:trans_next_in.xml和trans_next_out.xml如下
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android/apk/res/android"
android:fromXDelta="100%p"
android:toXDelta="0"
android:toYDelta="0"
android:fromYDelta="0"
android:duration="300">
</translate>
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android/apk/res/android"
android:fromXDelta="0"
android:toXDelta="-100%p"
android:toYDelta="0"
android:fromYDelta="0"
android:duration="300">
</translate>
手势识别器
1、先声明一个手势识别器
private GestureDetector mGestureDetector;
2、初始化一个手势识别器
//2、初始化手势识别器
mGestureDetector=new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
/**
* e1、手指触摸屏幕的一瞬间
* e2、手指离开屏幕的一瞬间
* velocityX、velocityY:水平方向和竖直方向的速度
*
*/
if((e1.getRawX()-e2.getRawX())>150){
showNext();
overridePendingTransition(R.anim.trans_next_in, R.anim.trans_next_out);
return true;
}
if((e2.getRawX()-e1.getRawX())>150){
showPre();
overridePendingTransition(R.anim.trans_pre_in, R.anim.trans_pre_out);
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
3、第三步、使用户识别手势器的动作
//第三步、使用手势识别器识别用户的动作
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
绑定手机卡、获取手机序列号,一个手机号对应一个序列号
//用到一个系统的服务
private TelephonyManager tm=(TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
//获取手机序列号
String sim=tm.getSimSerialNumber();
电话联系人
data/data/com.android.providers.contacts.database.contacts2.db
对应三张表:
查找联系人工具类:
public class ContactsInfoUtils {
public static List<ContactsInfo> getContactsInfo(Context context){
List<ContactsInfo> infocontacts=new ArrayList<ContactsInfo>();
//获取内容提供者的解析器
ContentResolver resolver=context.getContentResolver();
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri=Uri.parse("content://com.android.contacts/data");
//游标
Cursor cursor=resolver.query(uri, new String[]{"contact_id"}, null, null, null);
//遍历游标集合
while(cursor.moveToNext()){
String id=cursor.getString(0);
System.out.println("id"+id);
ContactsInfo infos=new ContactsInfoUtils().new ContactsInfo();
Cursor datacursor=resolver.query(dataUri, new String[]{"data1"}, "raw_contact_id=?", null, null);
while(datacursor.moveToNext()){
String data1=datacursor.getString(0);
String mimetype=datacursor.getString(1);
if("vnd.android.cursor.item/name".equals(mimetype)){
//姓名
infos.name=data1;
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
//电话
infos.phone=data1;
}else if("vnd.android.cursor.item/email_v2".equals(mimetype)){
//电话
infos.email=data1;
}
}
infocontacts.add(infos);
}
return infocontacts;
}
public class ContactsInfo{
public String name;
public String email;
public String phone;
}
}
密码加密:md5 单向加密,不可逆原文–>密文
public static String encode(String text){
try {
MessageDigest digest=MessageDigest.getInstance("md5");
String password="234";
byte[] result=digest.digest(password.getBytes());
StringBuffer sb=new StringBuffer();
for(byte b:result){
String hex=Integer.toHexString(b&0xff)+2;//加盐更好更安全
if(hex.length()==1){
sb.append("0");
}
sb.append(hex);
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
播放报警音乐:便捷方式:src下新建目录raw可放音乐文件
MediaPlayer mediaplayer=MediaPlayer.create(context, R.raw.uri);
//循环播放
mediaplayer.setLooping(true);
//设置音量最大声
mediaplayer.setVolume(1.0f, 1.0f);
mediaplayer.start();
abortBroadcast();
超级管理员:
Android 2.2引入了支持企业应用程序提供Android设备管理API。设备管理API提供了设备管理功能在系统水平。这些api允许您创建安全性敏感的应用程序是有用的在企业环境中,IT专业人员需要丰富的控制员工的设备。例如,内置Android电子邮件应用程序利用了新的api来改善交流的支持。通过电子邮件应用程序,交流管理员可以执行密码策略——包括字母数字密码或数字针——在设备。管理员也可以远程擦除(即恢复工厂默认值)丢失或被盗的手机。用户可以同步他们的电子邮件和日历数据交换。
Email client
Security application that to remove wipe
Device management service and application
一键锁屏应用:能够一键锁屏,一键卸载
步骤:
1、先创建admim类继承DeviceAdminReceiver
2、配置清单文件(参考api文档)
<receiver
android:name="coma.yijian.Admin"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<!-- 元数据,提供设备的超级管理员的配置信息 -->
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
还要新建一个 res目录下xml文件夹并新建device_admin_sample.xml:
声明中使用的安全策略的元数据提供了特定于设备管理员的附加信息,可通过DeviceAdminInfo类进行解析查看,以下为device_admin_sample.xml:的内容
<device-admin xmlns:android="http://schemas.android/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
</uses-policies>
</device-admin>
3、主活动中书写代码
点击按钮一键锁屏:
public void lockscreen(View view){
DevicePolicyManager dpm=(DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who=new ComponentName(this, Admin.class);
if(dpm.isAdminActive(who)){
//重置密码
//dpm.resetPassword("123", 0);
//清除sd卡数据
//dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
dpm.lockNow();
finish();
}else{
Toast.makeText(this, "请先激活应用程序", 0).show();
}
}
使用时:先来到系统设置界面,找到安全、进入设备管理器、找到一键锁屏,点击激活一键锁屏,此时可以使用了。
先激活应用程序
给用户一个很好的体验:来个按钮“先激活应用程序”
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
ComponentName who=new ComponentName(this, Admin.class);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, who);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"请大家赶紧去激活程序吧,首次激活有大礼包!");
startActivity(intent);
一键卸载
再来个卸载按钮:
public void deleteLockScreen(View view){
DevicePolicyManager dpm=(DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who=new ComponentName(this, Admin.class);
dpm.removeActiveAdmin(who);
Intent intent=new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+getPackageName()));
startActivity(intent);
}
获取位置的经纬度(真实标准坐标)在中国要转换成火星坐标才能真正确定位置
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取位置内容提供者
LocationManager lm=(LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria=new Criteria();
//指定高精度
criteria.setAccuracy(Criteria.ACCURACY_FINE);
//指定高耗电量
criteria.setPowerRequirement(Criteria.POWER_HIGH);
//获取最好的内容提供者
String provider =lm.getBestProvider(criteria, true);
lm.requestLocationUpdates(provider, 0, 0, new LocationListener() {
//状态改变时调用
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
//可用时调用
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onLocationChanged(Location location) {
location.getLatitude();//纬度
location.getLongitude();//经度
System.out.println("纬度:"+location.getLatitude()+"------经度:"+location.getLongitude());
TextView text=new TextView(getApplication());
text.setTextColor(Color.RED);
text.setText("纬度:"+location.getLatitude()+"------经度:"+location.getLongitude());
}
} );
}
标准坐标—->>中国的火星坐标
使用算法:导入modifyOffset.java和axisoffset.dat
直接到代码中使用:
ModifyOffset no =ModifyOffset.getInstance(context.getClassLoader().getResourceAsStream("axisoffset.dat"));
//真实坐标X经度 Y为纬度
//不过查找时外国网站经度放在围纬度后面:纬度,经度
PointDouble pt =new PointDouble(x,y);
PointDouble marpoint=mo.s2c(pt);
System.out.println(marpoint.toString());
//输出的是x=。。。。,y=。。。。。经纬度
listView的简单优化
容易内存溢出
1、尽量复用convertview历史的缓存,减少创建新的view对象
2、尽量的减少子孩子的id的查询次数,定义一个viewHolder
View view;
viewHolder holder;
if(convertView!=null){
//复用历史的view对象
view=convertView;
holder=(viewHolder) view.getTag();
}else{
//创建新的孩子时加上标签
holder=new viewHolder();
view=View.inflate(getApplicationContext(), R.layout.item_callsmssafe, null);
holder.black_phone=(TextView) view.findViewById(R.id.tv_black_phone);
holder.black_mode=(TextView) view.findViewById(R.id.tv_black_mode);
view.setTag(holder);
}
//内部类
class viewHolder{
public TextView black_phone;
public TextView black_mode;
public ImageView black_delete;
}
listView显示数据库中的数据时,当listview发生变化时应更新listview数据
//通知listview更新数据
adapter.notifyDataSetChanged();
在清单文件中配置广播接收者的特点是:不管应用程序进程是否存在都能接受到对应广播
短信拦截:开启服务并在里面注册一个广播接收者
开启服务:
Intent intent=new Intent(SettingActivity.this,CallSmsSafeService.class);
startService(intent);
//服务里面代码动态注册一个广播接收者
public class CallSmsSafeService extends Service {
private BlackNumberDao dao;
private InnerReceiver receiver;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
dao=new BlackNumberDao(this);
//动态注册
receiver=new InnerReceiver();
IntentFilter filter=new IntentFilter();
//设置关心短信到来的动作
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
filter.setPriority(Integer.MAX_VALUE);
//代码注册广播接收者
registerReceiver(receiver, filter);
System.out.println("黑名单短信拦截开启了!!!!!");
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
receiver=null;
}
//内部类广播接收者
private class InnerReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//拦截短信
Object[] objs=(Object[]) intent.getExtras().get("pdus");
for(Object obj:objs){
SmsMessage smsMessage=SmsMessage.createFromPdu((byte[])obj);
String address=smsMessage.getOriginatingAddress();
String result=dao.find(address);
if("2".equals(result)||"3".equals(result)){
System.out.println("黑名单短信拦截模式。。。");
abortBroadcast();
}
//智能拦截
String body=smsMessage.getMessageBody();
if(body.contains("天使")){//分词算法
SmsManager.getDefault().sendTextMessage("13531829360", null, "帮你拦截了天使客一条消息", null, null);
abortBroadcast();
}
}
}
}
}
服务断电就会自动停止,用sp存储不会保存状态,读取系统的的运行信息,调用系统的活动和服务管理者ActivityManager可以判断服务是否正在后台运行
/**
* 判断系统的服务是否在后台运行
* context:上下文
* StringName: 服务的全路经名
*/
public static boolean isServiceRunning(Context context,String StringName){
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infos=am.getRunningServices(100);
for(RunningServiceInfo info:infos){
String className=info.service.getClassName();
if(StringName.equals(className)){
return true;
}
}
return false;
}
分词算法:
开源算法:
luncence
利用反射原理挂断电话
/**
* 挂断电话的方法,利用反射
*/
public void endCall() {
try {
Class clazz=CallSmsSafeService.class.getClassLoader().loadClass("android.os.ServiceManager");
Method method=clazz.getDeclaredMethod("getService", String.class);
IBinder ibinder=(IBinder) method.invoke(null, TELEPHONY_SERVICE);
ITelephony iTelephony=ITelephony.Stub.asInterface(ibinder);
iTelephony.endCall();
} catch (Exception e) {
e.printStackTrace();
}
}
删除通话的记录(内容观察者)
//监视呼叫记录的的数据库,看什么时候生成了,
//就把它删除
Uri uri=Uri.parse("content://call_log/calls");
getContentResolver().registerContentObserver(uri, true,new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
deleteCallLog(incomingNumber);
}
});
/**
* 删除拨号记录
* @param incomingNumber
*/
public void deleteCallLog(String incomingNumber) {
ContentResolver resolver=getContentResolver();
Uri uri=Uri.parse("content://call_log/calls");
resolver.delete(uri, "number=?", new String[]{incomingNumber});
}
打断点、看内存、查源码
电话的拦截功能:
/**
* 定义电话管理的服务
*/
private TelephonyManager tm;
private MyPhoneStateListener listener;
/**
* 实例化电话管理的服务
*/
tm=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//注册电话的监听器
listener=new MyPhoneStateListener();
//监听电话的状态的改变
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
监听器的注册
class MyPhoneStateListener extends PhoneStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state){
case TelephonyManager.CALL_STATE_IDLE://空闲状态
break;
case TelephonyManager.CALL_STATE_RINGING://响铃状态
String mode=dao.find(incomingNumber);
if(mode.equals("1")||mode.equals("3")){
System.out.println("挂断电话");
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK://接听状态
break;
}
}
}
ActivityManager:获取进程和服务的管理
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE) ;
//获得系统运行的进程
List<ActivityManager.RunningAppProcessInfo> appList1 = mActivityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo running : appList1) {
System.out.println(running.processName);
}
System.out.println("================");
//获得当前正在运行的service
List<ActivityManager.RunningServiceInfo> appList2 = mActivityManager
.getRunningServices(100);
for (ActivityManager.RunningServiceInfo running : appList2) {
System.out.println(running.service.getClassName());
}
System.out.println("================");
//获得当前正在运行的activity
List<ActivityManager.RunningTaskInfo> appList3 = mActivityManager
.getRunningTasks(1000);
for (ActivityManager.RunningTaskInfo running : appList3) {
System.out.println(running.baseActivity.getClassName());
}
System.out.println("================");
//获得最近运行的应用
List<ActivityManager.RecentTaskInfo> appList4 = mActivityManager
.getRecentTasks(100, 1);
for (ActivityManager.RecentTaskInfo running : appList4) {
System.out.println(running.origActivity.getClassName());
}
判断某个进程或服务是否在后台进行的工具类:
package coma.mobilephone.Utils;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
public class ServicerUtils {
/**
* 判断系统的服务是否在后台运行
*/
public static boolean isServiceRunning(Context context,String StringName){
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infos=am.getRunningServices(1000);
for(ActivityManager.RunningServiceInfo info:infos){
String className=info.service.getClassName();
System.out.println(className);
if(StringName.equals(className)){
System.out.println(className);
return true;
}
}
return false;
}
}
数据库的增删改查
package coma.mobilephone.db.dao;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import coma.mobilephone.db.BlackNumberOpenHeloper;
import coma.mobilephone.domain.BlackNumberInfo;
public class BlackNumberDao {
private BlackNumberOpenHeloper openhelper;
/**
* 数据库的构造函数
* @param context
*/
public BlackNumberDao(Context context) {
super();
openhelper=new BlackNumberOpenHeloper(context);
}
/**
* 往数据库中增加号码
* @param phone 增加的电话号码
* @param mode 模式
* @return
*/
public boolean add(String phone,String mode){
SQLiteDatabase db=openhelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("phone", phone);
values.put("mode", mode);
long id=db.insert("blacknumberinfo", null, values);
db.close();
if(id!=-1){
return true;
}else{
return false;
}
}
/**
* 修改黑名单的拦截模式
* @param phone 要修改的黑名单号码
* @param newmode 新的拦截模式
* @return 修改是否成功
*/
public boolean update(String phone,String newmode){
SQLiteDatabase db=openhelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("mode", newmode);
int rowcount=db.update("blacknumberinfo", values, "phone=?", new String[]{phone});
db.close();
if(rowcount==0){
return false;
}else{
return true;
}
}
/**
* 查找黑名单号码的拦截模式
* @param phone 要查找的电话号码
* @return 返回拦截的模式
*/
public String find(String phone){
String mode=null;
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.query("blacknumberinfo", null, "phone=?", new String[]{phone},null, null, null);
if(cursor.moveToNext()){
mode=cursor.getString(cursor.getColumnIndex("mode"));;
}
cursor.close();
db.close();
return mode;
}
/**
* 删除黑名单号码
* @param phone 要删除的号码
* @return 是否删除成功
*/
public boolean delete(String phone){
SQLiteDatabase db=openhelper.getWritableDatabase();
int rowcount=db.delete("blacknumberinfo", "phone=?", new String[]{phone});
db.close();
if(rowcount==0){
return false;
}{
return true;
}
}
/**
* 返回全部的黑名单信息
* @return
*/
public List<BlackNumberInfo> findAll(){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.query("blacknumberinfo", null, null, null, null, null, "_id desc");
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
分批加载
/**
* 分批加载返回的黑名单信息
* @return
*/
public List<BlackNumberInfo> findPart(int startIndex,int maxCount){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?", new String[]{
String.valueOf(maxCount),String.valueOf(startIndex)
});
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
分页加载解决内存溢出
/**
* 分页加载返回的黑名单信息
* @return
*/
public List<BlackNumberInfo> findPagper(int pagper){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?", new String[]{
String.valueOf(10),String.valueOf(pagper*10)
});
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
/**
* 获取全部总条目
* @return
*/
public int getTotalCount(){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select count(*) from blacknumberinfo ",null);
cursor.moveToNext();
int total=cursor.getInt(0);
cursor.close();
db.close();
return total;
}
}
复制资产目录下的文件到android系统下
/**
* 拷贝资产目录下的数据库到Android系统下
*/
private void copyDB(final String name) {
/*
* 数据库多时可能耗时
*/
new Thread(){
public void run() {
File file=new File(getFilesDir(),name);
if(file.exists()&&file.length()>0){
System.out.println("数据库已经加载过,无需在加载!");
}else{
try {
InputStream is=getAssets().open(name);
FileOutputStream fos=new FileOutputStream(file);
byte[] buffer=new byte[1024];
int len=-1;
while((len=is.read(buffer))!=-1){
fos.write(buffer, 0, len);
}
is.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
}.start();
}
自定义吐司
/**
* 自定义吐司
* @param address
*/
public void showToast(String address) {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
View view = View.inflate(getApplicationContext(), R.layout.item_toast, null);
//设置背景,字体等自定义属性
int which=getSharedPreferences("config", 0).getInt("which", 0);
int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
view.setBackgroundResource(bgs[which]);
TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
tv_address.setText(address);
//设置参数params
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
wm.addView(view, params);
}
及时退出吐司的显示用:wm.removeView(view);
控件的拖拽效果
ImageView imgview= (ImageView) findViewById(R.id.imageview);
imgview.setOnTouchListener(new OnTouchListener() {
int startx;
int starty;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN://手指第一次触摸控件时调用
//获取控件在屏幕上的坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE://手指在控件上移动的事件
//手指移动后的偏移量
int newx=(int) event.getRawX();
int newy=(int) event.getRawY();
int dx=newx-startx;
int dy=newy-starty;
//移动后的控件新坐标
imgview.layout(imgview.getLeft()+dx, imgview.getTop()+dy,
imgview.getRight()+dx, imgview.getBottom()+dy);
//移动后重新初始化控件坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
System.out.println("移动了控件"+startx+"---"+starty);
break;
case MotionEvent.ACTION_UP://手指离开控件的一瞬间
break;
}
return true;
}
});
简单双击效果实现
btn=(Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(firsttime>0){
secondtime=System.currentTimeMillis();
if((secondtime-firsttime)<500){
Toast.makeText(getApplicationContext(), "双击了", 0).show();
firsttime=0;
}else{
firsttime=0;
}
return ;
}
firsttime=System.currentTimeMillis();
new Thread(){
public void run() {
try {
Thread.sleep(500);
firsttime=0;
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
}
});
多次点击事件实现
//定义了多长的数组就是多次点击,3就是连续3击
private long[] mHits=new long[3];
/**
*四个参数:源数组,从第几个开始拷贝,目标数组,从第几个开始拷贝,拷贝的长度
*
*/
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
Toast.makeText(getApplicationContext(), "多次击了", 0).show();
}
自定义吐司加上拖拽的效果图显示
/**
* 自定义吐司
* @param address
*/
public void showToast(String address) {
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
view = View.inflate(getApplicationContext(), R.layout.item_toast, null);
view.setOnTouchListener(new OnTouchListener() {
int startx ;
int starty ;
@SuppressWarnings("deprecation")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN://手指触摸
//获取自定义吐司坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_UP://手指离开
//存储控件的位置坐标
SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);
Editor edit=sp.edit();
edit.putInt("lastx", params.x);
edit.putInt("lasty", params.y);
editmit();
break;
case MotionEvent.ACTION_MOVE://手指移动
//获取偏移量
int newx=(int) event.getRawX();
int newy=(int) event.getRawY();
int dx=newx-startx;
int dy=newy-starty;
params.x +=dx;
params.y +=dy;
//判断view控件是否移出屏幕范围
if(params.x>(wm.getDefaultDisplay().getWidth()-view.getWidth())){
params.x=wm.getDefaultDisplay().getWidth()-view.getWidth();
}
if(params.y>(wm.getDefaultDisplay().getHeight()-view.getHeight())){
params.x=wm.getDefaultDisplay().getHeight()-view.getHeight();
}
wm.updateViewLayout(view, params);
//重新初始化控件坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
}
return true;
}
});
//设置背景颜色
int which=getSharedPreferences("config", 0).getInt("which", 0);
int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
view.setBackgroundResource(bgs[which]);
TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
tv_address.setText(address);
params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
//左上对齐
params.gravity=Gravity.LEFT+Gravity.TOP;
SharedPreferences sp=getSharedPreferences("config", MODE_PRIVATE);
params.x=sp.getInt("lastx", 0);
params.y=sp.getInt("lasty", 0);
params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
wm.addView(view, params);
}
可扩展的ListView(ExpandableListView控件)
public class QuerryUsualNumber extends Activity {
private ExpandableListView exl_listview;
private SQLiteDatabase db;
private TextView tv;
private MyExpandableAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db=SQLiteDatabase.openDatabase("/data/data/coma.mobilephone/files/commonnum.db", null, SQLiteDatabase.OPEN_READONLY);
setContentView(R.layout.activity_querryusualnumber);
exl_listview = (ExpandableListView) findViewById(R.id.exl_listview);
adapter = new MyExpandableAdapter();
//设置适配器
exl_listview.setAdapter(adapter);
//孩子被点击的监听器
exl_listview.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
//点击条目获得数据库返回的数据,并分割提取号码进行拨号
String data=UsualNumberDao.getChildrenNameByPosition(db, groupPosition, childPosition);
String datas[]=data.split("\n");
String name=datas[0];
String number=datas[1];
Toast.makeText(getApplicationContext(), groupPosition+"--"+childPosition+":"+name+":"+number, 0).show();
//点击之后进行拨打指定号码的电话
Intent intent =new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+number));
startActivity(intent);
return true;
}
});
}
适配器
private class MyExpandableAdapter extends BaseExpandableListAdapter{
/**
* 获取分组的个数
*/
@Override
public int getGroupCount() {
return UsualNumberDao.getGroupCount(db);
}
/**
* 获取每个分组的孩子的个数
*/
@Override
public int getChildrenCount(int groupPosition) {
return UsualNumberDao.getChildGroupCount(db,groupPosition);
}
@Override
public Object getGroup(int groupPosition) {
return null;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
@Override
public long getGroupId(int groupPosition) {
return 0;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
@Override
public boolean hasStableIds() {
return false;
}
/**
* 返回每个分组的view对象
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
//TextView tv;
if(convertView==null){
tv=new TextView(QuerryUsualNumber.this);
}else{
tv=(TextView) convertView;
}
tv.setTextSize(25);
tv.setTextColor(Color.RED);
tv.setText(" "+UsualNumberDao.getNameByGroupCountposition(db,groupPosition));
return tv;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if(convertView==null){
tv=new TextView(QuerryUsualNumber.this);
}else{
tv=(TextView) convertView;
}
tv.setTextSize(20);
tv.setTextColor(Color.BLACK);
tv.setText(" "+UsualNumberDao.getChildrenNameByPosition(db,groupPosition, childPosition));
return tv;
}
@Override
public boolean isChildSelectable(int groupPosition,
int childPosition) {
return true;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
db.close();
}
接口回调解耦的应用(用短信备份加进度条对话框来举例)
/**
* 短信备份
*
* @param view
*/
public void SMSBackUp(View view) {
/**
* 直接弹出一个进度条对话框
*/
final ProgressDialog pb = new ProgressDialog(this);
pb.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pb.setMessage("正在备份......");
pb.show();// show出来才能看得见
new Thread() {
public void run() {
boolean result = SMSTool.SmsBackup(
new SMSTool.SmsBackupCallBack() {
/**
* 接口里面的方法
*/
@Override
public void callBackprogress(int progress) {
pb.setProgress(progress);
}
/**
* 接口里面的方法
*/
@Override
public void callBackMax(int max) {
pb.setMax(max);
}
}, ToolActivity.this, "back.xml");
if (result) {
ToastUtils.show(ToolActivity.this, "备份成功");
} else {
ToastUtils.show(ToolActivity.this, "备份失败");
}
pb.dismiss();// 是否备份成功对话框都消失
};
}.start();
}
短信备份的逻辑:
/**
* 短信备份的工具类
*
* @author Administrator
*
*/
public class SMSTool {
/**
* 接口回调,定义一些抽象方法
*
* @author Administrator
*
*/
public interface SmsBackupCallBack {
/**
* 接口回调
*
* @param max 最大值
*
*/
public abstract void callBackMax(int max);
/**
* 接口回调
*
* @param progress
*/
public abstract void callBackprogress(int progress);
}
/**
* 短信备份的业务逻辑
*
* @param context 上下文
*
* @param filename 存进的文件名
*
* @return
*/
public static boolean SmsBackup(SmsBackupCallBack callBack,
Context context, String filename) {
try {
ContentResolver resolver = context.getContentResolver();
Uri uri = Uri.parse("content://sms/");
Cursor cursor = resolver.query(uri, new String[] { "address",
"date", "body", "type" }, null, null, null);
File file = new File(Environment.getExternalStorageDirectory(),
filename);
FileOutputStream fos = new FileOutputStream(file);
XmlSerializer serialer = Xml.newSerializer();
// 设置序列化参数
serialer.setOutput(fos, "utf-8");
serialer.startDocument("utf-8", true);
serialer.startTag(null, "info");
cursor.moveToNext();
int max = cursor.getCount();
int progress = 0;
//接口方法
callBack.callBackMax(max);
while (cursor.moveToNext()) {
// cursor.moveToNext();
serialer.startTag(null, "sms");
serialer.startTag(null, "address");
String address = cursor.getString(0);
serialer.text(address);
serialer.endTag(null, "address");
serialer.startTag(null, "date");
String date = cursor.getString(1);
serialer.text(date);
serialer.endTag(null, "date");
serialer.startTag(null, "body");
String body = cursor.getString(2);
serialer.text(body);
serialer.endTag(null, "body");
serialer.startTag(null, "type");
String type = cursor.getString(3);
serialer.text(type);
serialer.endTag(null, "type");
serialer.endTag(null, "sms");
progress++;
//接口的方法
callBack.callBackprogress(progress);
}
cursor.close();
serialer.startTag(null, "info");
serialer.endDocument();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
短信备份常见错误
- org.kxml2.io.KXmlSerializer.text(KXmlSerializer.java:536)
这是因为短信的内容中存在着搜狗输入法的一些表情,无法识别,只要把带有表情符号的短信删除掉就可以成功备份
java.io.FileNotFoundException:
/storage/emulated/0/backup.xml: 07-22 10:56:50.440: W/System.err(305): at
open failed: EACCES (Permission denied)没有权限齐全,短信的读写,sd卡、内存卡的读写权限等
listview的优化:四大原则
1、时间换空间
(牺牲时间换取空间,流的读写)
2、空间换时间
(把文件的路径存进数据库,以后查询就快很多,Android下的图库应用检索)
3、时间换时间
(开机启动速度的优化)
4、空间换空间
把内存换成硬盘,或者把硬盘换成内存
获取手机中所有应用程序的关键信息以List
返回List集合对象
public class AppManagerInfos {
@SuppressWarnings("unused")
public static List<AppInfo> getAppManagerInfos(Context context) {
List<AppInfo> appinfos = new ArrayList<AppInfo>();
PackageManager pm = context.getPackageManager();
//获取安装在手机上的应用程序
List<PackageInfo> infos = pm.getInstalledPackages(0);
for (PackageInfo appInfo : infos) {
AppInfo info = new AppInfo();
// 获得包名
String packagename = appInfo.packageName;
info.setPakageName(packagename);
// 获得应用名称
String appname = appInfo.applicationInfo.loadLabel(pm).toString();
info.setAppname(appname);
// 获得应用图标
Drawable icon = appInfo.applicationInfo.loadIcon(pm);
info.setIcon(icon);
// 获得应用app的绝对路径
String path = appInfo.applicationInfo.sourceDir;
info.setPath(path);
// 获得应用app的大小
File file = new File(path);
long size = file.length();
String sizedata = Formatter.formatFileSize(context, size);
info.setSize(size);
int flag = appInfo.applicationInfo.flags;
if ((flag & ApplicationInfo.FLAG_SYSTEM) == 0) {
// 用户应用
info.setUserapp(true);
} else {
// 系统应用
info.setUserapp(false);
}
if ((flag & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) {
// 存在手机内存
info.setInRom(true);
} else {
// 存在sd内存卡
info.setInRom(false);
}
appinfos.add(info);
}
return appinfos;
}
}
把不同集合数据展示到ListView中
public class AppManagerActivity extends Activity {
private TextView tv_shji_byte;
private TextView tv_sd_byte;
private ListView lv_listview;
private LinearLayout ll_loading;
private List<AppInfo> infos;
private List<AppInfo> userapp;
private List<AppInfo> systemapp;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
lv_listview.setAdapter(new MyAppManagerAdapter());
ll_loading.setVisibility(View.INVISIBLE);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_manager);
tv_shji_byte = (TextView) findViewById(R.id.tv_shji_byte);
tv_sd_byte = (TextView) findViewById(R.id.tv_sd_byte);
lv_listview = (ListView) findViewById(R.id.lv_listview);
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
userapp = new ArrayList<AppInfo>();
systemapp = new ArrayList<AppInfo>();
File datafile = Environment.getDataDirectory();
long datasize = datafile.getFreeSpace();
File sdfile = Environment.getExternalStorageDirectory();
long sdsize = sdfile.getFreeSpace();
tv_shji_byte.setText("手机可用内存"
+ Formatter.formatFileSize(this, datasize));
tv_sd_byte.setText("sd卡可用内存" + Formatter.formatFileSize(this, sdsize));
fillData();
}
/**
* 填充数据
*/
private void fillData() {
new Thread() {
public void run() {
infos = AppManagerInfos
.getAppManagerInfos(AppManagerActivity.this);
for (AppInfo info : infos) {
if (info.isUserapp()) {
// 用户程序
userapp.add(info);
} else {
systemapp.add(info);
// 系统程序
}
}
handler.sendEmptyMessage(0);
};
}.start();
}
private class MyAppManagerAdapter extends BaseAdapter {
@Override
public int getCount() {
return userapp.size() + systemapp.size() + 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
HoldView holder;
if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView;
holder = (HoldView) view.getTag();
} else {
holder = new HoldView();
view = View.inflate(AppManagerActivity.this,
R.layout.item_app_manager, null);
holder.app_name = (TextView) view.findViewById(R.id.app_name);
holder.app_location = (TextView) view
.findViewById(R.id.app_location);
holder.app_icon = (ImageView) view.findViewById(R.id.app_icom);
holder.app_size = (TextView) view.findViewById(R.id.app_size);
view.setTag(holder);
}
AppInfo info;
if (position == 0) {// 显示textView用户程序
TextView tv_user = new TextView(AppManagerActivity.this);
tv_user.setTextSize(15);
tv_user.setBackgroundColor(Color.GREEN);
tv_user.setTextColor(Color.BLACK);
tv_user.setText("用户程序" + userapp.size() + "个");
return tv_user;
} else if (position == userapp.size() + 1) {
TextView tv_system = new TextView(AppManagerActivity.this);
tv_system.setTextSize(15);
tv_system.setBackgroundColor(Color.GREEN);
tv_system.setTextColor(Color.BLACK);
tv_system.setText("系统程序" + systemapp.size() + "个");
return tv_system;
} else if (position < userapp.size() + 1) {
// 用户程序
info = userapp.get(position - 1);
} else {
// 系统程序
info = systemapp.get(position - 2 - userapp.size());
}
holder.app_name.setText(info.getAppname());
holder.app_icon.setImageDrawable(info.getIcon());
holder.app_size.setText(Formatter.formatFileSize(
AppManagerActivity.this, info.getSize()) + "M");
if (info.isInRom()) {
holder.app_location.setText("手机内存");
} else {
holder.app_location.setText("sd卡储存");
}
return view;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
private class HoldView {
TextView app_name;
TextView app_location;
ImageView app_icon;
TextView app_size;
}
}
设置listview属性可使其快速滚动
android:fastScrollEnabled="true"
在listview滚动时悬浮标识符
在帧布局中加入一个TextView
<TextView
android:id="@+id/tv_biaoshi"
android:layout_width="match_parent"
android:background="#00FF00"
android:textColor="#000000"
android:textSize="15sp"
android:text="用户程序"
android:layout_height="wrap_content"/>
不过设置属性时需要和之前区分系统用户时的属性相同,背景色、字体、大小,这样才可以重合
TextView tv_biaoshi=(TextView) findViewById(R.id.tv_biaoshi);
/**
* 给listview注册一个滚动监听器
*/
lv_listview.setOnScrollListener(new OnScrollListener() {
/**
* 当状态发生改变时执行此方法
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* 当listview滚动时执行此方法
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem>userapp.size()){
tv_biaoshi.setText("系统程序"+systemapp.size()+"个");
}else{
tv_biaoshi.setText("用户程序"+userapp.size()+"个");
}
}
});
悬浮窗体的创建使用(轻量级的对话框,内存开销比对话框小,灵活)漂浮的容器,在activity上方
//点击条目弹出悬浮窗体
TextView convertView=new TextView(AppManagerActivity.this);
convertView.setTextSize(15);
convertView.setTextColor(Color.RED);
convertView.setText(info.getPakageName());
popupwindow = new PopupWindow(convertView, 300, 100);
popupwindow.setBackgroundDrawable(new ColorDrawable(Color.GREEN));
//获取点击的条目view对象到窗体的宽高(左上对齐)存在location中x、y
int []location=new int[2];
view.getLocationInWindow(location);
popupwindow.showAtLocation(parent, Gravity.TOP+Gravity.LEFT, 80, location[1]);
不过一般都是自定义悬浮窗体
View convertView=View.inflate(getApplicationContext(), R.layout.item_app_popupwindow, null);
布局文件item.app.popupwindow.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tip_bg"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/my_user_exit" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="启动" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/delete" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="删除" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/wx_share_friends" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="分享" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/datasafety_item_icon_config" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="信息" />
</LinearLayout>
保证窗体中只有一个悬浮窗体,每次弹出前执行判断;listview滚动时消失也执行此方法
public void dismissPopupwindow() {
if(popupwindow!=null&& popupwindow.isShowing()){
popupwindow.dismiss();
popupwindow=null;
}
动画的播放原理
确定一个变化的函数:
根据这个函数 动态计算在某个时间应该显示什么画面
Canvas Bitmap 要求界面的窗体必须有背景,所以悬浮窗体必须设置背景才能启动动画
}
一键分享
//发送纯文本
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
//intent.setType("image/*");//图片
//intent.setType("video/*");//音频、视频
//intent.setType("*/*");//所有类型
intent.putExtra(Intent.EXTRA_TEXT, "请使用这款软件");
startActivity(intent);
一键卸载
动态注册广播接收者
innerReceiver=new InnerUninstallAppReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
registerReceiver(innerReceiver, filter);
/**
* 卸载软件程序后需要更新数据注册一个广播接收者
*/
private void uninstallapp() {
if(info.isUserapp()){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+info.getPakageName()));
startActivity(intent);
}else{
ToastUtils.show(this, "应用程序需要root权限才能卸载");
}
}
/**
* 内部类,广播接收者,监听软件卸载的事件
* @author Administrator
*
*/
private class InnerUninstallAppReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(info.isUserapp()){
userapp.remove(info);
}else{
systemapp.remove(info);
}
adapter.notifyDataSetChanged();
}
}
一键启动软件
/**
* 打开软件的功能
*/
public void openApp() {
PackageManager pm=getPackageManager();
Intent intent=pm.getLaunchIntentForPackage(info.getPakageName());
if(intent!=null){
startActivity(intent);
}else{
ToastUtils.show(this, "软件无法启动!");
}
}
查看应用程序信息(也可卸载应用程序:系统的设置卸载界面)
/**
* 查看应用程序全部信息
*/
private void showApp() {
//查找上层应用程序源码
/* <action android:name="android.settings.APPLICATION_DETAILS_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />*/
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+info.getPakageName()));
startActivity(intent);
}
获取手机所有正在运行的进程(返回的是List集合)
package coma.mobilephone.engine;
import java.util.ArrayList;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import coma.mobilephone.domain.ProcessInfo;
/**
* 获取所有正在运行的进程信息
* @author Administrator
*
*/
public class TaskInfoProvifer {
public static List<ProcessInfo> getRunningProcessInfo(Context context){
List<ProcessInfo> process=new ArrayList<ProcessInfo>();
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
PackageManager pm=context.getPackageManager();
//获取正在运行的进程集合
List<RunningAppProcessInfo>processrunninginfoinfo=am.getRunningAppProcesses();
//遍历集合
for(RunningAppProcessInfo runninginfo:processrunninginfoinfo){
ProcessInfo processinfo=new ProcessInfo();
//进程包名
String packageName=runninginfo.processName;
processinfo.setPackageName(packageName);
long menSize=am.getProcessMemoryInfo(new int[]{runninginfo.pid})[0].
getTotalPrivateDirty()*1024;
processinfo.setMenSize(menSize);
try {
PackageInfo packageinfo=pm.getPackageInfo(packageName, 0);
//进程图标
Drawable icon=packageinfo.applicationInfo.loadIcon(pm);
processinfo.setIcon(icon);
//进程名称
String processName=packageinfo.applicationInfo.loadLabel(pm).toString();
processinfo.setProcessName(processName);
//
if((packageinfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)!=0){
//系统进程
processinfo.setUserProcess(false);
}else{
//用户进程
processinfo.setUserProcess(true);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
process.add(processinfo);
}
return process;
}
}
javabean类的信息
package coma.mobilephone.domain;
import android.graphics.drawable.Drawable;
/**
* 进程包含的信息
* @author Administrator
*
*/
public class ProcessInfo {
private String packageName;
private String processName;
private Drawable icon;
private long menSize;
private boolean userProcess;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getProcessName() {
return processName;
}
public void setProcessName(String processName) {
this.processName = processName;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public long getMenSize() {
return menSize;
}
public void setMenSize(long menSize) {
this.menSize = menSize;
}
public boolean isUserProcess() {
return userProcess;
}
public void setUserProcess(boolean userProcess) {
this.userProcess = userProcess;
}
}
区分用户进程和系统进程(这是耗时操作)
List<ProcessInfo> processinfo=TaskInfoProvifer.getRunningProcessInfo(getApplicationContext());
userprocess=new ArrayList<ProcessInfo>();
systemprocess=new ArrayList<ProcessInfo>();
for(ProcessInfo process:processinfo){
if(process.isUserProcess()){
//用户程序
userprocess.add(process);
}else{
//系统程序
systemprocess.add(process);
}
}
//通知界面更新
handler.sendEmptyMessage(0);
打开一个服务,内部注册一个广播接收者,监听锁屏清理进程
public class AutoKillService extends Service {
private InnerScrrenOffReceiver receiver;
private Timer timer;
private TimerTask task;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
receiver=new InnerScrrenOffReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
/**
* 常用定时器,可设置为定时清理的功能
*/
timer=new Timer();
task=new TimerTask() {
@Override
public void run() {
//System.out.println("每1秒执行一次");
//清理的逻辑
}
};
timer.schedule(task,0, 1000);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
task.cancel();
unregisterReceiver(receiver);
receiver=null;
}
private class InnerScrrenOffReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//System.out.println("哈哈,屏幕锁屏了");
ActivityManager am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infos= am.getRunningAppProcesses();
for(RunningAppProcessInfo info:infos){
//杀死后台进程
am.killBackgroundProcesses(info.processName);
}
}
}
}
如何创建一个widget只需要3步
1、定义一个广播接收者继承AppwidgetProvider
2、在清单文件中配置广播接收者
<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>
3、建立一个xml文件夹存放资源example_appwidget_info.xml
<appwidget-provider xmlns:android="http://schemas.android/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000" //一天更新,最少半小时
android:previewImage="@drawable/preview"
android:initialLayout="@layout/example_appwidget">
</appwidget-provider>
4、自定义布局example_appwidget的内容
生命周期:
在手机桌面上创建第一个widget
11-05 00:46:24.817: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:46:24.817: I/System.out(1687): onenable (适合应用程序widget的初始化.)
11-05 00:46:24.817: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:46:24.817: I/System.out(1687): onupdate (只要有新的widget被创建都会调用onupdate方法)
11-05 00:46:27.347: I/System.out(1687): onreceive 接收到了系统的广播消息
如果界面上已经有一个widget被创建,再创建相同的widget
11-05 00:47:34.728: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:47:34.728: I/System.out(1687): onupdate
11-05 00:47:36.629: I/System.out(1687): onreceive 接收到了系统的广播消息
删除一个widget
11-05 00:48:48.019: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:48:48.019: I/System.out(1687): ondelete
最后一个widget被删除
11-05 00:49:25.710: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:49:25.710: I/System.out(1687): ondelete
11-05 00:49:25.710: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:49:25.710: I/System.out(1687): ondisabled (适合做应用程序扫尾的操作,)
总结: 不要记生命周期调用的先后顺序.
onenable 方法什么时候调用
ondisabled 方法什么时候调用
onupdate方法 在每次创建新的widget的时候都会调用 , 并且当时间片到的时候也会调用
创建widget模板
public class MyWidget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {//创建第一个桌面widget的时候调用
super.onReceive(context, intent);
}
//每次创建widget时都会调用
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Intent intent=new Intent(context,UpdateWidgetService.class);
context.startService(intent);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
//删除widget会调用
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
//对widget做初始化时调用
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
//结束widget是调用,做扫尾工作
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Intent intent=new Intent(context,UpdateWidgetService.class);
context.stopService(intent);
}
}
桌面启动服务定时更新widget
public class UpdateWidgetService extends Service {
private Timer timer;
private TimerTask task;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
timer=new Timer();
task=new TimerTask(){
@Override
public void run() {
System.out.println("更新widget里面的内容");
/*
* 进程间通讯
*/
ComponentName provider=new ComponentName(getApplicationContext(), MyWidget.class);
/*
* 告诉桌面布局文件去哪里找
*/
RemoteViews views=new RemoteViews(getPackageName(), R.layout.process_widget);
views.setTextViewText(R.id.process_count, "正在运行的软件"+ProcessInfoUtils.getRunningProcessCount(getApplicationContext())+"个");
String availstr=Formatter.formatFileSize(getApplicationContext(), ProcessInfoUtils.getAvialRam(getApplicationContext()));
views.setTextViewText(R.id.process_memory, "可用内存:"+availstr);
am.updateAppWidget(provider, views);
}};
timer.schedule(task, 0, 5000);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
task.cancel();
timer=null;
task=null;
}
}
逆向小助手的使用:反编译获取素材资源文件,everything可快速查找
反编译 拖拽到目录
多层显示的帧布局,功能多多
<FrameLayout
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp" >
<ListView
android:fastScrollEnabled="true"
android:id="@+id/lv_process_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<LinearLayout
android:id="@+id/ll_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载中..." />
</LinearLayout>
<TextView
android:id="@+id/tv_process_biaoshi"
android:layout_width="match_parent"
android:background="#00FF00"
android:textColor="#000000"
android:textSize="15sp"
android:text="用户进程"
android:layout_height="wrap_content"/>
</FrameLayout>
杀死所有运行的进程
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infos=am.getRunningAppProcesses();
for(RunningAppProcessInfo info:infos){
am.killBackgroundProcesses(info.processName);//参数为包名
}
抽屉控件
(重下往上拉),也可指定拉升的高度
<SlidingDrawer
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="@+id/my_content"
android:handle="@+id/my_handle" >
<ImageView
android:id="@id/my_handle" //相当于把柄,,id必须使用父类的
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:id="@id/my_content" //里面的内容,,id必须使用父类的
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是一个" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</SlidingDrawer>
也可重右往左拉
<SlidingDrawer
android:orientation="horizontal" //增加水平属性
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="@+id/my_content"
android:handle="@+id/my_handle" >
界面的切换(一个切面不同的布局切换)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:id="@+id/app_unlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_left_pressed"
android:gravity="center_vertical"
android:text="未加锁软件"
android:textSize="20sp" />
<TextView
android:id="@+id/app_locked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_right_default"
android:gravity="center_vertical"
android:text="已加锁软件"
android:textSize="20sp" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/ll_loading"
android:visibility="visible"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ProgressBar
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载数据..." />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_appunlock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_unlock_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="未加锁软件" />
<ListView
android:id="@+id/lv_unlock"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_applocked"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone" >
<TextView
android:id="@+id/tv_locked_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加锁软件" />
<ListView
android:id="@+id/lv_locked"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
</FrameLayout>
</LinearLayout>
主活动中点击切换
package coma.mobilephone.activity;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import coma.mobilephone.R;
import coma.mobilephone.db.dao.AppClockDao;
import coma.mobilephone.domain.AppInfo;
import coma.mobilephone.engine.AppManagerInfos;
/**
* 设置程序加锁的Activity
* @author Administrator
*
*/
public class AppLockedActivity extends Activity implements OnClickListener {
private TextView app_unlock;
private TextView app_locked;
/**
* 两种线性布局
*/
private LinearLayout ll_applocked;
private LinearLayout ll_appunlock;
/**
* 两种listview
*/
private ListView lv_locked;
private ListView lv_unlock;
/**
* 正在加载的进度条
*/
private LinearLayout ll_loading;
/**
* 所有程序的集合
*/
private List<AppInfo> infos;
/**
* 显示未加锁程序的个数
*/
private TextView tv_unlock_count;
/**
* 显示加锁程序的个数
*/
private TextView tv_locked_count;
/**
* 加锁的数据库
*/
private AppClockDao dao;
/**
* 加锁集合
*/
private List<AppInfo> lockedInfo;
/**
* 未加锁集合
*/
private List<AppInfo> unlockInfo;
/**
* 未加锁
*/
private MylockAdapter unlockadapter;
/**
* 加锁适配器
*/
private MylockAdapter lockedadapter;
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
// 加载未加锁的适配器
lv_unlock.setAdapter(unlockadapter);
// 加载加锁的适配器
lv_locked.setAdapter(lockedadapter);
ll_loading.setVisibility(View.INVISIBLE);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_applocked);
tv_unlock_count = (TextView) findViewById(R.id.tv_unlock_count);
tv_locked_count = (TextView) findViewById(R.id.tv_locked_count);
ll_loading=(LinearLayout) findViewById(R.id.ll_loading);
dao = new AppClockDao(this);
app_unlock = (TextView) findViewById(R.id.app_unlock);
app_locked = (TextView) findViewById(R.id.app_locked);
// 两种listview
lv_locked = (ListView) findViewById(R.id.lv_locked);
lv_unlock = (ListView) findViewById(R.id.lv_unlock);
// 两个不同点击事件
app_locked.setOnClickListener(this);
app_unlock.setOnClickListener(this);
// 两个线性布局
ll_applocked = (LinearLayout) findViewById(R.id.ll_applocked);
ll_appunlock = (LinearLayout) findViewById(R.id.ll_appunlock);
lockedInfo = new ArrayList<AppInfo>();
unlockInfo = new ArrayList<AppInfo>();
unlockadapter = new MylockAdapter(true);
lockedadapter = new MylockAdapter(false);
new Thread(){
public void run() {
// 获得全部软件程序
infos = AppManagerInfos.getAppManagerInfos(getApplicationContext());
/**
* 遍历集合,区分加锁和未加锁
*/
for (AppInfo info : infos) {
if (dao.find(info.getPakageName())) {
lockedInfo.add(info);
} else {
unlockInfo.add(info);
}
}
handler.sendEmptyMessage(0);
};
}.start();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.app_unlock:// 点击未加锁
ll_appunlock.setVisibility(View.VISIBLE);
ll_applocked.setVisibility(View.GONE);
app_unlock.setBackgroundResource(R.drawable.tab_left_pressed);
app_locked.setBackgroundResource(R.drawable.tab_left_default);
break;
case R.id.app_locked:// 点击已加锁
ll_appunlock.setVisibility(View.GONE);
ll_applocked.setVisibility(View.VISIBLE);
app_unlock.setBackgroundResource(R.drawable.tab_left_default);
app_locked.setBackgroundResource(R.drawable.tab_left_pressed);
break;
}
}
private class MylockAdapter extends BaseAdapter {
/**
* isunlock是否加锁的标识符 true 为未加锁 、 false 已加锁
*/
boolean isunlock;
public MylockAdapter(boolean isunlock) {
this.isunlock = isunlock;
}
@Override
public int getCount() {
int count = 0;
if (isunlock) {
count = unlockInfo.size();
tv_unlock_count.setText("未加锁软件:" + count);
} else {
count = lockedInfo.size();
tv_locked_count.setText("加锁软件:" + count);
}
return count;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
ViewHolder holder;
if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView;
holder = (ViewHolder) view.getTag();
} else {
view = View.inflate(getApplicationContext(),
R.layout.item_unlock_app, null);
holder = new ViewHolder();
holder.img_appicom = (ImageView) view
.findViewById(R.id.img_appicom);
holder.tv_appname = (TextView) view
.findViewById(R.id.tv_appname);
holder.img_locked = (ImageView) view
.findViewById(R.id.img_locked);
view.setTag(holder);
}
final AppInfo info;
if (isunlock) {
info = unlockInfo.get(position);
holder.img_locked
.setImageResource(R.drawable.list_button_lock_pressed);
} else {
info = lockedInfo.get(position);
holder.img_locked
.setImageResource(R.drawable.list_button_unlock_pressed);
}
holder.img_appicom.setImageDrawable(info.getIcon());
holder.tv_appname.setText(info.getAppname());
/**
* 点击加锁按钮移出条目,把数据加到数据库
*/
holder.img_locked.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isunlock) {
TranslateAnimation am = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0);
am.setDuration(500);
view.startAnimation(am);
am.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 未加锁
unlockInfo.remove(info);
lockedInfo.add(info);
dao.insert(info.getPakageName());
// 通知界面更新
// notifyDataSetChanged();
unlockadapter.notifyDataSetChanged();
lockedadapter.notifyDataSetChanged();
}
});
} else {
TranslateAnimation am = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, -1.0f,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0);
am.setDuration(500);
view.startAnimation(am);
am.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 已经加锁
lockedInfo.remove(info);
unlockInfo.add(info);
dao.delete(info.getPakageName());
// 通知界面更新
// notifyDataSetChanged();
unlockadapter.notifyDataSetChanged();
lockedadapter.notifyDataSetChanged();
}
});
}
}
});
return view;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
static class ViewHolder {
TextView tv_appname;
ImageView img_appicom;
ImageView img_locked;
}
}
在Service中开启一个活动Activity 在Activity往Service中发送信息采用自定义广播,只有服务才能接收:
活动中:
Intent intent=new Intent();
intent.setAction("coma.mobilesafe.watchdog");
intent.putExtra("packageNmae",packageName);
sendBroadcast(intent);
在服务中定义一个内部类广播接收者
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
temppackageName = intent.getStringExtra("packageName");
}
}
在onCreate方法中注册广播接收者:
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
registerReceiver(receiver, filter);
程序锁的主逻辑
package coma.mobilephone.service;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import coma.mobilephone.activity.EnterPasswordActivity;
import coma.mobilephone.db.dao.AppClockDao;
/**
* 看门狗服务,监视运行的软件
* @author Administrator
*
*/
public class WatchDogLockService extends Service {
private ActivityManager am;
private boolean flags;
private AppClockDao dao;
private InnerWatchDogReceiver receiver;
/**
* 临时不需要保护的包名
*/
private String temppackageName;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
registerReceiver(receiver, filter);
//获取活动管理器
am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
flags=true;
dao=new AppClockDao(this);
new Thread(){
public void run() {
while(flags){
//获取任务站里面的情况,对于任务栈里面的信息进行排序,最近使用的排在最前面
List<RunningTaskInfo> infos = am.getRunningTasks(100);
String packageName=infos.get(0).topActivity.getPackageName();
if(dao.find(packageName)){
//程序需要被保护,弹出一个输入密码的对话框
//再次判断是否需要保护
if(packageName.equals(temppackageName)){
//暂时不需要保护
}else{
//需要保护
Intent intent =new Intent(getApplicationContext(),EnterPasswordActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", packageName);
startActivity(intent);
}
}else{
//程序不需要被保护
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
flags=false;
unregisterReceiver(receiver);
receiver=null;
}
/**
* 定义内部类广播接收者,接收不需要保护的程序包名
* @author Administrator
*
*/
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
temppackageName = intent.getStringExtra("packageName");
}
}
}
程序的优化:考虑每个细节执行的时间,可以优化就优化
当有手机卫士在后台运行时,界面的跳转就不正常了,需要为打开密码保护的程序Activity设置一个模式:打开运用时会在一个新的任务栈中运行,这样就不会跳转回手机卫士了
android:launchMode="singleInstance"
在低版本时运行还没弹出密码界面就已经进入程序界面了,可以看到一些信息了,需要优化代码,执行效率更快
List<RunningTaskInfo> infos = am.getRunningTasks(100);
这句代码我们只需要获取第一个运用程序的包名
List<RunningTaskInfo> infos = am.getRunningTasks(1)定义为;
并定义为成员变量
优化:查询数据库所消耗的时间比内存中的多,把数据库查询的数据放在内存中,需要使用时到内存中查找即可
优化程序后发现新增加的要保护的程序保护不了,想到数据库查询时已经把数据存储在内存中固定了,所以要重新查询即更新数据,可以使用广播接收者、也可以使用内容观察者来观察数据库的变化,增加和删除一旦发现,重新查询数据存进内存中。
优化后的代码:电量的优化 屏幕锁屏后和锁屏的广播接收者
/**
* 看门狗服务,监视运行的软件
* @author Administrator
*
*/
public class WatchDogLockService extends Service {
private ActivityManager am;
private boolean flags;
private AppClockDao dao;
private InnerWatchDogReceiver receiver;
private List<RunningTaskInfo> infos ;
private String packageName;
/**
* 临时不需要保护的包名
*/
private String temppackageName;
/**
* 内容观察者
*/
private AppClockDaoObserver observer;
private Intent intent;
private List<String> packname;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(receiver, filter);
intent = new Intent(getApplicationContext(),EnterPasswordActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//获取活动管理器
am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
dao=new AppClockDao(this);
packname = dao.findAll();
//注册一个内容观察者
Uri uri=Uri.parse("content://coma.mobilephone.appclockdb");
observer=new AppClockDaoObserver(new Handler());
getContentResolver().registerContentObserver(uri, true, observer);
showWhatchDogStart();
}
/*
*对电量的优化,锁屏后停止监控
*
*/
public void showWhatchDogStart() {
if(flags==false){
return ;
}
flags=true;
new Thread(){
public void run() {
while(flags){
//获取任务站里面的情况,对于任务栈里面的信息进行排序,最近使用的排在最前面
infos= am.getRunningTasks(1);
packageName=infos.get(0).topActivity.getPackageName();
if(packname.contains(packageName)){
//程序需要被保护,弹出一个输入密码的对话框
//再次判断是否需要保护
if(packageName.equals(temppackageName)){
//暂时不需要保护
}else{
//需要保护
intent.putExtra("packageName", packageName);
startActivity(intent);
}
}else{
//程序不需要被保护
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
flags=false;
unregisterReceiver(receiver);
receiver=null;
}
/**
* 定义内部类广播接收者
* @author Administrator
*
*/
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if("coma.mobilephone.watchdog".equals(intent.getAction())){
temppackageName = intent.getStringExtra("packageName");
}else if(Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
//屏幕锁屏
temppackageName=null;
flags=false;
}else if(Intent.ACTION_SCREEN_ON.equals(intent.getAction())){
//屏幕解锁
showWhatchDogStart();
}
}
}
/**
* 定义内容观察者内部类
* @author Administrator
*
*/
private class AppClockDaoObserver extends ContentObserver{
public AppClockDaoObserver(Handler handler) {
super(handler);
}
//观察到数据库内容发生变化
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
System.out.println("内容观察者观察到数据库发生变化了");
packname = dao.findAll();
}
}
}
内容观察者
数据库中大声发个消息
Uri uri=Uri.parse("content://coma.mobilesafe.applockdb");
context.getContentResolver().notifyChange(Uri,null);
注册一个内容观察者:
Uri uri=Uri.parse("content://coma.mobilesafe.applockdb");
observer=new ApplockDBObserver(new Handler());
getContentResolver().registerContentObserver(uri,true,observer);
定义一个内容观察者内部类
/**
* 定义内容观察者内部类
* @author Administrator
*
*/
private class AppClockDaoObserver extends ContentObserver{
public AppClockDaoObserver(Handler handler) {
super(handler);
}
//观察到数据库内容发生变化
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
packname = dao.findAll();
}
}
目录
getFilesDir(); //data/data/<包名>/files 文件目录
getCacheDir(); //data/data/<包名>/cache 缓存目录
扫描手机获取所有程序员的缓存
public class CleanCacheActivity extends Activity {
protected static final int SCAN_STOP = 1;
public static final int SEND_SCAN = 2;
private ProgressBar pb;
private TextView tv_scan_cache;
private FrameLayout fl_scan_states;
private PackageManager pm;
private ListView lv_scan_listview;
private List<CacheHolder>cache;
private MyAdapter adapter;
/**
* 消息机制
*/
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case SCAN_STOP://扫描结束
Toast.makeText(getApplicationContext(), "扫描完毕", 0).show();
fl_scan_states.setVisibility(View.GONE);
if(cache.size()>0){
//设置适配器
adapter=new MyAdapter();
lv_scan_listview.setAdapter(adapter);
}else{
ToastUtils.show(CleanCacheActivity.this, "恭喜你,你的手机100分");
}
break;
case SEND_SCAN://正在扫描
String appname=(String) msg.obj;
tv_scan_cache.setText("正在清理:"+appname);
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clean_cache);
//初始化数据
pb=(ProgressBar) findViewById(R.id.pb);
tv_scan_cache=(TextView) findViewById(R.id.tv_scan_cache);
fl_scan_states=(FrameLayout) findViewById(R.id.fl_scan_states);
lv_scan_listview=(ListView) findViewById(R.id.lv_scan_listview);
pm=getPackageManager();
//扫描缓存
scanCache();
}
/**
* 扫描手机应用分别获取缓存信息
*/
private void scanCache() {
fl_scan_states.setVisibility(View.VISIBLE);
cache=new ArrayList<CacheHolder>();
//开子线程扫描程序缓存
new Thread(){
public void run() {
pb.setMax(100);
int progress=0;
//1、扫描应用程序全部的包名
List<PackageInfo>infos=pm.getInstalledPackages(0);
for(PackageInfo info:infos){
try {
//获取每个程序的包名
String packagename=info.packageName;
//利用反射获取指定的方法名
Method method=PackageManager.class.getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);
method.invoke(pm,packagename,new MyObserver());
} catch (Exception e) {
e.printStackTrace();
}
//进度条的设置
progress++;
pb.setProgress(progress);
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//2、通知界面更新
Message msg=Message.obtain();
msg.what=SCAN_STOP;
handler.sendMessage(msg);
};
}.start();
}
private class MyObserver extends IPackageStatsObserver.Stub{
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
try {
//把扫描到的包名发送回主界面更新
Message msg=Message.obtain();
msg.what=SEND_SCAN;
String appname=pm.getPackageInfo(pStats.packageName, 0).
applicationInfo.loadLabel(pm).toString();
msg.obj=appname;
handler.sendMessage(msg);
//主有有缓存大小的程序才需要存进集合中
if(pStats.cacheSize>0){
CacheHolder holder=new CacheHolder();
holder. cachesize=pStats.cacheSize;//缓存大小
holder. packName=pStats.packageName;//代码大小
holder. icon=pm.getPackageInfo(holder. packName, 0).applicationInfo.loadIcon(pm);
holder. appName=appname;
cache.add(holder);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class CacheHolder{
long cachesize;
String packName;
Drawable icon;
String appName;
}
/**
* listview的适配器
* @author Administrator
*
*/
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return cache.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder;
//服用历史缓存对象,优化listview
if(convertView!=null){
view=convertView;
holder=(ViewHolder) view.getTag();
}else{
holder=new ViewHolder();
view=View.inflate(getApplicationContext(), R.layout.item_cache_listview, null);
holder.icon=(ImageView) view.findViewById(R.id.img_icon);
holder.apname=(TextView) view.findViewById(R.id.tv_appname);
holder.cachesize=(TextView) view.findViewById(R.id.tv_cachesize);
holder.clearcache=(ImageView) view.findViewById(R.id.img_clear_button);
view.setTag(holder);
}
final CacheHolder cacheholder=cache.get(position);
holder.icon.setImageDrawable(cacheholder.icon);
holder.apname.setText(cacheholder.appName);
holder.cachesize.setText("缓存大小"+Formatter.formatFileSize(getApplicationContext(), cacheholder.cachesize));
holder.clearcache.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//打开应用程序信息
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+cacheholder.packName));
startActivity(intent);
}
});
if(cacheholder.cachesize==0){
cache.remove(cacheholder);
adapter.notifyDataSetChanged();
}
return view;
}
}
private class ViewHolder{
ImageView icon;
TextView apname;
TextView cachesize;
ImageView clearcache;
}
class ClearCacheObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
ToastUtils.show(CleanCacheActivity.this, "清除状态"+succeeded);
}
}
/**
* 清理全部的缓存空间
* @param view
*/
public void AllClearCache(View view){
Method[] methods=PackageManager.class.getMethods();
for(Method method:methods){
if("freeStorageAndNotify".equals(method.getName())){
try {
method.invoke(pm, Long.MAX_VALUE*1024,new ClearCacheObserver());
} catch (Exception e) {
e.printStackTrace();
}
scanCache();
return ;
}
}
}
}
自定义进度条
在drawable下建立一个progress_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android/apk/res/android">
//整个进度条背景
<item android:id="@android:id/background" android:drawable="@drawable/security_progress_bg">
</item>
<item android:id="@android:id/secondaryProgress" android:drawable="@drawable/security_progress">
//缓存到的背景
</item>
<item android:id="@android:id/progress" android:drawable="@drawable/security_progress">
//当前背景
</item>
</layer-list>
设置进度条的属性引用它
android:progressDrawable="@drawable/progress_horizontal"
这样就自定义好了进度条
具体的配置也可配置一下节点
share.xml下
在share节点下
android:shape="rectangle" //圆角矩形
<corners android:radius="5dp"/> //弧度
<gradient //渐变色
android:startColor="#ff0000"
android: endColor="#22ffff00"
/>
<padding //边距
android:left="5dp"
android:right="5dp"
android:top="5dp"
android:bottom="5dp"
/>
<solid android:width="1dp" android:color="#0000ff"/> //固定颜色不可和渐变色一起使用
<stroke android:width="1dp" android:color="#000000"
//实线 android:dashWidth="5dp" android:dashGap="2dip" //虚线
/>
清理缓存
//打开应用程序信息,手动清除
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+cacheholder.packName));
startActivity(intent);
全部清理缓存
/**
* 清理全部的缓存空间
* @param view
*/
public void AllClearCache(View view){
Method[] methods=PackageManager.class.getMethods();
for(Method method:methods){
if("freeStorageAndNotify".equals(method.getName())){
try {
method.invoke(pm, Long.MAX_VALUE*1024,new ClearCacheObserver());
} catch (Exception e) {
e.printStackTrace();
}
scanCache();
return ;
}
}
}
手机杀毒的方式
1、最原始的查杀方式
基于文件的的特征码(缺点:只能查杀已知的病毒,不能查杀未知的病毒)
2、基于程序的行为去查杀(主动防御)
替换系统的API(看雪论坛)
3、人工智能(学习模式+数据库)
字符串与字符串之间的距离
手机杀毒的实现
数据库的实现:
package coma.mobilephone.db.dao;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
/**
* 病毒数据库
* @author Administrator
*
*/
public class AntiVriusDao {
/**
* 在数据库中查找程序特征码是否存在,存在就是病毒软件,不存在就不是
* @param md5
* @return
*/
public static String isVriusdb(String md5){
SQLiteDatabase db=SQLiteDatabase.openDatabase("/data/data/coma.mobilephone/files/antivirus.db",
null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor=db.rawQuery("select desc from datable where md5=?", new String[]{md5});
String desc=null;
if(cursor.moveToNext()){
desc=cursor.getString(0);
}
db.close();
cursor.close();
return desc;
}
}
ui布局·:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_scanner_malware" />
<ImageView
android:id="@+id/img_rotate"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:src="@drawable/act_scanning_03" />
</FrameLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<TextView
android:id="@+id/tv_now_querry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:gravity="center_horizontal"
android:text="正在查杀..." />
<ProgressBar
android:id="@+id/verits_pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_now_querry"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="4dp"
android:progressDrawable="@drawable/progress_horizontal" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_add_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
</LinearLayout>
</LinearLayout>
代码的实现:
public class AntiVirusActivity extends Activity {
private ImageView img_rotate;
private LinearLayout ll_add_text;
private ProgressBar verits_pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_antivures);
img_rotate=(ImageView) findViewById(R.id.img_rotate);
ll_add_text=(LinearLayout) findViewById(R.id.ll_add_text);
verits_pb=(ProgressBar) findViewById(R.id.verits_pb);
/*
* 旋转动画
*/
RotateAnimation ra=new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(2000);
ra.setRepeatCount(Animation.INFINITE);
img_rotate.startAnimation(ra);
//扫描手机应用程序
scanVirus();
}
/**
* 扫描手机应用程序,查找手机病毒程序
*/
private void scanVirus() {
/**
* 遍历手机应用程序的信息,查询他的特征码在病毒数据库中是否存在
*/
PackageManager pm=getPackageManager();
List<PackageInfo> pakageinfos=pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
verits_pb.setMax(pakageinfos.size());
int progress=0;
for(PackageInfo info:pakageinfos){
try {
String apkpath=info.applicationInfo.sourceDir;
File file=new File(apkpath);
MessageDigest digest=MessageDigest.getInstance("md5");
FileInputStream fis=new FileInputStream(file);
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
digest.update(buffer, 0, len);
}
byte [] result=digest.digest();
StringBuffer sb=new StringBuffer();
for(byte b:result){
String str=Integer.toHexString(b&0xff);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
progress++;
verits_pb.setProgress(progress);
String md5=sb.toString();
/**
* 查找md5是否存在病毒数据库中
*/
final String desc=AntiVriusDao.isVriusdb(md5);
final String appname=(String) info.applicationInfo.loadLabel(pm);
runOnUiThread(new Runnable() {
@Override
public void run() {
TextView tv=new TextView(AntiVirusActivity.this);
if(desc!=null){
//发现病毒
tv.setTextColor(Color.RED);
tv.setText(appname+":发现病毒");
}else{
//扫描安全
tv.setTextColor(Color.GREEN);
tv.setText(appname+":扫描安全");
}
ll_add_text.addView(tv, 0);
}
});
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
隐藏应用程序的图标(不被用户发觉)
getPackageManager().setComponentEnabledSetting(getComponentName(),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
围绕中心轴旋转
/*
* 旋转动画
*/
RotateAnimation ra=new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(2000);
ra.setRepeatCount(Animation.INFINITE);
img_rotate.startAnimation(ra);
程序的签名
/**
* 获取应用程序的签名信息、使用MD5加密,要加上标志位PackageManager.GET_SIGNATURES ,系统默认不解析 TODO
*/
System.out.println("程序名"+info.applicationInfo.loadLabel(pm));
System.out.println("签名:"+MD5Utils.encode(info.signatures[0].toCharsString()));
获取程序的校验码
/**
* 获取程序的校验码
*/
//apk的路径
String apkpath=info.applicationInfo.sourceDir;
File file=new File(apkpath);
MessageDigest digest=MessageDigest.getInstance("md5");
//这里使用MD5 也可以使用 "sha-1" 获取
FileInputStream fis=new FileInputStream(file);
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
digest.update(buffer, 0, len);
}
byte [] result=digest.digest();
StringBuffer sb=new StringBuffer();
for(byte b:result){
String str=Integer.toHexString(b&0xff);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
创建应用程序的图标
/**
*创建快捷图标
*/
private void createShortCut() {
SharedPreferences sp=getSharedPreferences("config", MODE_PRIVATE);
boolean shortcut=sp.getBoolean("shortcut", false);
if(!shortcut){
//快捷方式的图片
//快捷方式的名称
//快捷方式干什么事情
//快捷图标其实是显示在桌面的,让桌面帮我们创建快捷图标
//给桌面发送消息
Intent intent=new Intent(); //发送广播的意图
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
//设置数据
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"破荒卫士" );
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
//快捷方式开启对应的意图
Intent shortcutIntent=new Intent();
shortcutIntent.setAction("coma.mobilesafe.home");
shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
//发送创建快捷方式的广播
sendBroadcast(intent);
Editor edit=sp.edit();
edit.putBoolean("shortcut", true);
editmit();
}
}
消息的通知
//消息的通知、先下兼容低版本
private void createNotification() {
//获取通知管理者
NotificationManager nm=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification=new Notification(R.drawable.ic_launcher, "破荒手机卫士正在保护你的手机!", System.currentTimeMillis());
//设置通知的标志
notification.flags=Notification.FLAG_NO_CLEAR;
//意图打开主界面
Intent intent=new Intent();
intent.setAction("coma.mobilesafe.home");
intent.addCategory(Intent.CATEGORY_DEFAULT);
PendingIntent contentIntent= PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(this, "破荒手机卫士", "正在保护你的手机", contentIntent);
nm.notify(0, notification);
}
对应用程序中的Log的控制,想打印什么类型的信息只要修改LOGLEVEL的值
package coma.mobilephone.Utils;
import android.util.Log;
/**
* 应用程序的Log的控制
* @author Administrator
*
*/
public class Logger {
private static final int VERBOSE=1;
private static final int DEBUG=2;
private static final int INFO=3;
private static final int WARN=4;
private static final int ERROR=5;
private static int LOGLEVEL=4;
public static void v(String tag,String msg){
if(VERBOSE>LOGLEVEL){
Log.v(tag, msg);
}
}
public static void d(String tag,String msg){
if(DEBUG>LOGLEVEL){
Log.d(tag, msg);
}
}
public static void i(String tag,String msg){
if(INFO>LOGLEVEL){
Log.i(tag, msg);
}
}
public static void w(String tag,String msg){
if(WARN>LOGLEVEL){
Log.w(tag, msg);
}
}
public static void e(String tag,String msg){
if(ERROR>LOGLEVEL){
Log.e(tag, msg);
}
}
}
应用程序的异常处理,捕获到异常信息存进指定的目录,可以上传至服务器中
package coma.mobilephone.log;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import android.app.Application;
import coma.mobilephone.Utils.Logger;
/**
* 代表的就是当前手机卫士的应用程序
* 《b》一定要注意在清单文件Application中配置,点Browser会自动匹配
* @author Administrator
*
*/
public class MobileSafeApplication extends Application {
//开天地,老母子方法
@Override
public void onCreate() {
super.onCreate();
Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
}
/**
* 捕获异常信息存进sd中,再上传至服务器中
* @author Administrator
*
*/
private class MyExceptionHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Logger.i("","发生了异常,被哥捕获到了。。。。。");
//并不能把异常消化掉,只是在应用程序挂掉之前,来一个留遗嘱的时间
try {
//获取手机适配的信息
Field[] fields=Builder.class.getDeclaredFields();
StringBuffer sb=new StringBuffer();
for(Field field:fields){
String value=field.get(null).toString();
String name=field.getName();
sb.append(value);
sb.append(":");
sb.append(name);
sb.append("\n");
}
//输出异常信息
FileOutputStream out=new FileOutputStream("/mnt/sdcard/error.log");
//阻塞性方法,直接写到内存中,内存输出流
StringWriter wr=new StringWriter();
PrintWriter err=new PrintWriter(wr);//打印输出流,异步输出流
ex.printStackTrace(err);
String errorlog=wr.toString();
out.write(errorlog.getBytes());
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
//ActivityManager 可以杀死别的进程,不能自杀,而专注于自杀是 android.os.Process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
}
应用程序的混淆加密(四大组件、自定义控件不可混淆)
操作方法:直接到目录把 sdk/tools/proguard/proguard-android这个文件拷贝到工程目录下就可以导出apk文件了
混淆工作原理:
全局替换 :类名、变量名、方法名
想把什么给保留出来,只要增加一下类似的语句
-keep class coma.mobilesafe.domain.AppInfo
介绍广告
1、内付费互联网公司
2、软件付费
3、免费软件+广告
cpm:千次有效展现
cpc:点击
cpa:完整有效点击
cpd:下载
广告主
代理公司(有米、百度联盟)
小程序员
常见系统的管理器:
- TelephonyManager:电话管理的服务
- SmsManager :信息的管理服务
- DevicesManager :设备的超级管理者
- ActivityManager:活动管理器:获取进程和服务的管理器,相当于window系统的任务管理器,获取的是动态信息
- PackageManager:获取各种包的信息(版本、应用程序图标、包信息等)相当于window系统的软件管理,获取的是静态的信息
- AppWidgetManager 桌面小控件
- NotificationManager 通知的管理
- LocationManager 位置提供者
- WindowManager窗口管理者
手机卫士涉及的知识点总结
Splash界面
splash: 溅,洒
- 展现产品的logo提升产品的知名度
- 初始化操作(创建数据库,读取配置文件)
- 连接服务器检查软件授权
- 连接服务器检查软件的更新
自动更新的前提
- 包名一致
- 签名一致
状态选择器
整体取消掉标题栏:在清单文件中加一修改主题
android:theme=”@android:style/Theme.Light.NoTitleBar”
PackageManager:获取各种包的信息(版本、应用程序图标、包信息等)
开源项目框架:
xUtils-2.6.8.jar 断点下载
使用:
HttpUtils httputils=new HttpUtils();
httputils.download(url,target,autoResume,callback);
//url:下载的路径
//targer:存放的路径sd
//autoResume:true是否断点续传
//callback:下载回传
new RequestCallBack<File>(){
重写onSuccess();
重写onFailure();
重写onload();//显示下载进度在textview中当前/总进度
}
开源项目断点下载xUtils耗时操作
HttpUtils http=new HttpUtils();
final File file=new File(Environment.getExternalStorageDirectory(),"xxx.apk");
http.download(data.downLoadUrl, file.getAbsolutePath(), true, new RequestCallBack<File>(){
//下载失败
@Override
public void onFailure(HttpException arg0, String arg1) {
}
//下载成功
@Override
public void onSuccess(ResponseInfo arg0) {
//下载成功,替换安装模板代码
ToastUtils.show(SplashActivity.this, "下载成功");
Intent intent=new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);
}});
下载替换安装只要调用系统的应用就行:(模板代码)
Itent intent=new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
startActivity(intent);
市面上常用界面-九宫格
状态选择器:
就是在res目录下建立一个drawable文件中定义一个xml文件,设置属性background时引用这个xml文件就行。
//背景颜色选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@android:color/darker_gray" android:state_pressed="true"> //按住时
<item android:drawable="@android:color/darker_gray" android:state_focused="true"> //聚焦时
<item android:drawable="@android:color/transparent" > //默认状态
</item>
</item>
</item>
</selector>
按住图标显示不一样的图片,新建一个tupian.xml文件,引用图标时R.drawable.tupian.xml
//图标状态选择
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@drawable/app_pressed" android:state_pressed="true"> //按住时
<item android:drawable="@drawable/app_focused"
android:state_focused="true"> //聚焦时
<item android:drawable="@drawable/app" > //默认状态
</item>
</item>
</item>
</selector>
走马灯效果按钮
Button可实现,当点击按钮的时候滚动起来
设置属性
android:focusableInTouchMode="true"
android:ellipsize="marquee"
android:text="显示的内容"
TextView也可以实现滚动走马灯:需要自定义TextView,实现里面的所有构造函数并重写isFocused()直接返回true
@Override
@ExportedProperty(category = "focus")
public boolean isFocused() {
return true;
}
并设置下面几个属性
<coma.mobilephone.ui.FocusedTextView
android:ellipsize="marquee"
android:focusableInTouchMode="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="希望我所认识的亲戚朋友远离病痛,远离饥饿,走上富康的道路,过上幸福的的生活!"
/>
这样textview跑马灯效果就可以跑起来了
设置一条线可以使用View
自定义组合控件:textView+checkBox 下面还有一条分割线
public class SettingCheckView extends LinearLayout {
public SettingCheckView(Context context, AttributeSet attrs) {
super(context, attrs);
initial(context);
String bigtitle=attrs.getAttributeValue("http://schemas.android/apk/res/coma.mobilephone", "bigtitle");
TextView tv_title=(TextView) findViewById(R.id.tv_ui_setting);
tv_title.setText(bigtitle);
}
public SettingCheckView(Context context) {
super(context);
initial(context);
}
private void initial(Context context) {
this.setOrientation(LinearLayout.VERTICAL);//
this.addView(View.inflate(context, R.layout.ui_setting_view, null));
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android/apk/res/android"
android:id="@+id/rl_set_update"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:background="@drawable/background" >
<TextView
android:id="@+id/tv_ui_setting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:text="开启自动更新"
android:textSize="20sp" />
<CheckBox
android:id="@+id/cb_set_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:clickable="false"
android:focusable="false" />
<View
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:layout_margin="2dp"
android:background="#88000000" />
</RelativeLayout>
使用时:
<coma.mobilephone.ui.SettingCheckView
android:layout_width="match_parent"
android:layout_height="wrap_content"
mobilephone:bigtitle="我是功能2"
/>
自定义属性:
先声明属性命名空间
xmlns:mobilephone="http://schemas.android/apk/res/coma.mobilephone"
在values定义一个attrs.xml文件,在里面声明功能
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SettingCheckView">
<attr name="bigtitle" format="string"/>
</declare-styleable>
//或者
<declare-styleable name="SettingCheckView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
做到这里就可以使用自定义组合控件了,功能可以设置文本内容,想增加其他的属性,在attrs中定义出来就可以使用了。
自定义对话框:
AlertDialog.Builder builder=new Builder(context);
View dialogview=View.inflate(context, R.layout.show_setup_dialog, null);
builder.setView(view);
builder.show();
//高低版本默认的背景色和字体颜色不一样、使高低版本保持一致的样式需
设置其背景色、文本字体色
AlertDialog.Builder builder=new Builder(MainActivity.this);
View dialogview=View.inflate(context, R.layout.show_setup_dialog, null);
AlertDialog dialog=builder.create();
dialog.setView(dialogview,0,0,0,0);//设置对话框上下左右的距离
dialog.show();
show_setup_dialog的xml布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#BFFF01"
android:text="设置密码"
android:textSize="30dp"
android:gravity="center"/>
<EditText
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="请输入密码"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:inputType="textPassword"/>
<EditText
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:hint="请确定密码"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:inputType="textPassword"/>
<LinearLayout
android:layout_width="300dp"
android:layout_height="wrap_content">
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:background="@drawable/btn_background"
android:text="取消"
android:layout_marginRight="5dp"
android:layout_height="wrap_content"/>
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:background="@drawable/btn_background"
android:text="确定"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
自定义背景选择器:btn_background.xml(要放在drawable文件下)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android/apk/res/android">
<item android:drawable="@android:color/holo_blue_light" android:state_pressed="true">
<item android:drawable="@android:color/holo_blue_light" android:state_focused="true">
<item android:drawable="@android:color/transparent" >
</item></item></item>
</selector>
当有很多个界面有相同的方法,相同的布局时,都要存储数据时,可定义一个父类让其他的类来继承它
动画的切换效果:
//一句代码,必须要放在Activity或者finish()的后面
overridePendingTransition(R.anim.trans_next_in, R.anim.trans_next_out);
在res目录下建立一个anim文件夹:创建两个xml:trans_next_in.xml和trans_next_out.xml如下
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android/apk/res/android"
android:fromXDelta="100%p"
android:toXDelta="0"
android:toYDelta="0"
android:fromYDelta="0"
android:duration="300">
</translate>
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android/apk/res/android"
android:fromXDelta="0"
android:toXDelta="-100%p"
android:toYDelta="0"
android:fromYDelta="0"
android:duration="300">
</translate>
手势识别器
1、先声明一个手势识别器
private GestureDetector mGestureDetector;
2、初始化一个手势识别器
//2、初始化手势识别器
mGestureDetector=new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
/**
* e1、手指触摸屏幕的一瞬间
* e2、手指离开屏幕的一瞬间
* velocityX、velocityY:水平方向和竖直方向的速度
*
*/
if((e1.getRawX()-e2.getRawX())>150){
showNext();
overridePendingTransition(R.anim.trans_next_in, R.anim.trans_next_out);
return true;
}
if((e2.getRawX()-e1.getRawX())>150){
showPre();
overridePendingTransition(R.anim.trans_pre_in, R.anim.trans_pre_out);
return true;
}
return super.onFling(e1, e2, velocityX, velocityY);
}
});
3、第三步、使用户识别手势器的动作
//第三步、使用手势识别器识别用户的动作
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
绑定手机卡、获取手机序列号,一个手机号对应一个序列号
//用到一个系统的服务
private TelephonyManager tm=(TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
//获取手机序列号
String sim=tm.getSimSerialNumber();
电话联系人
data/data/com.android.providers.contacts.database.contacts2.db
对应三张表:
查找联系人工具类:
public class ContactsInfoUtils {
public static List<ContactsInfo> getContactsInfo(Context context){
List<ContactsInfo> infocontacts=new ArrayList<ContactsInfo>();
//获取内容提供者的解析器
ContentResolver resolver=context.getContentResolver();
Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri=Uri.parse("content://com.android.contacts/data");
//游标
Cursor cursor=resolver.query(uri, new String[]{"contact_id"}, null, null, null);
//遍历游标集合
while(cursor.moveToNext()){
String id=cursor.getString(0);
System.out.println("id"+id);
ContactsInfo infos=new ContactsInfoUtils().new ContactsInfo();
Cursor datacursor=resolver.query(dataUri, new String[]{"data1"}, "raw_contact_id=?", null, null);
while(datacursor.moveToNext()){
String data1=datacursor.getString(0);
String mimetype=datacursor.getString(1);
if("vnd.android.cursor.item/name".equals(mimetype)){
//姓名
infos.name=data1;
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
//电话
infos.phone=data1;
}else if("vnd.android.cursor.item/email_v2".equals(mimetype)){
//电话
infos.email=data1;
}
}
infocontacts.add(infos);
}
return infocontacts;
}
public class ContactsInfo{
public String name;
public String email;
public String phone;
}
}
密码加密:md5 单向加密,不可逆原文–>密文
public static String encode(String text){
try {
MessageDigest digest=MessageDigest.getInstance("md5");
String password="234";
byte[] result=digest.digest(password.getBytes());
StringBuffer sb=new StringBuffer();
for(byte b:result){
String hex=Integer.toHexString(b&0xff)+2;//加盐更好更安全
if(hex.length()==1){
sb.append("0");
}
sb.append(hex);
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
}
播放报警音乐:便捷方式:src下新建目录raw可放音乐文件
MediaPlayer mediaplayer=MediaPlayer.create(context, R.raw.uri);
//循环播放
mediaplayer.setLooping(true);
//设置音量最大声
mediaplayer.setVolume(1.0f, 1.0f);
mediaplayer.start();
abortBroadcast();
超级管理员:
Android 2.2引入了支持企业应用程序提供Android设备管理API。设备管理API提供了设备管理功能在系统水平。这些api允许您创建安全性敏感的应用程序是有用的在企业环境中,IT专业人员需要丰富的控制员工的设备。例如,内置Android电子邮件应用程序利用了新的api来改善交流的支持。通过电子邮件应用程序,交流管理员可以执行密码策略——包括字母数字密码或数字针——在设备。管理员也可以远程擦除(即恢复工厂默认值)丢失或被盗的手机。用户可以同步他们的电子邮件和日历数据交换。
Email client
Security application that to remove wipe
Device management service and application
一键锁屏应用:能够一键锁屏,一键卸载
步骤:
1、先创建admim类继承DeviceAdminReceiver
2、配置清单文件(参考api文档)
<receiver
android:name="coma.yijian.Admin"
android:description="@string/sample_device_admin_description"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<!-- 元数据,提供设备的超级管理员的配置信息 -->
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
还要新建一个 res目录下xml文件夹并新建device_admin_sample.xml:
声明中使用的安全策略的元数据提供了特定于设备管理员的附加信息,可通过DeviceAdminInfo类进行解析查看,以下为device_admin_sample.xml:的内容
<device-admin xmlns:android="http://schemas.android/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
</uses-policies>
</device-admin>
3、主活动中书写代码
点击按钮一键锁屏:
public void lockscreen(View view){
DevicePolicyManager dpm=(DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who=new ComponentName(this, Admin.class);
if(dpm.isAdminActive(who)){
//重置密码
//dpm.resetPassword("123", 0);
//清除sd卡数据
//dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
dpm.lockNow();
finish();
}else{
Toast.makeText(this, "请先激活应用程序", 0).show();
}
}
使用时:先来到系统设置界面,找到安全、进入设备管理器、找到一键锁屏,点击激活一键锁屏,此时可以使用了。
先激活应用程序
给用户一个很好的体验:来个按钮“先激活应用程序”
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
ComponentName who=new ComponentName(this, Admin.class);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, who);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"请大家赶紧去激活程序吧,首次激活有大礼包!");
startActivity(intent);
一键卸载
再来个卸载按钮:
public void deleteLockScreen(View view){
DevicePolicyManager dpm=(DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName who=new ComponentName(this, Admin.class);
dpm.removeActiveAdmin(who);
Intent intent=new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+getPackageName()));
startActivity(intent);
}
获取位置的经纬度(真实标准坐标)在中国要转换成火星坐标才能真正确定位置
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取位置内容提供者
LocationManager lm=(LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria=new Criteria();
//指定高精度
criteria.setAccuracy(Criteria.ACCURACY_FINE);
//指定高耗电量
criteria.setPowerRequirement(Criteria.POWER_HIGH);
//获取最好的内容提供者
String provider =lm.getBestProvider(criteria, true);
lm.requestLocationUpdates(provider, 0, 0, new LocationListener() {
//状态改变时调用
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
//可用时调用
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onLocationChanged(Location location) {
location.getLatitude();//纬度
location.getLongitude();//经度
System.out.println("纬度:"+location.getLatitude()+"------经度:"+location.getLongitude());
TextView text=new TextView(getApplication());
text.setTextColor(Color.RED);
text.setText("纬度:"+location.getLatitude()+"------经度:"+location.getLongitude());
}
} );
}
标准坐标—->>中国的火星坐标
使用算法:导入modifyOffset.java和axisoffset.dat
直接到代码中使用:
ModifyOffset no =ModifyOffset.getInstance(context.getClassLoader().getResourceAsStream("axisoffset.dat"));
//真实坐标X经度 Y为纬度
//不过查找时外国网站经度放在围纬度后面:纬度,经度
PointDouble pt =new PointDouble(x,y);
PointDouble marpoint=mo.s2c(pt);
System.out.println(marpoint.toString());
//输出的是x=。。。。,y=。。。。。经纬度
listView的简单优化
容易内存溢出
1、尽量复用convertview历史的缓存,减少创建新的view对象
2、尽量的减少子孩子的id的查询次数,定义一个viewHolder
View view;
viewHolder holder;
if(convertView!=null){
//复用历史的view对象
view=convertView;
holder=(viewHolder) view.getTag();
}else{
//创建新的孩子时加上标签
holder=new viewHolder();
view=View.inflate(getApplicationContext(), R.layout.item_callsmssafe, null);
holder.black_phone=(TextView) view.findViewById(R.id.tv_black_phone);
holder.black_mode=(TextView) view.findViewById(R.id.tv_black_mode);
view.setTag(holder);
}
//内部类
class viewHolder{
public TextView black_phone;
public TextView black_mode;
public ImageView black_delete;
}
listView显示数据库中的数据时,当listview发生变化时应更新listview数据
//通知listview更新数据
adapter.notifyDataSetChanged();
在清单文件中配置广播接收者的特点是:不管应用程序进程是否存在都能接受到对应广播
短信拦截:开启服务并在里面注册一个广播接收者
开启服务:
Intent intent=new Intent(SettingActivity.this,CallSmsSafeService.class);
startService(intent);
//服务里面代码动态注册一个广播接收者
public class CallSmsSafeService extends Service {
private BlackNumberDao dao;
private InnerReceiver receiver;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
dao=new BlackNumberDao(this);
//动态注册
receiver=new InnerReceiver();
IntentFilter filter=new IntentFilter();
//设置关心短信到来的动作
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
filter.setPriority(Integer.MAX_VALUE);
//代码注册广播接收者
registerReceiver(receiver, filter);
System.out.println("黑名单短信拦截开启了!!!!!");
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
receiver=null;
}
//内部类广播接收者
private class InnerReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//拦截短信
Object[] objs=(Object[]) intent.getExtras().get("pdus");
for(Object obj:objs){
SmsMessage smsMessage=SmsMessage.createFromPdu((byte[])obj);
String address=smsMessage.getOriginatingAddress();
String result=dao.find(address);
if("2".equals(result)||"3".equals(result)){
System.out.println("黑名单短信拦截模式。。。");
abortBroadcast();
}
//智能拦截
String body=smsMessage.getMessageBody();
if(body.contains("天使")){//分词算法
SmsManager.getDefault().sendTextMessage("13531829360", null, "帮你拦截了天使客一条消息", null, null);
abortBroadcast();
}
}
}
}
}
服务断电就会自动停止,用sp存储不会保存状态,读取系统的的运行信息,调用系统的活动和服务管理者ActivityManager可以判断服务是否正在后台运行
/**
* 判断系统的服务是否在后台运行
* context:上下文
* StringName: 服务的全路经名
*/
public static boolean isServiceRunning(Context context,String StringName){
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infos=am.getRunningServices(100);
for(RunningServiceInfo info:infos){
String className=info.service.getClassName();
if(StringName.equals(className)){
return true;
}
}
return false;
}
分词算法:
开源算法:
luncence
利用反射原理挂断电话
/**
* 挂断电话的方法,利用反射
*/
public void endCall() {
try {
Class clazz=CallSmsSafeService.class.getClassLoader().loadClass("android.os.ServiceManager");
Method method=clazz.getDeclaredMethod("getService", String.class);
IBinder ibinder=(IBinder) method.invoke(null, TELEPHONY_SERVICE);
ITelephony iTelephony=ITelephony.Stub.asInterface(ibinder);
iTelephony.endCall();
} catch (Exception e) {
e.printStackTrace();
}
}
删除通话的记录(内容观察者)
//监视呼叫记录的的数据库,看什么时候生成了,
//就把它删除
Uri uri=Uri.parse("content://call_log/calls");
getContentResolver().registerContentObserver(uri, true,new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
deleteCallLog(incomingNumber);
}
});
/**
* 删除拨号记录
* @param incomingNumber
*/
public void deleteCallLog(String incomingNumber) {
ContentResolver resolver=getContentResolver();
Uri uri=Uri.parse("content://call_log/calls");
resolver.delete(uri, "number=?", new String[]{incomingNumber});
}
打断点、看内存、查源码
电话的拦截功能:
/**
* 定义电话管理的服务
*/
private TelephonyManager tm;
private MyPhoneStateListener listener;
/**
* 实例化电话管理的服务
*/
tm=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//注册电话的监听器
listener=new MyPhoneStateListener();
//监听电话的状态的改变
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
监听器的注册
class MyPhoneStateListener extends PhoneStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state){
case TelephonyManager.CALL_STATE_IDLE://空闲状态
break;
case TelephonyManager.CALL_STATE_RINGING://响铃状态
String mode=dao.find(incomingNumber);
if(mode.equals("1")||mode.equals("3")){
System.out.println("挂断电话");
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK://接听状态
break;
}
}
}
ActivityManager:获取进程和服务的管理
ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE) ;
//获得系统运行的进程
List<ActivityManager.RunningAppProcessInfo> appList1 = mActivityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo running : appList1) {
System.out.println(running.processName);
}
System.out.println("================");
//获得当前正在运行的service
List<ActivityManager.RunningServiceInfo> appList2 = mActivityManager
.getRunningServices(100);
for (ActivityManager.RunningServiceInfo running : appList2) {
System.out.println(running.service.getClassName());
}
System.out.println("================");
//获得当前正在运行的activity
List<ActivityManager.RunningTaskInfo> appList3 = mActivityManager
.getRunningTasks(1000);
for (ActivityManager.RunningTaskInfo running : appList3) {
System.out.println(running.baseActivity.getClassName());
}
System.out.println("================");
//获得最近运行的应用
List<ActivityManager.RecentTaskInfo> appList4 = mActivityManager
.getRecentTasks(100, 1);
for (ActivityManager.RecentTaskInfo running : appList4) {
System.out.println(running.origActivity.getClassName());
}
判断某个进程或服务是否在后台进行的工具类:
package coma.mobilephone.Utils;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
public class ServicerUtils {
/**
* 判断系统的服务是否在后台运行
*/
public static boolean isServiceRunning(Context context,String StringName){
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> infos=am.getRunningServices(1000);
for(ActivityManager.RunningServiceInfo info:infos){
String className=info.service.getClassName();
System.out.println(className);
if(StringName.equals(className)){
System.out.println(className);
return true;
}
}
return false;
}
}
数据库的增删改查
package coma.mobilephone.db.dao;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import coma.mobilephone.db.BlackNumberOpenHeloper;
import coma.mobilephone.domain.BlackNumberInfo;
public class BlackNumberDao {
private BlackNumberOpenHeloper openhelper;
/**
* 数据库的构造函数
* @param context
*/
public BlackNumberDao(Context context) {
super();
openhelper=new BlackNumberOpenHeloper(context);
}
/**
* 往数据库中增加号码
* @param phone 增加的电话号码
* @param mode 模式
* @return
*/
public boolean add(String phone,String mode){
SQLiteDatabase db=openhelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("phone", phone);
values.put("mode", mode);
long id=db.insert("blacknumberinfo", null, values);
db.close();
if(id!=-1){
return true;
}else{
return false;
}
}
/**
* 修改黑名单的拦截模式
* @param phone 要修改的黑名单号码
* @param newmode 新的拦截模式
* @return 修改是否成功
*/
public boolean update(String phone,String newmode){
SQLiteDatabase db=openhelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("mode", newmode);
int rowcount=db.update("blacknumberinfo", values, "phone=?", new String[]{phone});
db.close();
if(rowcount==0){
return false;
}else{
return true;
}
}
/**
* 查找黑名单号码的拦截模式
* @param phone 要查找的电话号码
* @return 返回拦截的模式
*/
public String find(String phone){
String mode=null;
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.query("blacknumberinfo", null, "phone=?", new String[]{phone},null, null, null);
if(cursor.moveToNext()){
mode=cursor.getString(cursor.getColumnIndex("mode"));;
}
cursor.close();
db.close();
return mode;
}
/**
* 删除黑名单号码
* @param phone 要删除的号码
* @return 是否删除成功
*/
public boolean delete(String phone){
SQLiteDatabase db=openhelper.getWritableDatabase();
int rowcount=db.delete("blacknumberinfo", "phone=?", new String[]{phone});
db.close();
if(rowcount==0){
return false;
}{
return true;
}
}
/**
* 返回全部的黑名单信息
* @return
*/
public List<BlackNumberInfo> findAll(){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.query("blacknumberinfo", null, null, null, null, null, "_id desc");
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
分批加载
/**
* 分批加载返回的黑名单信息
* @return
*/
public List<BlackNumberInfo> findPart(int startIndex,int maxCount){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?", new String[]{
String.valueOf(maxCount),String.valueOf(startIndex)
});
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
分页加载解决内存溢出
/**
* 分页加载返回的黑名单信息
* @return
*/
public List<BlackNumberInfo> findPagper(int pagper){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select _id,phone,mode from blacknumberinfo order by _id desc limit ? offset ?", new String[]{
String.valueOf(10),String.valueOf(pagper*10)
});
List<BlackNumberInfo> infos=new ArrayList<BlackNumberInfo>();
while(cursor.moveToNext()){
String phone=cursor.getString(cursor.getColumnIndex("phone"));
String mode=cursor.getString(cursor.getColumnIndex("mode"));
BlackNumberInfo info=new BlackNumberInfo();
info.setPhone(phone);
info.setMode(mode);
infos.add(info);
}
cursor.close();
db.close();
return infos;
}
/**
* 获取全部总条目
* @return
*/
public int getTotalCount(){
SQLiteDatabase db=openhelper.getReadableDatabase();
Cursor cursor=db.rawQuery("select count(*) from blacknumberinfo ",null);
cursor.moveToNext();
int total=cursor.getInt(0);
cursor.close();
db.close();
return total;
}
}
复制资产目录下的文件到android系统下
/**
* 拷贝资产目录下的数据库到Android系统下
*/
private void copyDB(final String name) {
/*
* 数据库多时可能耗时
*/
new Thread(){
public void run() {
File file=new File(getFilesDir(),name);
if(file.exists()&&file.length()>0){
System.out.println("数据库已经加载过,无需在加载!");
}else{
try {
InputStream is=getAssets().open(name);
FileOutputStream fos=new FileOutputStream(file);
byte[] buffer=new byte[1024];
int len=-1;
while((len=is.read(buffer))!=-1){
fos.write(buffer, 0, len);
}
is.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
}.start();
}
自定义吐司
/**
* 自定义吐司
* @param address
*/
public void showToast(String address) {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
View view = View.inflate(getApplicationContext(), R.layout.item_toast, null);
//设置背景,字体等自定义属性
int which=getSharedPreferences("config", 0).getInt("which", 0);
int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
view.setBackgroundResource(bgs[which]);
TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
tv_address.setText(address);
//设置参数params
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
wm.addView(view, params);
}
及时退出吐司的显示用:wm.removeView(view);
控件的拖拽效果
ImageView imgview= (ImageView) findViewById(R.id.imageview);
imgview.setOnTouchListener(new OnTouchListener() {
int startx;
int starty;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN://手指第一次触摸控件时调用
//获取控件在屏幕上的坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE://手指在控件上移动的事件
//手指移动后的偏移量
int newx=(int) event.getRawX();
int newy=(int) event.getRawY();
int dx=newx-startx;
int dy=newy-starty;
//移动后的控件新坐标
imgview.layout(imgview.getLeft()+dx, imgview.getTop()+dy,
imgview.getRight()+dx, imgview.getBottom()+dy);
//移动后重新初始化控件坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
System.out.println("移动了控件"+startx+"---"+starty);
break;
case MotionEvent.ACTION_UP://手指离开控件的一瞬间
break;
}
return true;
}
});
简单双击效果实现
btn=(Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(firsttime>0){
secondtime=System.currentTimeMillis();
if((secondtime-firsttime)<500){
Toast.makeText(getApplicationContext(), "双击了", 0).show();
firsttime=0;
}else{
firsttime=0;
}
return ;
}
firsttime=System.currentTimeMillis();
new Thread(){
public void run() {
try {
Thread.sleep(500);
firsttime=0;
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
}
});
多次点击事件实现
//定义了多长的数组就是多次点击,3就是连续3击
private long[] mHits=new long[3];
/**
*四个参数:源数组,从第几个开始拷贝,目标数组,从第几个开始拷贝,拷贝的长度
*
*/
System.arraycopy(mHits, 1, mHits, 0, mHits.length-1);
mHits[mHits.length-1] = SystemClock.uptimeMillis();
if (mHits[0] >= (SystemClock.uptimeMillis()-500)) {
Toast.makeText(getApplicationContext(), "多次击了", 0).show();
}
自定义吐司加上拖拽的效果图显示
/**
* 自定义吐司
* @param address
*/
public void showToast(String address) {
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
view = View.inflate(getApplicationContext(), R.layout.item_toast, null);
view.setOnTouchListener(new OnTouchListener() {
int startx ;
int starty ;
@SuppressWarnings("deprecation")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN://手指触摸
//获取自定义吐司坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
case MotionEvent.ACTION_UP://手指离开
//存储控件的位置坐标
SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE);
Editor edit=sp.edit();
edit.putInt("lastx", params.x);
edit.putInt("lasty", params.y);
editmit();
break;
case MotionEvent.ACTION_MOVE://手指移动
//获取偏移量
int newx=(int) event.getRawX();
int newy=(int) event.getRawY();
int dx=newx-startx;
int dy=newy-starty;
params.x +=dx;
params.y +=dy;
//判断view控件是否移出屏幕范围
if(params.x>(wm.getDefaultDisplay().getWidth()-view.getWidth())){
params.x=wm.getDefaultDisplay().getWidth()-view.getWidth();
}
if(params.y>(wm.getDefaultDisplay().getHeight()-view.getHeight())){
params.x=wm.getDefaultDisplay().getHeight()-view.getHeight();
}
wm.updateViewLayout(view, params);
//重新初始化控件坐标
startx=(int) event.getRawX();
starty=(int) event.getRawY();
break;
}
return true;
}
});
//设置背景颜色
int which=getSharedPreferences("config", 0).getInt("which", 0);
int bgs[]={R.drawable.btn_gray_normal,R.drawable.btn_green_normal,R.drawable.btn_gray_pressed,R.drawable.call_show_bg,R.drawable.btn_disabled};
view.setBackgroundResource(bgs[which]);
TextView tv_address=(TextView) view.findViewById(R.id.tv_address);
tv_address.setText(address);
params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
//左上对齐
params.gravity=Gravity.LEFT+Gravity.TOP;
SharedPreferences sp=getSharedPreferences("config", MODE_PRIVATE);
params.x=sp.getInt("lastx", 0);
params.y=sp.getInt("lasty", 0);
params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
wm.addView(view, params);
}
可扩展的ListView(ExpandableListView控件)
public class QuerryUsualNumber extends Activity {
private ExpandableListView exl_listview;
private SQLiteDatabase db;
private TextView tv;
private MyExpandableAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db=SQLiteDatabase.openDatabase("/data/data/coma.mobilephone/files/commonnum.db", null, SQLiteDatabase.OPEN_READONLY);
setContentView(R.layout.activity_querryusualnumber);
exl_listview = (ExpandableListView) findViewById(R.id.exl_listview);
adapter = new MyExpandableAdapter();
//设置适配器
exl_listview.setAdapter(adapter);
//孩子被点击的监听器
exl_listview.setOnChildClickListener(new OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
//点击条目获得数据库返回的数据,并分割提取号码进行拨号
String data=UsualNumberDao.getChildrenNameByPosition(db, groupPosition, childPosition);
String datas[]=data.split("\n");
String name=datas[0];
String number=datas[1];
Toast.makeText(getApplicationContext(), groupPosition+"--"+childPosition+":"+name+":"+number, 0).show();
//点击之后进行拨打指定号码的电话
Intent intent =new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+number));
startActivity(intent);
return true;
}
});
}
适配器
private class MyExpandableAdapter extends BaseExpandableListAdapter{
/**
* 获取分组的个数
*/
@Override
public int getGroupCount() {
return UsualNumberDao.getGroupCount(db);
}
/**
* 获取每个分组的孩子的个数
*/
@Override
public int getChildrenCount(int groupPosition) {
return UsualNumberDao.getChildGroupCount(db,groupPosition);
}
@Override
public Object getGroup(int groupPosition) {
return null;
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return null;
}
@Override
public long getGroupId(int groupPosition) {
return 0;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return 0;
}
@Override
public boolean hasStableIds() {
return false;
}
/**
* 返回每个分组的view对象
*/
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
//TextView tv;
if(convertView==null){
tv=new TextView(QuerryUsualNumber.this);
}else{
tv=(TextView) convertView;
}
tv.setTextSize(25);
tv.setTextColor(Color.RED);
tv.setText(" "+UsualNumberDao.getNameByGroupCountposition(db,groupPosition));
return tv;
}
@Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
if(convertView==null){
tv=new TextView(QuerryUsualNumber.this);
}else{
tv=(TextView) convertView;
}
tv.setTextSize(20);
tv.setTextColor(Color.BLACK);
tv.setText(" "+UsualNumberDao.getChildrenNameByPosition(db,groupPosition, childPosition));
return tv;
}
@Override
public boolean isChildSelectable(int groupPosition,
int childPosition) {
return true;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
db.close();
}
接口回调解耦的应用(用短信备份加进度条对话框来举例)
/**
* 短信备份
*
* @param view
*/
public void SMSBackUp(View view) {
/**
* 直接弹出一个进度条对话框
*/
final ProgressDialog pb = new ProgressDialog(this);
pb.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pb.setMessage("正在备份......");
pb.show();// show出来才能看得见
new Thread() {
public void run() {
boolean result = SMSTool.SmsBackup(
new SMSTool.SmsBackupCallBack() {
/**
* 接口里面的方法
*/
@Override
public void callBackprogress(int progress) {
pb.setProgress(progress);
}
/**
* 接口里面的方法
*/
@Override
public void callBackMax(int max) {
pb.setMax(max);
}
}, ToolActivity.this, "back.xml");
if (result) {
ToastUtils.show(ToolActivity.this, "备份成功");
} else {
ToastUtils.show(ToolActivity.this, "备份失败");
}
pb.dismiss();// 是否备份成功对话框都消失
};
}.start();
}
短信备份的逻辑:
/**
* 短信备份的工具类
*
* @author Administrator
*
*/
public class SMSTool {
/**
* 接口回调,定义一些抽象方法
*
* @author Administrator
*
*/
public interface SmsBackupCallBack {
/**
* 接口回调
*
* @param max 最大值
*
*/
public abstract void callBackMax(int max);
/**
* 接口回调
*
* @param progress
*/
public abstract void callBackprogress(int progress);
}
/**
* 短信备份的业务逻辑
*
* @param context 上下文
*
* @param filename 存进的文件名
*
* @return
*/
public static boolean SmsBackup(SmsBackupCallBack callBack,
Context context, String filename) {
try {
ContentResolver resolver = context.getContentResolver();
Uri uri = Uri.parse("content://sms/");
Cursor cursor = resolver.query(uri, new String[] { "address",
"date", "body", "type" }, null, null, null);
File file = new File(Environment.getExternalStorageDirectory(),
filename);
FileOutputStream fos = new FileOutputStream(file);
XmlSerializer serialer = Xml.newSerializer();
// 设置序列化参数
serialer.setOutput(fos, "utf-8");
serialer.startDocument("utf-8", true);
serialer.startTag(null, "info");
cursor.moveToNext();
int max = cursor.getCount();
int progress = 0;
//接口方法
callBack.callBackMax(max);
while (cursor.moveToNext()) {
// cursor.moveToNext();
serialer.startTag(null, "sms");
serialer.startTag(null, "address");
String address = cursor.getString(0);
serialer.text(address);
serialer.endTag(null, "address");
serialer.startTag(null, "date");
String date = cursor.getString(1);
serialer.text(date);
serialer.endTag(null, "date");
serialer.startTag(null, "body");
String body = cursor.getString(2);
serialer.text(body);
serialer.endTag(null, "body");
serialer.startTag(null, "type");
String type = cursor.getString(3);
serialer.text(type);
serialer.endTag(null, "type");
serialer.endTag(null, "sms");
progress++;
//接口的方法
callBack.callBackprogress(progress);
}
cursor.close();
serialer.startTag(null, "info");
serialer.endDocument();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
短信备份常见错误
- org.kxml2.io.KXmlSerializer.text(KXmlSerializer.java:536)
这是因为短信的内容中存在着搜狗输入法的一些表情,无法识别,只要把带有表情符号的短信删除掉就可以成功备份
java.io.FileNotFoundException:
/storage/emulated/0/backup.xml: 07-22 10:56:50.440: W/System.err(305): at
open failed: EACCES (Permission denied)没有权限齐全,短信的读写,sd卡、内存卡的读写权限等
listview的优化:四大原则
1、时间换空间
(牺牲时间换取空间,流的读写)
2、空间换时间
(把文件的路径存进数据库,以后查询就快很多,Android下的图库应用检索)
3、时间换时间
(开机启动速度的优化)
4、空间换空间
把内存换成硬盘,或者把硬盘换成内存
获取手机中所有应用程序的关键信息以List
返回List集合对象
public class AppManagerInfos {
@SuppressWarnings("unused")
public static List<AppInfo> getAppManagerInfos(Context context) {
List<AppInfo> appinfos = new ArrayList<AppInfo>();
PackageManager pm = context.getPackageManager();
//获取安装在手机上的应用程序
List<PackageInfo> infos = pm.getInstalledPackages(0);
for (PackageInfo appInfo : infos) {
AppInfo info = new AppInfo();
// 获得包名
String packagename = appInfo.packageName;
info.setPakageName(packagename);
// 获得应用名称
String appname = appInfo.applicationInfo.loadLabel(pm).toString();
info.setAppname(appname);
// 获得应用图标
Drawable icon = appInfo.applicationInfo.loadIcon(pm);
info.setIcon(icon);
// 获得应用app的绝对路径
String path = appInfo.applicationInfo.sourceDir;
info.setPath(path);
// 获得应用app的大小
File file = new File(path);
long size = file.length();
String sizedata = Formatter.formatFileSize(context, size);
info.setSize(size);
int flag = appInfo.applicationInfo.flags;
if ((flag & ApplicationInfo.FLAG_SYSTEM) == 0) {
// 用户应用
info.setUserapp(true);
} else {
// 系统应用
info.setUserapp(false);
}
if ((flag & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) {
// 存在手机内存
info.setInRom(true);
} else {
// 存在sd内存卡
info.setInRom(false);
}
appinfos.add(info);
}
return appinfos;
}
}
把不同集合数据展示到ListView中
public class AppManagerActivity extends Activity {
private TextView tv_shji_byte;
private TextView tv_sd_byte;
private ListView lv_listview;
private LinearLayout ll_loading;
private List<AppInfo> infos;
private List<AppInfo> userapp;
private List<AppInfo> systemapp;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
lv_listview.setAdapter(new MyAppManagerAdapter());
ll_loading.setVisibility(View.INVISIBLE);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_manager);
tv_shji_byte = (TextView) findViewById(R.id.tv_shji_byte);
tv_sd_byte = (TextView) findViewById(R.id.tv_sd_byte);
lv_listview = (ListView) findViewById(R.id.lv_listview);
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
userapp = new ArrayList<AppInfo>();
systemapp = new ArrayList<AppInfo>();
File datafile = Environment.getDataDirectory();
long datasize = datafile.getFreeSpace();
File sdfile = Environment.getExternalStorageDirectory();
long sdsize = sdfile.getFreeSpace();
tv_shji_byte.setText("手机可用内存"
+ Formatter.formatFileSize(this, datasize));
tv_sd_byte.setText("sd卡可用内存" + Formatter.formatFileSize(this, sdsize));
fillData();
}
/**
* 填充数据
*/
private void fillData() {
new Thread() {
public void run() {
infos = AppManagerInfos
.getAppManagerInfos(AppManagerActivity.this);
for (AppInfo info : infos) {
if (info.isUserapp()) {
// 用户程序
userapp.add(info);
} else {
systemapp.add(info);
// 系统程序
}
}
handler.sendEmptyMessage(0);
};
}.start();
}
private class MyAppManagerAdapter extends BaseAdapter {
@Override
public int getCount() {
return userapp.size() + systemapp.size() + 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
HoldView holder;
if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView;
holder = (HoldView) view.getTag();
} else {
holder = new HoldView();
view = View.inflate(AppManagerActivity.this,
R.layout.item_app_manager, null);
holder.app_name = (TextView) view.findViewById(R.id.app_name);
holder.app_location = (TextView) view
.findViewById(R.id.app_location);
holder.app_icon = (ImageView) view.findViewById(R.id.app_icom);
holder.app_size = (TextView) view.findViewById(R.id.app_size);
view.setTag(holder);
}
AppInfo info;
if (position == 0) {// 显示textView用户程序
TextView tv_user = new TextView(AppManagerActivity.this);
tv_user.setTextSize(15);
tv_user.setBackgroundColor(Color.GREEN);
tv_user.setTextColor(Color.BLACK);
tv_user.setText("用户程序" + userapp.size() + "个");
return tv_user;
} else if (position == userapp.size() + 1) {
TextView tv_system = new TextView(AppManagerActivity.this);
tv_system.setTextSize(15);
tv_system.setBackgroundColor(Color.GREEN);
tv_system.setTextColor(Color.BLACK);
tv_system.setText("系统程序" + systemapp.size() + "个");
return tv_system;
} else if (position < userapp.size() + 1) {
// 用户程序
info = userapp.get(position - 1);
} else {
// 系统程序
info = systemapp.get(position - 2 - userapp.size());
}
holder.app_name.setText(info.getAppname());
holder.app_icon.setImageDrawable(info.getIcon());
holder.app_size.setText(Formatter.formatFileSize(
AppManagerActivity.this, info.getSize()) + "M");
if (info.isInRom()) {
holder.app_location.setText("手机内存");
} else {
holder.app_location.setText("sd卡储存");
}
return view;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
private class HoldView {
TextView app_name;
TextView app_location;
ImageView app_icon;
TextView app_size;
}
}
设置listview属性可使其快速滚动
android:fastScrollEnabled="true"
在listview滚动时悬浮标识符
在帧布局中加入一个TextView
<TextView
android:id="@+id/tv_biaoshi"
android:layout_width="match_parent"
android:background="#00FF00"
android:textColor="#000000"
android:textSize="15sp"
android:text="用户程序"
android:layout_height="wrap_content"/>
不过设置属性时需要和之前区分系统用户时的属性相同,背景色、字体、大小,这样才可以重合
TextView tv_biaoshi=(TextView) findViewById(R.id.tv_biaoshi);
/**
* 给listview注册一个滚动监听器
*/
lv_listview.setOnScrollListener(new OnScrollListener() {
/**
* 当状态发生改变时执行此方法
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/**
* 当listview滚动时执行此方法
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem>userapp.size()){
tv_biaoshi.setText("系统程序"+systemapp.size()+"个");
}else{
tv_biaoshi.setText("用户程序"+userapp.size()+"个");
}
}
});
悬浮窗体的创建使用(轻量级的对话框,内存开销比对话框小,灵活)漂浮的容器,在activity上方
//点击条目弹出悬浮窗体
TextView convertView=new TextView(AppManagerActivity.this);
convertView.setTextSize(15);
convertView.setTextColor(Color.RED);
convertView.setText(info.getPakageName());
popupwindow = new PopupWindow(convertView, 300, 100);
popupwindow.setBackgroundDrawable(new ColorDrawable(Color.GREEN));
//获取点击的条目view对象到窗体的宽高(左上对齐)存在location中x、y
int []location=new int[2];
view.getLocationInWindow(location);
popupwindow.showAtLocation(parent, Gravity.TOP+Gravity.LEFT, 80, location[1]);
不过一般都是自定义悬浮窗体
View convertView=View.inflate(getApplicationContext(), R.layout.item_app_popupwindow, null);
布局文件item.app.popupwindow.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tip_bg"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/my_user_exit" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="启动" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/delete" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="删除" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/wx_share_friends" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="分享" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:src="@drawable/datasafety_item_icon_config" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="信息" />
</LinearLayout>
保证窗体中只有一个悬浮窗体,每次弹出前执行判断;listview滚动时消失也执行此方法
public void dismissPopupwindow() {
if(popupwindow!=null&& popupwindow.isShowing()){
popupwindow.dismiss();
popupwindow=null;
}
动画的播放原理
确定一个变化的函数:
根据这个函数 动态计算在某个时间应该显示什么画面
Canvas Bitmap 要求界面的窗体必须有背景,所以悬浮窗体必须设置背景才能启动动画
}
一键分享
//发送纯文本
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
//intent.setType("image/*");//图片
//intent.setType("video/*");//音频、视频
//intent.setType("*/*");//所有类型
intent.putExtra(Intent.EXTRA_TEXT, "请使用这款软件");
startActivity(intent);
一键卸载
动态注册广播接收者
innerReceiver=new InnerUninstallAppReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
registerReceiver(innerReceiver, filter);
/**
* 卸载软件程序后需要更新数据注册一个广播接收者
*/
private void uninstallapp() {
if(info.isUserapp()){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:"+info.getPakageName()));
startActivity(intent);
}else{
ToastUtils.show(this, "应用程序需要root权限才能卸载");
}
}
/**
* 内部类,广播接收者,监听软件卸载的事件
* @author Administrator
*
*/
private class InnerUninstallAppReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(info.isUserapp()){
userapp.remove(info);
}else{
systemapp.remove(info);
}
adapter.notifyDataSetChanged();
}
}
一键启动软件
/**
* 打开软件的功能
*/
public void openApp() {
PackageManager pm=getPackageManager();
Intent intent=pm.getLaunchIntentForPackage(info.getPakageName());
if(intent!=null){
startActivity(intent);
}else{
ToastUtils.show(this, "软件无法启动!");
}
}
查看应用程序信息(也可卸载应用程序:系统的设置卸载界面)
/**
* 查看应用程序全部信息
*/
private void showApp() {
//查找上层应用程序源码
/* <action android:name="android.settings.APPLICATION_DETAILS_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />*/
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+info.getPakageName()));
startActivity(intent);
}
获取手机所有正在运行的进程(返回的是List集合)
package coma.mobilephone.engine;
import java.util.ArrayList;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import coma.mobilephone.domain.ProcessInfo;
/**
* 获取所有正在运行的进程信息
* @author Administrator
*
*/
public class TaskInfoProvifer {
public static List<ProcessInfo> getRunningProcessInfo(Context context){
List<ProcessInfo> process=new ArrayList<ProcessInfo>();
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
PackageManager pm=context.getPackageManager();
//获取正在运行的进程集合
List<RunningAppProcessInfo>processrunninginfoinfo=am.getRunningAppProcesses();
//遍历集合
for(RunningAppProcessInfo runninginfo:processrunninginfoinfo){
ProcessInfo processinfo=new ProcessInfo();
//进程包名
String packageName=runninginfo.processName;
processinfo.setPackageName(packageName);
long menSize=am.getProcessMemoryInfo(new int[]{runninginfo.pid})[0].
getTotalPrivateDirty()*1024;
processinfo.setMenSize(menSize);
try {
PackageInfo packageinfo=pm.getPackageInfo(packageName, 0);
//进程图标
Drawable icon=packageinfo.applicationInfo.loadIcon(pm);
processinfo.setIcon(icon);
//进程名称
String processName=packageinfo.applicationInfo.loadLabel(pm).toString();
processinfo.setProcessName(processName);
//
if((packageinfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)!=0){
//系统进程
processinfo.setUserProcess(false);
}else{
//用户进程
processinfo.setUserProcess(true);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
process.add(processinfo);
}
return process;
}
}
javabean类的信息
package coma.mobilephone.domain;
import android.graphics.drawable.Drawable;
/**
* 进程包含的信息
* @author Administrator
*
*/
public class ProcessInfo {
private String packageName;
private String processName;
private Drawable icon;
private long menSize;
private boolean userProcess;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getProcessName() {
return processName;
}
public void setProcessName(String processName) {
this.processName = processName;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public long getMenSize() {
return menSize;
}
public void setMenSize(long menSize) {
this.menSize = menSize;
}
public boolean isUserProcess() {
return userProcess;
}
public void setUserProcess(boolean userProcess) {
this.userProcess = userProcess;
}
}
区分用户进程和系统进程(这是耗时操作)
List<ProcessInfo> processinfo=TaskInfoProvifer.getRunningProcessInfo(getApplicationContext());
userprocess=new ArrayList<ProcessInfo>();
systemprocess=new ArrayList<ProcessInfo>();
for(ProcessInfo process:processinfo){
if(process.isUserProcess()){
//用户程序
userprocess.add(process);
}else{
//系统程序
systemprocess.add(process);
}
}
//通知界面更新
handler.sendEmptyMessage(0);
打开一个服务,内部注册一个广播接收者,监听锁屏清理进程
public class AutoKillService extends Service {
private InnerScrrenOffReceiver receiver;
private Timer timer;
private TimerTask task;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
receiver=new InnerScrrenOffReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
/**
* 常用定时器,可设置为定时清理的功能
*/
timer=new Timer();
task=new TimerTask() {
@Override
public void run() {
//System.out.println("每1秒执行一次");
//清理的逻辑
}
};
timer.schedule(task,0, 1000);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
task.cancel();
unregisterReceiver(receiver);
receiver=null;
}
private class InnerScrrenOffReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//System.out.println("哈哈,屏幕锁屏了");
ActivityManager am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infos= am.getRunningAppProcesses();
for(RunningAppProcessInfo info:infos){
//杀死后台进程
am.killBackgroundProcesses(info.processName);
}
}
}
}
如何创建一个widget只需要3步
1、定义一个广播接收者继承AppwidgetProvider
2、在清单文件中配置广播接收者
<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>
3、建立一个xml文件夹存放资源example_appwidget_info.xml
<appwidget-provider xmlns:android="http://schemas.android/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000" //一天更新,最少半小时
android:previewImage="@drawable/preview"
android:initialLayout="@layout/example_appwidget">
</appwidget-provider>
4、自定义布局example_appwidget的内容
生命周期:
在手机桌面上创建第一个widget
11-05 00:46:24.817: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:46:24.817: I/System.out(1687): onenable (适合应用程序widget的初始化.)
11-05 00:46:24.817: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:46:24.817: I/System.out(1687): onupdate (只要有新的widget被创建都会调用onupdate方法)
11-05 00:46:27.347: I/System.out(1687): onreceive 接收到了系统的广播消息
如果界面上已经有一个widget被创建,再创建相同的widget
11-05 00:47:34.728: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:47:34.728: I/System.out(1687): onupdate
11-05 00:47:36.629: I/System.out(1687): onreceive 接收到了系统的广播消息
删除一个widget
11-05 00:48:48.019: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:48:48.019: I/System.out(1687): ondelete
最后一个widget被删除
11-05 00:49:25.710: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:49:25.710: I/System.out(1687): ondelete
11-05 00:49:25.710: I/System.out(1687): onreceive 接收到了系统的广播消息
11-05 00:49:25.710: I/System.out(1687): ondisabled (适合做应用程序扫尾的操作,)
总结: 不要记生命周期调用的先后顺序.
onenable 方法什么时候调用
ondisabled 方法什么时候调用
onupdate方法 在每次创建新的widget的时候都会调用 , 并且当时间片到的时候也会调用
创建widget模板
public class MyWidget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {//创建第一个桌面widget的时候调用
super.onReceive(context, intent);
}
//每次创建widget时都会调用
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Intent intent=new Intent(context,UpdateWidgetService.class);
context.startService(intent);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
//删除widget会调用
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
//对widget做初始化时调用
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
//结束widget是调用,做扫尾工作
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Intent intent=new Intent(context,UpdateWidgetService.class);
context.stopService(intent);
}
}
桌面启动服务定时更新widget
public class UpdateWidgetService extends Service {
private Timer timer;
private TimerTask task;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
timer=new Timer();
task=new TimerTask(){
@Override
public void run() {
System.out.println("更新widget里面的内容");
/*
* 进程间通讯
*/
ComponentName provider=new ComponentName(getApplicationContext(), MyWidget.class);
/*
* 告诉桌面布局文件去哪里找
*/
RemoteViews views=new RemoteViews(getPackageName(), R.layout.process_widget);
views.setTextViewText(R.id.process_count, "正在运行的软件"+ProcessInfoUtils.getRunningProcessCount(getApplicationContext())+"个");
String availstr=Formatter.formatFileSize(getApplicationContext(), ProcessInfoUtils.getAvialRam(getApplicationContext()));
views.setTextViewText(R.id.process_memory, "可用内存:"+availstr);
am.updateAppWidget(provider, views);
}};
timer.schedule(task, 0, 5000);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
task.cancel();
timer=null;
task=null;
}
}
逆向小助手的使用:反编译获取素材资源文件,everything可快速查找
反编译 拖拽到目录
多层显示的帧布局,功能多多
<FrameLayout
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp" >
<ListView
android:fastScrollEnabled="true"
android:id="@+id/lv_process_listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
<LinearLayout
android:id="@+id/ll_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible" >
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载中..." />
</LinearLayout>
<TextView
android:id="@+id/tv_process_biaoshi"
android:layout_width="match_parent"
android:background="#00FF00"
android:textColor="#000000"
android:textSize="15sp"
android:text="用户进程"
android:layout_height="wrap_content"/>
</FrameLayout>
杀死所有运行的进程
ActivityManager am=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> infos=am.getRunningAppProcesses();
for(RunningAppProcessInfo info:infos){
am.killBackgroundProcesses(info.processName);//参数为包名
}
抽屉控件
(重下往上拉),也可指定拉升的高度
<SlidingDrawer
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="@+id/my_content"
android:handle="@+id/my_handle" >
<ImageView
android:id="@id/my_handle" //相当于把柄,,id必须使用父类的
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:id="@id/my_content" //里面的内容,,id必须使用父类的
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是一个" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</SlidingDrawer>
也可重右往左拉
<SlidingDrawer
android:orientation="horizontal" //增加水平属性
android:layout_width="match_parent"
android:layout_height="match_parent"
android:content="@+id/my_content"
android:handle="@+id/my_handle" >
界面的切换(一个切面不同的布局切换)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<TextView
android:id="@+id/app_unlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_left_pressed"
android:gravity="center_vertical"
android:text="未加锁软件"
android:textSize="20sp" />
<TextView
android:id="@+id/app_locked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/tab_right_default"
android:gravity="center_vertical"
android:text="已加锁软件"
android:textSize="20sp" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/ll_loading"
android:visibility="visible"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ProgressBar
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载数据..." />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_appunlock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_unlock_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="未加锁软件" />
<ListView
android:id="@+id/lv_unlock"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_applocked"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone" >
<TextView
android:id="@+id/tv_locked_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加锁软件" />
<ListView
android:id="@+id/lv_locked"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
</FrameLayout>
</LinearLayout>
主活动中点击切换
package coma.mobilephone.activity;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import coma.mobilephone.R;
import coma.mobilephone.db.dao.AppClockDao;
import coma.mobilephone.domain.AppInfo;
import coma.mobilephone.engine.AppManagerInfos;
/**
* 设置程序加锁的Activity
* @author Administrator
*
*/
public class AppLockedActivity extends Activity implements OnClickListener {
private TextView app_unlock;
private TextView app_locked;
/**
* 两种线性布局
*/
private LinearLayout ll_applocked;
private LinearLayout ll_appunlock;
/**
* 两种listview
*/
private ListView lv_locked;
private ListView lv_unlock;
/**
* 正在加载的进度条
*/
private LinearLayout ll_loading;
/**
* 所有程序的集合
*/
private List<AppInfo> infos;
/**
* 显示未加锁程序的个数
*/
private TextView tv_unlock_count;
/**
* 显示加锁程序的个数
*/
private TextView tv_locked_count;
/**
* 加锁的数据库
*/
private AppClockDao dao;
/**
* 加锁集合
*/
private List<AppInfo> lockedInfo;
/**
* 未加锁集合
*/
private List<AppInfo> unlockInfo;
/**
* 未加锁
*/
private MylockAdapter unlockadapter;
/**
* 加锁适配器
*/
private MylockAdapter lockedadapter;
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
// 加载未加锁的适配器
lv_unlock.setAdapter(unlockadapter);
// 加载加锁的适配器
lv_locked.setAdapter(lockedadapter);
ll_loading.setVisibility(View.INVISIBLE);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_applocked);
tv_unlock_count = (TextView) findViewById(R.id.tv_unlock_count);
tv_locked_count = (TextView) findViewById(R.id.tv_locked_count);
ll_loading=(LinearLayout) findViewById(R.id.ll_loading);
dao = new AppClockDao(this);
app_unlock = (TextView) findViewById(R.id.app_unlock);
app_locked = (TextView) findViewById(R.id.app_locked);
// 两种listview
lv_locked = (ListView) findViewById(R.id.lv_locked);
lv_unlock = (ListView) findViewById(R.id.lv_unlock);
// 两个不同点击事件
app_locked.setOnClickListener(this);
app_unlock.setOnClickListener(this);
// 两个线性布局
ll_applocked = (LinearLayout) findViewById(R.id.ll_applocked);
ll_appunlock = (LinearLayout) findViewById(R.id.ll_appunlock);
lockedInfo = new ArrayList<AppInfo>();
unlockInfo = new ArrayList<AppInfo>();
unlockadapter = new MylockAdapter(true);
lockedadapter = new MylockAdapter(false);
new Thread(){
public void run() {
// 获得全部软件程序
infos = AppManagerInfos.getAppManagerInfos(getApplicationContext());
/**
* 遍历集合,区分加锁和未加锁
*/
for (AppInfo info : infos) {
if (dao.find(info.getPakageName())) {
lockedInfo.add(info);
} else {
unlockInfo.add(info);
}
}
handler.sendEmptyMessage(0);
};
}.start();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.app_unlock:// 点击未加锁
ll_appunlock.setVisibility(View.VISIBLE);
ll_applocked.setVisibility(View.GONE);
app_unlock.setBackgroundResource(R.drawable.tab_left_pressed);
app_locked.setBackgroundResource(R.drawable.tab_left_default);
break;
case R.id.app_locked:// 点击已加锁
ll_appunlock.setVisibility(View.GONE);
ll_applocked.setVisibility(View.VISIBLE);
app_unlock.setBackgroundResource(R.drawable.tab_left_default);
app_locked.setBackgroundResource(R.drawable.tab_left_pressed);
break;
}
}
private class MylockAdapter extends BaseAdapter {
/**
* isunlock是否加锁的标识符 true 为未加锁 、 false 已加锁
*/
boolean isunlock;
public MylockAdapter(boolean isunlock) {
this.isunlock = isunlock;
}
@Override
public int getCount() {
int count = 0;
if (isunlock) {
count = unlockInfo.size();
tv_unlock_count.setText("未加锁软件:" + count);
} else {
count = lockedInfo.size();
tv_locked_count.setText("加锁软件:" + count);
}
return count;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
ViewHolder holder;
if (convertView != null && convertView instanceof RelativeLayout) {
view = convertView;
holder = (ViewHolder) view.getTag();
} else {
view = View.inflate(getApplicationContext(),
R.layout.item_unlock_app, null);
holder = new ViewHolder();
holder.img_appicom = (ImageView) view
.findViewById(R.id.img_appicom);
holder.tv_appname = (TextView) view
.findViewById(R.id.tv_appname);
holder.img_locked = (ImageView) view
.findViewById(R.id.img_locked);
view.setTag(holder);
}
final AppInfo info;
if (isunlock) {
info = unlockInfo.get(position);
holder.img_locked
.setImageResource(R.drawable.list_button_lock_pressed);
} else {
info = lockedInfo.get(position);
holder.img_locked
.setImageResource(R.drawable.list_button_unlock_pressed);
}
holder.img_appicom.setImageDrawable(info.getIcon());
holder.tv_appname.setText(info.getAppname());
/**
* 点击加锁按钮移出条目,把数据加到数据库
*/
holder.img_locked.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (isunlock) {
TranslateAnimation am = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0);
am.setDuration(500);
view.startAnimation(am);
am.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 未加锁
unlockInfo.remove(info);
lockedInfo.add(info);
dao.insert(info.getPakageName());
// 通知界面更新
// notifyDataSetChanged();
unlockadapter.notifyDataSetChanged();
lockedadapter.notifyDataSetChanged();
}
});
} else {
TranslateAnimation am = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, -1.0f,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0);
am.setDuration(500);
view.startAnimation(am);
am.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
// 已经加锁
lockedInfo.remove(info);
unlockInfo.add(info);
dao.delete(info.getPakageName());
// 通知界面更新
// notifyDataSetChanged();
unlockadapter.notifyDataSetChanged();
lockedadapter.notifyDataSetChanged();
}
});
}
}
});
return view;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
static class ViewHolder {
TextView tv_appname;
ImageView img_appicom;
ImageView img_locked;
}
}
在Service中开启一个活动Activity 在Activity往Service中发送信息采用自定义广播,只有服务才能接收:
活动中:
Intent intent=new Intent();
intent.setAction("coma.mobilesafe.watchdog");
intent.putExtra("packageNmae",packageName);
sendBroadcast(intent);
在服务中定义一个内部类广播接收者
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
temppackageName = intent.getStringExtra("packageName");
}
}
在onCreate方法中注册广播接收者:
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
registerReceiver(receiver, filter);
程序锁的主逻辑
package coma.mobilephone.service;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import coma.mobilephone.activity.EnterPasswordActivity;
import coma.mobilephone.db.dao.AppClockDao;
/**
* 看门狗服务,监视运行的软件
* @author Administrator
*
*/
public class WatchDogLockService extends Service {
private ActivityManager am;
private boolean flags;
private AppClockDao dao;
private InnerWatchDogReceiver receiver;
/**
* 临时不需要保护的包名
*/
private String temppackageName;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
registerReceiver(receiver, filter);
//获取活动管理器
am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
flags=true;
dao=new AppClockDao(this);
new Thread(){
public void run() {
while(flags){
//获取任务站里面的情况,对于任务栈里面的信息进行排序,最近使用的排在最前面
List<RunningTaskInfo> infos = am.getRunningTasks(100);
String packageName=infos.get(0).topActivity.getPackageName();
if(dao.find(packageName)){
//程序需要被保护,弹出一个输入密码的对话框
//再次判断是否需要保护
if(packageName.equals(temppackageName)){
//暂时不需要保护
}else{
//需要保护
Intent intent =new Intent(getApplicationContext(),EnterPasswordActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("packageName", packageName);
startActivity(intent);
}
}else{
//程序不需要被保护
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
flags=false;
unregisterReceiver(receiver);
receiver=null;
}
/**
* 定义内部类广播接收者,接收不需要保护的程序包名
* @author Administrator
*
*/
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
temppackageName = intent.getStringExtra("packageName");
}
}
}
程序的优化:考虑每个细节执行的时间,可以优化就优化
当有手机卫士在后台运行时,界面的跳转就不正常了,需要为打开密码保护的程序Activity设置一个模式:打开运用时会在一个新的任务栈中运行,这样就不会跳转回手机卫士了
android:launchMode="singleInstance"
在低版本时运行还没弹出密码界面就已经进入程序界面了,可以看到一些信息了,需要优化代码,执行效率更快
List<RunningTaskInfo> infos = am.getRunningTasks(100);
这句代码我们只需要获取第一个运用程序的包名
List<RunningTaskInfo> infos = am.getRunningTasks(1)定义为;
并定义为成员变量
优化:查询数据库所消耗的时间比内存中的多,把数据库查询的数据放在内存中,需要使用时到内存中查找即可
优化程序后发现新增加的要保护的程序保护不了,想到数据库查询时已经把数据存储在内存中固定了,所以要重新查询即更新数据,可以使用广播接收者、也可以使用内容观察者来观察数据库的变化,增加和删除一旦发现,重新查询数据存进内存中。
优化后的代码:电量的优化 屏幕锁屏后和锁屏的广播接收者
/**
* 看门狗服务,监视运行的软件
* @author Administrator
*
*/
public class WatchDogLockService extends Service {
private ActivityManager am;
private boolean flags;
private AppClockDao dao;
private InnerWatchDogReceiver receiver;
private List<RunningTaskInfo> infos ;
private String packageName;
/**
* 临时不需要保护的包名
*/
private String temppackageName;
/**
* 内容观察者
*/
private AppClockDaoObserver observer;
private Intent intent;
private List<String> packname;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//注册一个广播接收者
receiver=new InnerWatchDogReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction("coma.mobilephone.watchdog");
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(receiver, filter);
intent = new Intent(getApplicationContext(),EnterPasswordActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//获取活动管理器
am=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
dao=new AppClockDao(this);
packname = dao.findAll();
//注册一个内容观察者
Uri uri=Uri.parse("content://coma.mobilephone.appclockdb");
observer=new AppClockDaoObserver(new Handler());
getContentResolver().registerContentObserver(uri, true, observer);
showWhatchDogStart();
}
/*
*对电量的优化,锁屏后停止监控
*
*/
public void showWhatchDogStart() {
if(flags==false){
return ;
}
flags=true;
new Thread(){
public void run() {
while(flags){
//获取任务站里面的情况,对于任务栈里面的信息进行排序,最近使用的排在最前面
infos= am.getRunningTasks(1);
packageName=infos.get(0).topActivity.getPackageName();
if(packname.contains(packageName)){
//程序需要被保护,弹出一个输入密码的对话框
//再次判断是否需要保护
if(packageName.equals(temppackageName)){
//暂时不需要保护
}else{
//需要保护
intent.putExtra("packageName", packageName);
startActivity(intent);
}
}else{
//程序不需要被保护
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
flags=false;
unregisterReceiver(receiver);
receiver=null;
}
/**
* 定义内部类广播接收者
* @author Administrator
*
*/
private class InnerWatchDogReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if("coma.mobilephone.watchdog".equals(intent.getAction())){
temppackageName = intent.getStringExtra("packageName");
}else if(Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
//屏幕锁屏
temppackageName=null;
flags=false;
}else if(Intent.ACTION_SCREEN_ON.equals(intent.getAction())){
//屏幕解锁
showWhatchDogStart();
}
}
}
/**
* 定义内容观察者内部类
* @author Administrator
*
*/
private class AppClockDaoObserver extends ContentObserver{
public AppClockDaoObserver(Handler handler) {
super(handler);
}
//观察到数据库内容发生变化
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
System.out.println("内容观察者观察到数据库发生变化了");
packname = dao.findAll();
}
}
}
内容观察者
数据库中大声发个消息
Uri uri=Uri.parse("content://coma.mobilesafe.applockdb");
context.getContentResolver().notifyChange(Uri,null);
注册一个内容观察者:
Uri uri=Uri.parse("content://coma.mobilesafe.applockdb");
observer=new ApplockDBObserver(new Handler());
getContentResolver().registerContentObserver(uri,true,observer);
定义一个内容观察者内部类
/**
* 定义内容观察者内部类
* @author Administrator
*
*/
private class AppClockDaoObserver extends ContentObserver{
public AppClockDaoObserver(Handler handler) {
super(handler);
}
//观察到数据库内容发生变化
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
packname = dao.findAll();
}
}
目录
getFilesDir(); //data/data/<包名>/files 文件目录
getCacheDir(); //data/data/<包名>/cache 缓存目录
扫描手机获取所有程序员的缓存
public class CleanCacheActivity extends Activity {
protected static final int SCAN_STOP = 1;
public static final int SEND_SCAN = 2;
private ProgressBar pb;
private TextView tv_scan_cache;
private FrameLayout fl_scan_states;
private PackageManager pm;
private ListView lv_scan_listview;
private List<CacheHolder>cache;
private MyAdapter adapter;
/**
* 消息机制
*/
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
switch(msg.what){
case SCAN_STOP://扫描结束
Toast.makeText(getApplicationContext(), "扫描完毕", 0).show();
fl_scan_states.setVisibility(View.GONE);
if(cache.size()>0){
//设置适配器
adapter=new MyAdapter();
lv_scan_listview.setAdapter(adapter);
}else{
ToastUtils.show(CleanCacheActivity.this, "恭喜你,你的手机100分");
}
break;
case SEND_SCAN://正在扫描
String appname=(String) msg.obj;
tv_scan_cache.setText("正在清理:"+appname);
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clean_cache);
//初始化数据
pb=(ProgressBar) findViewById(R.id.pb);
tv_scan_cache=(TextView) findViewById(R.id.tv_scan_cache);
fl_scan_states=(FrameLayout) findViewById(R.id.fl_scan_states);
lv_scan_listview=(ListView) findViewById(R.id.lv_scan_listview);
pm=getPackageManager();
//扫描缓存
scanCache();
}
/**
* 扫描手机应用分别获取缓存信息
*/
private void scanCache() {
fl_scan_states.setVisibility(View.VISIBLE);
cache=new ArrayList<CacheHolder>();
//开子线程扫描程序缓存
new Thread(){
public void run() {
pb.setMax(100);
int progress=0;
//1、扫描应用程序全部的包名
List<PackageInfo>infos=pm.getInstalledPackages(0);
for(PackageInfo info:infos){
try {
//获取每个程序的包名
String packagename=info.packageName;
//利用反射获取指定的方法名
Method method=PackageManager.class.getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);
method.invoke(pm,packagename,new MyObserver());
} catch (Exception e) {
e.printStackTrace();
}
//进度条的设置
progress++;
pb.setProgress(progress);
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//2、通知界面更新
Message msg=Message.obtain();
msg.what=SCAN_STOP;
handler.sendMessage(msg);
};
}.start();
}
private class MyObserver extends IPackageStatsObserver.Stub{
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
try {
//把扫描到的包名发送回主界面更新
Message msg=Message.obtain();
msg.what=SEND_SCAN;
String appname=pm.getPackageInfo(pStats.packageName, 0).
applicationInfo.loadLabel(pm).toString();
msg.obj=appname;
handler.sendMessage(msg);
//主有有缓存大小的程序才需要存进集合中
if(pStats.cacheSize>0){
CacheHolder holder=new CacheHolder();
holder. cachesize=pStats.cacheSize;//缓存大小
holder. packName=pStats.packageName;//代码大小
holder. icon=pm.getPackageInfo(holder. packName, 0).applicationInfo.loadIcon(pm);
holder. appName=appname;
cache.add(holder);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class CacheHolder{
long cachesize;
String packName;
Drawable icon;
String appName;
}
/**
* listview的适配器
* @author Administrator
*
*/
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return cache.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder holder;
//服用历史缓存对象,优化listview
if(convertView!=null){
view=convertView;
holder=(ViewHolder) view.getTag();
}else{
holder=new ViewHolder();
view=View.inflate(getApplicationContext(), R.layout.item_cache_listview, null);
holder.icon=(ImageView) view.findViewById(R.id.img_icon);
holder.apname=(TextView) view.findViewById(R.id.tv_appname);
holder.cachesize=(TextView) view.findViewById(R.id.tv_cachesize);
holder.clearcache=(ImageView) view.findViewById(R.id.img_clear_button);
view.setTag(holder);
}
final CacheHolder cacheholder=cache.get(position);
holder.icon.setImageDrawable(cacheholder.icon);
holder.apname.setText(cacheholder.appName);
holder.cachesize.setText("缓存大小"+Formatter.formatFileSize(getApplicationContext(), cacheholder.cachesize));
holder.clearcache.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//打开应用程序信息
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+cacheholder.packName));
startActivity(intent);
}
});
if(cacheholder.cachesize==0){
cache.remove(cacheholder);
adapter.notifyDataSetChanged();
}
return view;
}
}
private class ViewHolder{
ImageView icon;
TextView apname;
TextView cachesize;
ImageView clearcache;
}
class ClearCacheObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(final String packageName, final boolean succeeded) {
ToastUtils.show(CleanCacheActivity.this, "清除状态"+succeeded);
}
}
/**
* 清理全部的缓存空间
* @param view
*/
public void AllClearCache(View view){
Method[] methods=PackageManager.class.getMethods();
for(Method method:methods){
if("freeStorageAndNotify".equals(method.getName())){
try {
method.invoke(pm, Long.MAX_VALUE*1024,new ClearCacheObserver());
} catch (Exception e) {
e.printStackTrace();
}
scanCache();
return ;
}
}
}
}
自定义进度条
在drawable下建立一个progress_horizontal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android/apk/res/android">
//整个进度条背景
<item android:id="@android:id/background" android:drawable="@drawable/security_progress_bg">
</item>
<item android:id="@android:id/secondaryProgress" android:drawable="@drawable/security_progress">
//缓存到的背景
</item>
<item android:id="@android:id/progress" android:drawable="@drawable/security_progress">
//当前背景
</item>
</layer-list>
设置进度条的属性引用它
android:progressDrawable="@drawable/progress_horizontal"
这样就自定义好了进度条
具体的配置也可配置一下节点
share.xml下
在share节点下
android:shape="rectangle" //圆角矩形
<corners android:radius="5dp"/> //弧度
<gradient //渐变色
android:startColor="#ff0000"
android: endColor="#22ffff00"
/>
<padding //边距
android:left="5dp"
android:right="5dp"
android:top="5dp"
android:bottom="5dp"
/>
<solid android:width="1dp" android:color="#0000ff"/> //固定颜色不可和渐变色一起使用
<stroke android:width="1dp" android:color="#000000"
//实线 android:dashWidth="5dp" android:dashGap="2dip" //虚线
/>
清理缓存
//打开应用程序信息,手动清除
Intent intent =new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT" );
intent.setData(Uri.parse("package:"+cacheholder.packName));
startActivity(intent);
全部清理缓存
/**
* 清理全部的缓存空间
* @param view
*/
public void AllClearCache(View view){
Method[] methods=PackageManager.class.getMethods();
for(Method method:methods){
if("freeStorageAndNotify".equals(method.getName())){
try {
method.invoke(pm, Long.MAX_VALUE*1024,new ClearCacheObserver());
} catch (Exception e) {
e.printStackTrace();
}
scanCache();
return ;
}
}
}
手机杀毒的方式
1、最原始的查杀方式
基于文件的的特征码(缺点:只能查杀已知的病毒,不能查杀未知的病毒)
2、基于程序的行为去查杀(主动防御)
替换系统的API(看雪论坛)
3、人工智能(学习模式+数据库)
字符串与字符串之间的距离
手机杀毒的实现
数据库的实现:
package coma.mobilephone.db.dao;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
/**
* 病毒数据库
* @author Administrator
*
*/
public class AntiVriusDao {
/**
* 在数据库中查找程序特征码是否存在,存在就是病毒软件,不存在就不是
* @param md5
* @return
*/
public static String isVriusdb(String md5){
SQLiteDatabase db=SQLiteDatabase.openDatabase("/data/data/coma.mobilephone/files/antivirus.db",
null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor=db.rawQuery("select desc from datable where md5=?", new String[]{md5});
String desc=null;
if(cursor.moveToNext()){
desc=cursor.getString(0);
}
db.close();
cursor.close();
return desc;
}
}
ui布局·:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_scanner_malware" />
<ImageView
android:id="@+id/img_rotate"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:src="@drawable/act_scanning_03" />
</FrameLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<TextView
android:id="@+id/tv_now_querry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:gravity="center_horizontal"
android:text="正在查杀..." />
<ProgressBar
android:id="@+id/verits_pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_now_querry"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="4dp"
android:progressDrawable="@drawable/progress_horizontal" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_add_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
</LinearLayout>
</LinearLayout>
代码的实现:
public class AntiVirusActivity extends Activity {
private ImageView img_rotate;
private LinearLayout ll_add_text;
private ProgressBar verits_pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_antivures);
img_rotate=(ImageView) findViewById(R.id.img_rotate);
ll_add_text=(LinearLayout) findViewById(R.id.ll_add_text);
verits_pb=(ProgressBar) findViewById(R.id.verits_pb);
/*
* 旋转动画
*/
RotateAnimation ra=new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(2000);
ra.setRepeatCount(Animation.INFINITE);
img_rotate.startAnimation(ra);
//扫描手机应用程序
scanVirus();
}
/**
* 扫描手机应用程序,查找手机病毒程序
*/
private void scanVirus() {
/**
* 遍历手机应用程序的信息,查询他的特征码在病毒数据库中是否存在
*/
PackageManager pm=getPackageManager();
List<PackageInfo> pakageinfos=pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
verits_pb.setMax(pakageinfos.size());
int progress=0;
for(PackageInfo info:pakageinfos){
try {
String apkpath=info.applicationInfo.sourceDir;
File file=new File(apkpath);
MessageDigest digest=MessageDigest.getInstance("md5");
FileInputStream fis=new FileInputStream(file);
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
digest.update(buffer, 0, len);
}
byte [] result=digest.digest();
StringBuffer sb=new StringBuffer();
for(byte b:result){
String str=Integer.toHexString(b&0xff);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
progress++;
verits_pb.setProgress(progress);
String md5=sb.toString();
/**
* 查找md5是否存在病毒数据库中
*/
final String desc=AntiVriusDao.isVriusdb(md5);
final String appname=(String) info.applicationInfo.loadLabel(pm);
runOnUiThread(new Runnable() {
@Override
public void run() {
TextView tv=new TextView(AntiVirusActivity.this);
if(desc!=null){
//发现病毒
tv.setTextColor(Color.RED);
tv.setText(appname+":发现病毒");
}else{
//扫描安全
tv.setTextColor(Color.GREEN);
tv.setText(appname+":扫描安全");
}
ll_add_text.addView(tv, 0);
}
});
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
隐藏应用程序的图标(不被用户发觉)
getPackageManager().setComponentEnabledSetting(getComponentName(),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
围绕中心轴旋转
/*
* 旋转动画
*/
RotateAnimation ra=new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(2000);
ra.setRepeatCount(Animation.INFINITE);
img_rotate.startAnimation(ra);
程序的签名
/**
* 获取应用程序的签名信息、使用MD5加密,要加上标志位PackageManager.GET_SIGNATURES ,系统默认不解析 TODO
*/
System.out.println("程序名"+info.applicationInfo.loadLabel(pm));
System.out.println("签名:"+MD5Utils.encode(info.signatures[0].toCharsString()));
获取程序的校验码
/**
* 获取程序的校验码
*/
//apk的路径
String apkpath=info.applicationInfo.sourceDir;
File file=new File(apkpath);
MessageDigest digest=MessageDigest.getInstance("md5");
//这里使用MD5 也可以使用 "sha-1" 获取
FileInputStream fis=new FileInputStream(file);
byte[] buffer=new byte[1024];
int len=0;
while((len=fis.read(buffer))!=-1){
digest.update(buffer, 0, len);
}
byte [] result=digest.digest();
StringBuffer sb=new StringBuffer();
for(byte b:result){
String str=Integer.toHexString(b&0xff);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
创建应用程序的图标
/**
*创建快捷图标
*/
private void createShortCut() {
SharedPreferences sp=getSharedPreferences("config", MODE_PRIVATE);
boolean shortcut=sp.getBoolean("shortcut", false);
if(!shortcut){
//快捷方式的图片
//快捷方式的名称
//快捷方式干什么事情
//快捷图标其实是显示在桌面的,让桌面帮我们创建快捷图标
//给桌面发送消息
Intent intent=new Intent(); //发送广播的意图
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
//设置数据
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"破荒卫士" );
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
//快捷方式开启对应的意图
Intent shortcutIntent=new Intent();
shortcutIntent.setAction("coma.mobilesafe.home");
shortcutIntent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
//发送创建快捷方式的广播
sendBroadcast(intent);
Editor edit=sp.edit();
edit.putBoolean("shortcut", true);
editmit();
}
}
消息的通知
//消息的通知、先下兼容低版本
private void createNotification() {
//获取通知管理者
NotificationManager nm=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification=new Notification(R.drawable.ic_launcher, "破荒手机卫士正在保护你的手机!", System.currentTimeMillis());
//设置通知的标志
notification.flags=Notification.FLAG_NO_CLEAR;
//意图打开主界面
Intent intent=new Intent();
intent.setAction("coma.mobilesafe.home");
intent.addCategory(Intent.CATEGORY_DEFAULT);
PendingIntent contentIntent= PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(this, "破荒手机卫士", "正在保护你的手机", contentIntent);
nm.notify(0, notification);
}
对应用程序中的Log的控制,想打印什么类型的信息只要修改LOGLEVEL的值
package coma.mobilephone.Utils;
import android.util.Log;
/**
* 应用程序的Log的控制
* @author Administrator
*
*/
public class Logger {
private static final int VERBOSE=1;
private static final int DEBUG=2;
private static final int INFO=3;
private static final int WARN=4;
private static final int ERROR=5;
private static int LOGLEVEL=4;
public static void v(String tag,String msg){
if(VERBOSE>LOGLEVEL){
Log.v(tag, msg);
}
}
public static void d(String tag,String msg){
if(DEBUG>LOGLEVEL){
Log.d(tag, msg);
}
}
public static void i(String tag,String msg){
if(INFO>LOGLEVEL){
Log.i(tag, msg);
}
}
public static void w(String tag,String msg){
if(WARN>LOGLEVEL){
Log.w(tag, msg);
}
}
public static void e(String tag,String msg){
if(ERROR>LOGLEVEL){
Log.e(tag, msg);
}
}
}
应用程序的异常处理,捕获到异常信息存进指定的目录,可以上传至服务器中
package coma.mobilephone.log;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import android.app.Application;
import coma.mobilephone.Utils.Logger;
/**
* 代表的就是当前手机卫士的应用程序
* 《b》一定要注意在清单文件Application中配置,点Browser会自动匹配
* @author Administrator
*
*/
public class MobileSafeApplication extends Application {
//开天地,老母子方法
@Override
public void onCreate() {
super.onCreate();
Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
}
/**
* 捕获异常信息存进sd中,再上传至服务器中
* @author Administrator
*
*/
private class MyExceptionHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Logger.i("","发生了异常,被哥捕获到了。。。。。");
//并不能把异常消化掉,只是在应用程序挂掉之前,来一个留遗嘱的时间
try {
//获取手机适配的信息
Field[] fields=Builder.class.getDeclaredFields();
StringBuffer sb=new StringBuffer();
for(Field field:fields){
String value=field.get(null).toString();
String name=field.getName();
sb.append(value);
sb.append(":");
sb.append(name);
sb.append("\n");
}
//输出异常信息
FileOutputStream out=new FileOutputStream("/mnt/sdcard/error.log");
//阻塞性方法,直接写到内存中,内存输出流
StringWriter wr=new StringWriter();
PrintWriter err=new PrintWriter(wr);//打印输出流,异步输出流
ex.printStackTrace(err);
String errorlog=wr.toString();
out.write(errorlog.getBytes());
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
//ActivityManager 可以杀死别的进程,不能自杀,而专注于自杀是 android.os.Process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
}
应用程序的混淆加密(四大组件、自定义控件不可混淆)
操作方法:直接到目录把 sdk/tools/proguard/proguard-android这个文件拷贝到工程目录下就可以导出apk文件了
混淆工作原理:
全局替换 :类名、变量名、方法名
想把什么给保留出来,只要增加一下类似的语句
-keep class coma.mobilesafe.domain.AppInfo
介绍广告
1、内付费互联网公司
2、软件付费
3、免费软件+广告
cpm:千次有效展现
cpc:点击
cpa:完整有效点击
cpd:下载
广告主
代理公司(有米、百度联盟)
小程序员
常见系统的管理器:
- TelephonyManager:电话管理的服务
- SmsManager :信息的管理服务
- DevicesManager :设备的超级管理者
- ActivityManager:活动管理器:获取进程和服务的管理器,相当于window系统的任务管理器,获取的是动态信息
- PackageManager:获取各种包的信息(版本、应用程序图标、包信息等)相当于window系统的软件管理,获取的是静态的信息
- AppWidgetManager 桌面小控件
- NotificationManager 通知的管理
- LocationManager 位置提供者
- WindowManager窗口管理者
版权声明:本文标题:Android之手机卫士涉及的知识点总结 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://it.en369.cn/jiaocheng/1763810769a2965665.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论