安全卫士总结:
一、splash界面:
主要用于展示logo,初始化,检查版本更新,创建桌面图标等操作
初始化:
1、拷贝数据: 文件的输入输出流的使用
如:将电话归属地信息数据库拷贝到系统data/data/包名/files下, 将病毒数据库拷贝到data/data/包名/files下等
代码:
if(new File(getFileDir(),"dbName.db").exists()){
//文件存在则不拷贝
return;
}
FileOutputStream fos = null;
InputStream is = null;
fos = new FileOutputStream(file);
is = getAssets().open(dbName);//获取assest目录下文件
int len = 0;
byte[] b = new byte[1024];
while ((len = is.read(b)) != -1) {
fos.write(b, 0, len);
}
2 版本更新: Android网络编程 ,解析json,Handler,线程。
注: 耗时操作
代码:
Get请求
URL url = new URL("http://ip:8080/update.json"); //URL
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET"); // 请求方法
conn.setConnectTimeout(5000) ; // 连接超时
conn.setReadTimeout(5000); // 响应超时, 虽连接上了,但服务器迟迟不给响应
conn.connect(); // 连接服务器
int responseCode = conn.getResponseCode(); // 获取响应码,返回码为200表示正常,
//当下载资源的某一部分时返回的是206
InputStream inputStream = conn.getInputStream(); //获取服务端返回的结果
解析json
JSONObject jo = new JSONObject(result); //根据result得到一个Json对象,result为服务端返回的.json文件
mVersionName = jo.getString("versionName"); //获取Json中具体值
mVersionCode = jo.getInt("versionCode");
mDesc = jo.getString("description");
mDownloadUrl = jo.getString("downloadUrl");
判断是否有更新
if (mVersionCode > getVersionCode()) {
//更新软件并下载
//xUtils包的使用
}
app安装:主要是跳转到系统安装界面进行安装
action: Intent.ACTION_VIEW = "android.intent.action.VIEW"--------Display the data to the user 启动activity用的
data: URI.fromFile(new File(path)) ----------- app文件
type:"application/vnd.android.package-archive" ---------- 是文件类型,具体为APK的互联网媒体类型
代码:
// 跳转到系统安装页面
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(path),"application/vnd.android.package-archive");
startActivityForResult(intent, 0);
app卸载:
删除一个app所对应的intent-filter
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DELETE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
</intent-filter>
app启动
PackageManager pm = getPackageManager();
// 获取手机中所有具有启动能力的activities,做桌面app时运用
// Intent intent = new Intent();
// intent.setAction(Intent.ACTION_MAIN);
// intent.addCategory(Intent.CATEGORY_LAUNCHER);
// List<ResolveInfo> activities = pm.queryIntentActivities(intent,
// PackageManager.GET_INTENT_FILTERS);
Intent intent = pm.getLaunchIntentForPackage(mAppInfo.getPackName());
if (intent != null) {
startActivity(intent);
dismissPopupWindow();
}
app分享
代码:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, 推荐具体内容);
startActivity(intent);
注:
1、ByteArrayOutputStream在网络通信的使用:
代码:
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
String result = out.toString();
in.close();
out.close();
2、Handler机制:
当一个程序启动时,系统会同时启动一个主线程即UI线程(主要处理用户与UI主键相关的事件),由于Android系统规定子线程不能刷新UI,在多线程中若需要更新UI界面则可以利用Handler消息机制实现,即子线程发送更新UI的消息即携带必要的更新UI的数据,主线程接受并处理消息,在Handler中主要有Message、Looper、MessageQueue三者协调工作。
UI线程创建时自动创建一个Looper,Looper作用是不断的读取MessageQueue(消息对列)中的Message,然后将读取到的消息交给Handler的HandlerMessage方法处理;对于子线程由于在初始化时没有创建Looper,故需创建并启动一个Looper【具体是 1、Looper.prepare 2、new Handler() 3、Looper.loop()】,一个线程只允许存在一个Looper,且Looper.loop()后面的代码不能执行。
3 桌面快捷图标(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, 图标);
//点击时的意图即响应什么事件
Intent newIntent = new Intent();
newIntent.setAction(Intent.ACTION_MAIN); //Intent.ACTION_MAIN标识一个程序的入口,即最先启动的activity
newIntent.addCategory(Intent.CATEGORY_LAUNCHER); //Intent.CATEGORY_LAUNCHER 决定程序是否显示在程序列表中
newIntent.setClassName(getPackageName(), 启动页面的在包中的具体路径);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, newIntent);
sendBroadcast(intent);
二、主界面 展示app的主要功能
主要功能有:"手机防盗", "通讯卫士", "软件管理", "进程管理","流量统计", "手机杀毒", "缓存清理", "高级工具", "设置中心"
三、手机防盗 自定义dialog布局、获取Sim卡信息、联系人数据库的操作、发送短信、sharepreference,手势识别
注:1、在多个界面中若重用的代码很多可以考虑activity的继承
2、overridePendingTransition()界面切换动画
3、sharepreference注意commit()
4、手势识别注意,onTouchEvent()必须要传递给手势识别器,不然无法响应手势,手势监听器有已封装好的listener
3.1 自定义dialog布局
代码:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog dialog = builder.create();
View view = View.inflate(context, layoutID, ViewGroup);
dialog.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom);//viewSpacingX:X方向上背景布局里dialog边界的距离,以免程序运行 在低版本系统上出现黑边框
注:1、AlertDialog的构造方法全部是Protected的,所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法。
2、上述dialog才有(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom)方法,
3、只有builder才有setPositiveButton(xx,xx)和 setNegativeButtonxx,xx)方法。dialog中有public void setButton(CharSequence text, final OnClickListener listener)不过已废弃
3.2 获取Sim卡信息
代码:
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
String simSerialNumber = tm.getSimSerialNumber();// 获取sim卡序列号
3.3、联系人数据库的操作
四个常用的URI:
1、ContactsContract.Contacts.CONTENT_URI:管理联系人的URI
2、ContactsContract.CommonDataKinds.Phone.CONTENT_URI:管理联系人号码的URI
3、ContactsContract.CommonDataKinds.Email.CONTENT_URI:管理联系人E-mail的URI
4、ContactsContract.Data.CONTENT_URI: 管理data表的URI
五个常用的表:
1、contacts表 保存手机中目前所有的联系人,每个联系人占一行,该表保存了联系人的ContactID、联系次数、最后一次联系的时间、是否含有号码、是否被添加到收藏夹等信息
2、raw_contacts表 保存手机中所有创建过的联系人,每个联系人占一行,表里有一列标识该联系人是否被删除,该表保存了两个ID:RawContactID和ContactID,从而将contacts表和raw_contacts表联系起来。该表保存了联系人的RawContactID、ContactID、联系次数、最后一次联系的时间、是否被添加到收藏夹、显示的名字、用于排序的汉语拼音等信息。
3、mimetypes表 该表定义了所有的MimeTypeID,即联系人的各个字段的唯一标志
4、data表 该表保存了所有创建过的手机测联系人的所有信息,每个字段占一行 ,该表保存了两个ID:MimeTypeID和RawContactID,从而将data表和raw_contacts表联系起来
5、phone_lookup表 用于根据手机号码查询联系人
查询顺序:
contacts表获取 ID和Name ---> raw_contacts表 获取 RawcontactsID ---> data 表获取具体数据
伪代码流程:ContactsContract.Contacts.CONTENT_URI 获取 ID和Name ---> ContactsContract.CommonDataKinds.Phone.CONTENT_URI 获取 phone ---> ContactsContract.CommonDataKinds.Email.CONTENT_URI 获取Email
插入顺序:
获得rowcontactID ---> 插入具体数据即类型 ---> 插入data表(URI:ContactsContract.Data.CONTENT_URI )
3.4、发送短信
代码:
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(电话号码, 短信中心号码(一般填空即默认),短信内容, 发送成功时相应的操作, 接受成功相应的操作);
四、通讯卫士 SQLite3 数据库的操作
原理:当有一条短信或来电是,首先查看其是否在黑名单中,若在查询期拦截模式进行拦截。来电监听(TelephonyManager)去电广播,短信接受也是广播。
注:sdk4.4以后,无法对系统短信进行拦截,还原,需要设置默认短信来实现。
代码:
建立数据库
public class BlackNumHelper extends SQLiteOpenHelper {
public static final String dbName = "BlackNumber.db";
public static final String tableName = "Numbers";
public BlackNumHelper(Context context) {
super(context, dbName, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
//数据库创建是同时创建表
db.execSQL("create table "+ tableName + " ( _id integer primary key autoincrement, name varchar(10), number varchar(11), mode varchar(4) )");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
数据库的增删改查 分页和分批加载是一次性加载一部分,避免数据量太大造成不必要的问题
public class BlackNumDbOperate {
private BlackNumHelper helper;
public BlackNumDbOperate(Context context) {
helper = new BlackNumHelper(context);
}
插入一个黑名单号码
public boolean insertDB(BlackNumItem item) {
SQLiteDatabase db = helper.getReadableDatabase();
String name = item.getName();
String number = item.getNumber();
int mode = item.getMode();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("number", number);
values.put("mode", String.valueOf(mode));
long rowID = db.insert(BlackNumHelper.tableName, null, values);
db.close();
if (rowID == -1) {
return false;
} else {
return true;
}
}
删除一个黑名单号码
public boolean delete(String number) {
SQLiteDatabase db = helper.getReadableDatabase();
int rowCount = db.delete(BlackNumHelper.tableName, "number=?",
new String[] { number });
db.close();
if (rowCount == 0) {
return false;
} else {
return true;
}
}
变更拦截模式
public boolean changeMode(String number, int mode) {
SQLiteDatabase db = helper.getReadableDatabase();
if (mode < 1 || mode > 3) {
return false;
}
ContentValues values = new ContentValues();
values.put("mode", String.valueOf(mode));
int rowCount = db.update(BlackNumHelper.tableName, values, "number=?",
new String[] { number });
db.close();
if (rowCount == 0) {
return false;
} else {
return true;
}
}
获取一个号码的拦截模式信息
public int getMode(String number) {
/**
* 黑名单拦截模式 1 全部拦截 拦截 电话+短信 2 电话拦截 3 短信拦截
*/
int mode = 0;
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery("select mode from "
+ BlackNumHelper.tableName + " where number=?",
new String[] { number });
if (cursor.moveToNext()) {
mode = Integer.parseInt(cursor.getString(0));
}
cursor.close();
db.close();
return mode;
}
获取所有黑名单
public List<BlackNumItem> getAllBlackNum() {
SQLiteDatabase db = helper.getReadableDatabase();
ArrayList<BlackNumItem> blacks = new ArrayList<BlackNumItem>();
Cursor cursor = db.query(BlackNumHelper.tableName, new String[] {
"name", "number", "mode" }, null, null, null, null, "_id desc");//逆序
while (cursor.moveToNext()) {
String name = cursor.getString(0);
String number = cursor.getString(1);
int mode = Integer.parseInt(cursor.getString(2));
blacks.add(new BlackNumItem(number, mode, name));
}
cursor.close();
db.close();
return blacks;
}
分页加载 pageNumber从0开始,表示页数
原理:数据库查询时限制查询的数量(limit ?),以及设置偏移量(offset ?)
public ArrayList<BlackNumItem> getPageBlackNum(int pageNumber, int pageSize) {
SQLiteDatabase db = helper.getReadableDatabase();
ArrayList<BlackNumItem> blacks = new ArrayList<BlackNumItem>();
Cursor cursor = db.rawQuery("select name, number, mode from "
+ BlackNumHelper.tableName + " order by _id desc"
+ " limit ? offset ?", new String[] { String.valueOf(pageSize),
String.valueOf((pageNumber-1) * pageSize) });
while (cursor.moveToNext()) {
String name = cursor.getString(0);
String number = cursor.getString(1);
int mode = Integer.parseInt(cursor.getString(2));
blacks.add(new BlackNumItem(number, mode, name));
}
cursor.close();
db.close();
return blacks;
}
分批加载
原理:数据库查询时限制查询的数量(limit ?),以及设置偏移量(offset ?)
public ArrayList<BlackNumItem> getBatchBlackNum(int maxsize, int offset) {
SQLiteDatabase db = helper.getReadableDatabase();
ArrayList<BlackNumItem> blacks = new ArrayList<BlackNumItem>();
Cursor cursor =db.rawQuery("select name, number, mode from "
+ BlackNumHelper.tableName
+ " order by _id desc limit ? offset ?",
new String[] { String.valueOf(maxsize), String.valueOf(offset) });
while (cursor.moveToNext()) {
String name = cursor.getString(0);
String number = cursor.getString(1);
int mode = Integer.parseInt(cursor.getString(2));
blacks.add(new BlackNumItem(number, mode, name));
}
cursor.close();
db.close();
return blacks;
}
获取数据库中的数据量
public int getCount() {
int count = 0;
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery("select count(number) from "
+ BlackNumHelper.tableName, null);
if (cursor.moveToNext()) {
count = cursor.getInt(0);
}
cursor.close();
db.close();
return count;
}
}
挂断电话: AIDL(进程间通信)远程挂断
注:电话记录位于contact2数据库中
private class MyPhoneStateListener extends PhoneStateListener { //来电监听
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
int mode = op.getMode(incomingNumber);
if (mode == 1 || mode == 2) {
//注册电话记录观察者,以便动态删除拦截电话记录,
getContentResolver().registerContentObserver(
CallLog.CONTENT_URI, true,
new myOberver(new Handler(), incomingNumber));
//挂断电话
try {
Class clazz = Class.forName("android.os.ServiceManager"); //反射加载一个类的字节码,然后获取其方法执行
Method method = clazz.getMethod("getService", String.class); //getService为方法名,String.class为参数类型
IBinder binder = (IBinder) method.invoke(null,
new Object[] { TELEPHONY_SERVICE });
ITelephony.Stub.asInterface(binder).endCall();
} catch (Exception e) {
e.printStackTrace();
}
}
break;
}
}
}
观察通话记录的变化情况
private class myOberver extends ContentObserver {
private String number;
public myOberver(Handler handler, String number) {
super(handler);
this.number = number;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
getContentResolver().delete(CallLog.Calls.CONTENT_URI, //CallLog.Calls.CONTENT_URI
CallLog.Calls.NUMBER + "=?", new String[] { number });
getContentResolver().unregisterContentObserver(this);//注销观察者
}
}
获取短信内容:
代码:
public void onReceive(Context context, Intent intent) {
//拿到广播里携带的短信内容
Bundle bundle = intent.getExtras();
Object[] objects = (Object[]) bundle.get("pdus");
for(Object ob : objects ){
//通过object对象创建一个短信对象
SmsMessage sms = SmsMessage.createFromPdu((byte[])ob);
}
}
服务总结:
一、service的生命周期:
1、startSercice(): oncreate()->onstartcommand()->ondestroy()
2、bindService(): oncreate()->onBind()->onUnbind()->ondestroy()
只有绑定服务才能获得服务内部的IBinder对象
二、service与activity的区别是:有无界面,系统回收内存时的优先级
进程优先级
1. 前台进程:拥有前台activity(onResume方法被调用)
2. 可见进程:拥有可见activity(onPause方法被调用)
3. 服务进程:不到万不得已不会被回收,而且即便被回收,内存充足时也会被重启
4. 后台进程:拥有后台activity(activity的onStop方法被调用了),很容易被回收
5. 空进程:没有运行任何activity,很容易被回收
三、调用方法
1、调用本地服务方法:
绑定服务 ---> 得到IBinder对象 ---> 将IBinder对象转换为相应的对象 ---> 通过该对象调用相应的方法
代码:
1.1、首先定义一个接口
public interface musicInterface {
public void play();
public void pause();
}
1.2、然后在service中定义一个内部类,继承IBinder并实现该接口
public class musicService extends Service {
private MediaPlayer mplayer;
@Override
public void onCreate() {
}
@Override
public IBinder onBind(Intent intent) {
return new musicPlay();
}
public class musicPlay extends Binder implements musicInterface{
@Override
public void play() {
startMusic();
}
@Override
public void pause() {
pauseMusic();
}
}
//服务内部的方法
public void startMusic(){
mplayer.start();
}
public void pauseMusic(){
mplayer.pause();
}
}
1.3、bindservice得到IBinder对象,然后强转,最后调用相应的方法
public class MainActivity extends Activity {
private musicInterface mu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, musicService.class);
startService(intent);
bindService(intent, new MusicServiceConn(), Context.BIND_AUTO_CREATE);
}
public class MusicServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mu = (musicInterface) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
public void click(View v){
switch (v.getId()) {
case R.id.start:
mu.play(); //方法的调用
break;
case R.id.pause:
mu.pause(); //方法的调用
break;
}
}
}
2、调用远程服务方法:
2.1、 把远程服务的方法抽取成一个单独的接口 XX.java文件
2.2、 把接口java文件的后缀名直接改成 XX.aidl
2.3、 在自动生成的 XX.java 文件中,有一个静态抽象类Stub,它已经继承了binder类,实现了 XX.java 接口,这个类就是新的中间人
2.4、 把aidl文件复制粘贴到其他项目,粘贴的时候注意,aidl文件所在的包名必须跟原项目中aidl所在的包名一致
2.5、 在其他项目中,强转中间人对象时,直接使用Stub.asInterface()
设备管理器(DevicePolicyManager):
作用:锁屏,擦除手机数据等
代码:
1、添加设备管理器
public static void activeManager(Context context) {
DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName mComponentName = new ComponentName(context,
lockScreenReciver.class);
//启动设备管理器
if (!mDevicePolicyManager.isAdminActive(mComponentName)) {
Intent intent = new Intent(
DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
mComponentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"激活后才能使用一件锁屏功能!");
context.startActivity(intent);
}
}
2、使用DevicePolicyManager
2.1、先自定义一个继承DeviceAdminReceiver的类
代码:
public class MyReciver extends DeviceAdminReceiver {
}
2.2、Activity中使用DevicePolicyManager
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layoutId);
mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(this, MyReciver.class); //ComponentName用于显式指定一个组件
if (mDevicePolicyManager.isAdminActive(mComponentName)) { //isAdminActive判断当前组件是否被激活即可用
mDevicePolicyManager.lockNow(); //锁屏
finish();
} else {
activeManager(this);// 添加设备管理器
}
2.3、Activity清单文件配置:
<receiver
android:name="com.example.mobilesafe.receiver.MyReciver"
android:permission="android.permission.BIND_DEVICE_ADMIN" >
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/my_device_admin_explain" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
my_device_admin_explain.xml:
<device-admin xmlns:android="http://schemas.android.com/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>
五、软件管理 ListView、自定义adapter、packagemanager、悬浮框、程序琐
自定义adapter:重写Baseadapter类,在getView方法中()方法中 根据postion筛选显示的内容,注:contentView复用,及viewHolder的使用
代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
viewHolder holder;
AppInfo Info = null;
// 根据listview的位置分别显示系统app和用户app
if (position == 0) {
TextView tv = new TextView(AppManagerActivity.this);
tvStatus.setText("用户程序(" + userAppInfos.size() + "个)");
tv.setText("用户程序(" + userAppInfos.size() + "个)");
tv.setTextColor(Color.WHITE);
tv.setBackground(new ColorDrawable(Color.GRAY));
return tv;
} else if (position <= userAppInfos.size()) {
Info = userAppInfos.get(position - 1);
} else if (position == userAppInfos.size() + 1) {
TextView tv = new TextView(AppManagerActivity.this);
tv.setText("系统程序(" + systemAppInfos.size() + "个)");
tv.setTextColor(Color.WHITE);
tv.setBackground(new ColorDrawable(Color.GRAY));
return tv;
} else {
Info = systemAppInfos.get(position - userAppInfos.size() - 2);
}
if (convertView == null || !(convertView instanceof RelativeLayout)) {
holder = new viewHolder();
convertView = View.inflate(AppManagerActivity.this,
R.layout.list_app_item, null);
holder.icon = (ImageView) convertView
.findViewById(R.id.iv_app_icon);
holder.tvName = (TextView) convertView
.findViewById(R.id.tv_app_name);
holder.tvlocation = (TextView) convertView
.findViewById(R.id.tv_app_location);
holder.lock = (ImageView) convertView
.findViewById(R.id.iv_app_lock);
convertView.setTag(holder);
} else {
holder = (viewHolder) convertView.getTag();
}
holder.icon.setBackground(Info.getIcon());
holder.tvName.setText(Info.getName());
if (Info.isInRom()) {
holder.tvlocation.setText("内部存储空间");
} else {
holder.tvlocation.setText("外部存储空间");
}
if (lop.find(Info.getPackName())) {
holder.lock.setBackgroundResource(R.drawable.lock);
} else {
holder.lock.setBackgroundResource(R.drawable.unlock);
}
return convertView;
}
packagemanager:类比win7系统的卸载或更改程序,可以获得所有系统已安装的程序的名称、图标、安装的位置、是否为系统应用等
代码:
// 获取手机中所有已安装的程序
public static ArrayList<AppInfo> getInstalledApps(Context context) {
PackageManager pm = context.getPackageManager();
List<PackageInfo> packages = pm.getInstalledPackages(0);
ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>();
for (PackageInfo packageInfo : packages) {
Drawable icon = packageInfo.applicationInfo.loadIcon(pm);
String name = packageInfo.applicationInfo.loadLabel(pm).toString();
String packName = packageInfo.packageName;
AppInfo info = new AppInfo(icon, name, packName);
int flag = packageInfo.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 {
info.setInRom(false);
}
appInfos.add(info);
}
return appInfos;
}
//获取手机中已安装的app使用流量的情况
public static ArrayList<AppInfo> getInstalledAppsTrafficInfo(Context context) {
PackageManager pm = context.getPackageManager();
List<ApplicationInfo> applicationInfos = pm.getInstalledApplications(0);
ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>();
for (ApplicationInfo info : applicationInfos) {
Drawable icon = info.loadIcon(pm);
String name = info.loadLabel(pm).toString();
String packName = info.packageName;
// 获取流量信息,只能获取开机到目前为止的流量信息
int uid = info.uid; //一个app在安装时其uid已经确定,且在卸载前不会变化,一旦程序卸载将由其他新安装的程序使用该uid
long rxBytes = TrafficStats.getUidRxBytes(uid); //已接收的流量
long txBytes = TrafficStats.getUidTxBytes(uid); //已上传的流量
AppInfo item = new AppInfo(icon, name, packName);
item.setTrafficSize(txBytes+rxBytes);
int flag = info.flags;
if ((flag & ApplicationInfo.FLAG_SYSTEM) == 0) {
item.setUserApp(true);
} else {
item.setUserApp(false);
}
if ((flag & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0) {
item.setInRom(true);
} else {
item.setInRom(false);
}
appInfos.add(item);
}
return appInfos;
}
ActivityManager:类比win7系统的任务管理器,可以获得所有运行着的进程,及进程信息、系统内存信息等
代码:
// 获取系统中正在运行的进程数
public static int getProcessCount(Context context) {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am
.getRunningAppProcesses();
return runningAppProcesses.size();
}
// 获取可用内存
public static long getAvaiMem(Context context) {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo outInfo = new MemoryInfo();
am.getMemoryInfo(outInfo);
return outInfo.availMem;
}
// 获取总内存
public static long getTotalMem(Context context) {
// ActivityManager am = (ActivityManager)
// context.getSystemService(Context.ACTIVITY_SERVICE);
// MemoryInfo outInfo = new MemoryInfo();
// am.getMemoryInfo(outInfo);
// return outInfo.totalMem;
long totalMem = 0;
File file = new File("proc/meminfo");
try {
FileInputStream fis = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(
fis));
String[] str = reader.readLine().split(" ");// MemTotal: 1028744 kB
for (String string : str) {
if (string.matches("^\\d+$")) {
totalMem = Long.parseLong(string);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return totalMem;
}
悬浮框(PopupWindow):
代码:
mPopupWindow = new PopupWindow(自定义布局View,宽,高); //ViewGroup.LayoutParams.WRAP_CONTENT <=>wrap_content
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//悬浮框没有背景,若给其添加动画必须指定背景不然动画效果无法显示
mPopupWindow.showAtLocation(悬浮的父窗体,悬浮的位置,悬浮框距父窗体左边的距离, 悬浮框距父窗体上边的距离);
//获取父窗体在手机屏幕中的位置
int[] location = new int[2];
view.getLocationInWindow(location);//location[0]:左边距,location[1]:上边距
程序琐:
原理:程序琐是一个死循环,它不断获取手机任务栈中栈顶任务即用户正欲操作的程序,判断其是否在加密保护列表中,若是,直接启动程序琐,且让程序琐运行在栈顶,提示用户输入密码。
注:1、程序琐界面此时应位于手机屏幕上,将保护的程序界面遮盖在其下
2、注意节电处理,关屏时应停止线程运行
3、单例模式及不保留活动痕迹(代码: <activity android:name="ActivityName"
android:launchMode="singleTask"
android:excludeFromRecents="true"/>)
代码:
private class myRunnable implements Runnable{
@Override
public void run() {
while (flag) {
runningTasks = am.getRunningTasks(1);
String packageName = runningTasks.get(0).topActivity
.getPackageName();
if (lockedApps.contains(packageName)) {
if (!(temStopPacName.equals(packageName))) {
启动程序琐界面
}
}
SystemClock.sleep(80);//Cpu睡眠,省电处理
}
}
Java多线程复习:
转:http://lavasoft.blog.51cto.com/62575/27069
六、缓存清理
1、获取所有已安装app的信息:安装包大小、数据大小、缓存大小
获得方法是通过发射调用系统方法:
public abstract void getPackageSizeInfo(String packageName, int userHandle,IPackageStatsObserver observer);//该方法别系统隐藏
在observer中可以获取这些信息。
代码:
Method getPackageSizeInfoMethod = PackageManager.class.getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);
getPackageSizeInfoMethod.invoke(pm, packagename,new myIPackageStatsObserver());
// 获取手机中已安装app缓存信息
private class myIPackageStatsObserver extends IPackageStatsObserver.Stub { //IPackageStatsObserver 是系统的aidl方法
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)throws RemoteException {
packagename = pStats.packageName;
long cacheSize = pStats.cacheSize;
long dataSize = pStats.dataSize;
long codeSize = pStats.codeSize;
}
}
2、由于只有系统应用才能清理缓存,故点击某个程序的缓存清理按钮时只能跳转到期详细设置页面手动清理
代码:
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + PackageName));
startActivity(intent);
3、一键清理:利用Android系统一个漏洞进行清理:向系统申请一定大小的空间进行相应的操作时,系统会检查期可用空间大小,若发现可用空间大小小于申请空间的大小则会清理掉申请空间大小减去可用空间大小的缓存,故可以申请一块很大的内存空间使得系统将所有应用的缓存全部清理掉
代码:
public void click(View v) {
//mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver);
try {
//Method method = PackageManager.class.getMethod("freeStorageAndNotify", long.class,IPackageDataObserver.class);
Method[] methods = PackageManager.class.getMethods();
for (Method method : methods) {
if (method.getName().equals("freeStorageAndNotify")) {
method.invoke(pm, Integer.MAX_VALUE,new clearAllObserve());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private class clearAllObserve extends IPackageDataObserver.Stub{ //IPackageDataObserver系统aidl文件
@Override
public void onRemoveCompleted(String packageName, boolean succeeded)
throws RemoteException {
if (succeeded) {
显示已清理完毕
}
}
}
七、设置中心 自定义view