完成了通讯卫士功能,接着来做软件管理。
先来说下界面,软件管家主界面有一个标题栏,这个可以根据自己的喜好设置。然后下面是一个RelativeLayout,包含了两个TextView,分别用来显示手机和SD卡可用容量。最后是一个FramLayout,包含一个ListView,用来显示已安装的app的具体信息,还有一个TextView,由来显示用户/系统应用个数。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include layout="@layout/titlebar"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp">
<TextView
android:id="@+id/tv_phonememory_appmanager"
style="@style/textview12sp"
android:layout_alignParentLeft="true"
/>
<TextView
android:id="@+id/tv_sdmemory_appmanager"
style="@style/textview12sp"
android:layout_alignParentRight="true"/>
</RelativeLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/lv_appmanager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@color/transparent"/>
<TextView
android:id="@+id/tv_appnumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="@color/black"
android:background="@color/graye5"/>
</FrameLayout>
</LinearLayout>
然后是每个item的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp">
<ImageView
android:id="@+id/imgv_appicon"
android:layout_width="50dp"
android:layout_height="50dp"/>
<TextView
android:id="@+id/tv_appsize"
style="@style/textview16sp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"/>
<TextView
android:id="@+id/tv_appname"
style="@style/textview16sp"
android:layout_toRightOf="@+id/imgv_appicon"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"/>
<TextView
android:id="@+id/tv_appisroom"
style="@style/textview14sp"
android:layout_marginTop="3dp"
android:layout_alignLeft="@+id/tv_appname"
android:layout_toRightOf="@+id/imgv_appicon"
android:layout_below="@+id/tv_appname"/>
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/black30"/>
<LinearLayout
android:id="@+id/ll_option_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="3dp"
android:visibility="visible">
<TextView
android:id="@+id/tv_launch_app"
style="@style/tvyellow14sp"
android:drawableTop="@drawable/phoneicon_yellow_n"
android:text="启动"/>
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="@color/black30"/>
<TextView
android:id="@+id/tv_uninstall_app"
style="@style/tvyellow14sp"
android:drawableTop="@drawable/deleteicon_yellow_n"
android:text="卸载"/>
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="@color/black30"/>
<TextView
android:id="@+id/tv_share_app"
style="@style/tvyellow14sp"
android:text="分享"
android:drawableTop="@drawable/shareicon_yellow_n"/>
<View
android:layout_width="1px"
android:layout_height="match_parent"
android:background="@color/black30"/>
<TextView
android:id="@+id/tv_setting_app"
style="@style/tvyellow14sp"
android:text="设置"
android:drawableTop="@drawable/settingicon_yellow_n"/>
</LinearLayout>
</LinearLayout>
界面完成了,接下来实现逻辑部分
我们要想在我们的界面上显示所有应用的具体信息,首先要得到各个应用,这个可用packagemanager的相关方法来实现。我们要得到的消息有应用的图标,name,是否在手机内存,是否是用户应用,大小。信息很多,所以先建立一个实体类来包含这些信息,以便后面使用。
package com.yangmiaoqing.example.myassitant;
import android.graphics.drawable.Drawable;
public class AppInfo {
/** 应用程序包名 */
public String packageName;
/** 应用程序图标 */
public Drawable icon;
/** 应用程序名称 */
public String appName;
/** 应用程序路径 */
public String apkPath;
/** 应用程序大小 */
public long appSize;
/** 是否是手机存储 */
public boolean isInRoom;
/** 是否是用户应用 */
public boolean isUserApp;
/** 是否选中,默认都为false */
public boolean isSelected = false;
/**拿到App位置字符串*/
public String getAppLocation(boolean isInRoom) {
if (isInRoom) {
return "手机内存";
} else {
return "外部存储";
}
}
}
接着我们来写一个类来获取这些信息,因为我们要把信息填充到ListView中去,肯定要配置adapter,因此我们在这个类里直接写一个返回值是List<AppInfo>类型的函数。在这里,先实例化一个PackageManager pm,然后调用pm.getIntalledPackage来得到所有已安装应用的包
package com.yangmiaoqing.example.myassitant;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
public class AppInfoParser {
/**
* 获取手机里面的所有的应用程序
* @param context 上下文
* @return
*/
public static List<AppInfo> getAppInfos(Context context){
//得到一个java保证的 包管理器。
PackageManager pm = context.getPackageManager();
List<PackageInfo> packInfos = pm.getInstalledPackages(0);
List<AppInfo> appinfos = new ArrayList<AppInfo>();
for(PackageInfo packInfo:packInfos){
AppInfo appinfo = new AppInfo();
String packname = packInfo.packageName;
appinfo.packageName = packname;
Drawable icon = packInfo.applicationInfo.loadIcon(pm);
appinfo. icon = icon;
String appname = packInfo.applicationInfo.loadLabel(pm).toString();
appinfo.appName = appname;
//应用程序apk包的路径
String apkpath = packInfo.applicationInfo.sourceDir;
appinfo.apkPath = apkpath;
File file = new File(apkpath);
long appSize = file.length();
appinfo.appSize = appSize;
//应用程序安装的位置。
int flags = packInfo.applicationInfo.flags; //二进制映射 大bit-map
if((ApplicationInfo.FLAG_EXTERNAL_STORAGE & flags)!=0){
//外部存储
appinfo.isInRoom = false;
}else{
//手机内存
appinfo.isInRoom = true;
}
if((ApplicationInfo.FLAG_SYSTEM&flags)!=0){
//系统应用
appinfo.isUserApp = false;
}else{
//用户应用
appinfo.isUserApp = true;
}
appinfos.add(appinfo);
appinfo = null;
}
return appinfos;
}
}
完成这些,我们已经可以实现把已安装的应用显示到我们的界面上了,但是我们要做的还不止于此。将信息显示到界面上之后,我们还可以做一些操作如:启动,卸载,分享,设置权限等。我们先做一个工具类,来做这些事,到时候只需要调用即可。
package com.yangmiaoqing.example.myassitant;
import com.stericson.RootTools.RootTools;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.widget.Toast;
/**业务工具类*/
public class EngineUtils {
/**
* 分享应用
*/
public static void shareApplication(Context context,AppInfo appInfo) {
Intent intent = new Intent("android.intent.action.SEND");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT,
"推荐您使用一款软件,名称叫:" + appInfo.appName
+ "下载路径:https://play.google.com/store/apps/details?id="
+ appInfo.packageName);
context.startActivity(intent);
}
/**
* 开启应用程序
*/
public static void startApplication(Context context,AppInfo appInfo) {
// 打开这个应用程序的入口activity。
PackageManager pm = context.getPackageManager();
Intent intent = pm.getLaunchIntentForPackage(appInfo.packageName);
if (intent != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, "该应用没有启动界面", 0).show();
}
}
/**
* 开启应用设置页面
* @param context
* @param appInfo
*/
public static void SettingAppDetail(Context context,AppInfo appInfo) {
Intent intent = new Intent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory(Intent.CATEGORY_DEFAULT);
// dat=package:com.itheima.mobileguard
intent.setData(Uri.parse("package:" + appInfo.packageName));
context.startActivity(intent);
}
/**卸载应用*/
public static void uninstallApplication(Context context,AppInfo appInfo) {
if (appInfo.isUserApp) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse("package:" + appInfo.packageName));
context.startActivity(intent);
}else{
//系统应用 ,root权限 利用linux命令删除文件。
if(!RootTools.isRootAvailable()){
Toast.makeText(context, "卸载系统应用,必须要root权限", 0).show();
return ;
}
try {
if(!RootTools.isAccessGiven()){
Toast.makeText(context, "请授权黑马小护卫root权限", 0).show();
return ;
}
RootTools.sendShell("mount -o remount ,rw /system", 3000);
RootTools.sendShell("rm -r "+appInfo.apkPath, 30000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
RootTools需要下载jar包
然后我们来配置adapter
package com.yangmiaoqing.example.myassitant;
import java.util.List;
import android.R.anim;
import android.content.Context;
import android.text.format.Formatter;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class AppManagerAdapter extends BaseAdapter {
private List<AppInfo> UserAppInfos;
private List<AppInfo> SystemAppInfos;
private Context context;
public AppManagerAdapter(List<AppInfo> userAppInfos,
List<AppInfo> systemAppInfos, Context context) {
super();
UserAppInfos = userAppInfos;
SystemAppInfos = systemAppInfos;
this.context = context;
}
@Override
public int getCount() {
// 因为有两个条目需要用于显示用户进程,系统进程因此需要加2
return UserAppInfos.size() + SystemAppInfos.size() + 2;
}
@Override
public Object getItem(int position) {
if (position == 0) {
// 第0个位置显示的应该是 用户程序的个数的标签。
return null;
} else if (position == (UserAppInfos.size() + 1)) {
return null;
}
AppInfo appInfo;
if (position < (UserAppInfos.size() + 1)) {
// 用户程序
appInfo = UserAppInfos.get(position - 1);// 多了一个textview的标签 ,
// 位置需要-1
} else {
// 系统程序
int location = position - UserAppInfos.size() - 2;
appInfo = SystemAppInfos.get(location);
}
return appInfo;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 如果 position为0,则为TextView
if (position == 0) {
TextView tv = getTextView();
tv.setText("用户程序:" + UserAppInfos.size() + "个");
return tv;
// 系统应用
} else if (position == (UserAppInfos.size() + 1)) {
TextView tv = getTextView();
tv.setText("系统程序:" + SystemAppInfos.size() + "个");
return tv;
}
// 获取到当前App的对象
AppInfo appInfo;
if (position < (UserAppInfos.size() + 1)) {
// position 0 为textView
appInfo = UserAppInfos.get(position - 1);
} else {
// 系统应用
appInfo = SystemAppInfos.get(position - UserAppInfos.size() - 2);
}
ViewHolder viewHolder = null;
if (convertView != null & convertView instanceof LinearLayout) {
viewHolder = (ViewHolder) convertView.getTag();
} else {
viewHolder = new ViewHolder();
convertView = View.inflate(context, R.layout.item_appmanager_list,
null);
viewHolder.mAppIconImgv = (ImageView) convertView
.findViewById(R.id.imgv_appicon);
viewHolder.mAppLocationTV = (TextView) convertView
.findViewById(R.id.tv_appisroom);
viewHolder.mAppSizeTV = (TextView) convertView
.findViewById(R.id.tv_appsize);
viewHolder.mAppNameTV = (TextView) convertView
.findViewById(R.id.tv_appname);
viewHolder.mLuanchAppTV = (TextView) convertView
.findViewById(R.id.tv_launch_app);
viewHolder.mSettingAppTV = (TextView) convertView
.findViewById(R.id.tv_setting_app);
viewHolder.mShareAppTV = (TextView) convertView
.findViewById(R.id.tv_share_app);
viewHolder.mUninstallTV = (TextView) convertView
.findViewById(R.id.tv_uninstall_app);
viewHolder.mAppOptionLL = (LinearLayout) convertView
.findViewById(R.id.ll_option_app);
convertView.setTag(viewHolder);
}
if (appInfo != null) {
viewHolder.mAppLocationTV.setText(appInfo
.getAppLocation(appInfo.isInRoom));
viewHolder.mAppIconImgv.setImageDrawable(appInfo.icon);
viewHolder.mAppSizeTV.setText(Formatter.formatFileSize(context,
appInfo.appSize));
viewHolder.mAppNameTV.setText(appInfo.appName);
if (appInfo.isSelected) {
viewHolder.mAppOptionLL.setVisibility(View.VISIBLE);
} else {
viewHolder.mAppOptionLL.setVisibility(View.GONE);
}
}
MyClickListener listener = new MyClickListener(appInfo);
viewHolder.mLuanchAppTV.setOnClickListener(listener);
viewHolder.mSettingAppTV.setOnClickListener(listener);
viewHolder.mShareAppTV.setOnClickListener(listener);
viewHolder.mUninstallTV.setOnClickListener(listener);
return convertView;
}
/***
* 创建一个TextView
* @return
*/
private TextView getTextView() {
TextView tv = new TextView(context);
tv.setBackgroundColor(context.getResources()
.getColor(R.color.graye5));
tv.setPadding(DensityUtil.dip2px(context, 5),
DensityUtil.dip2px(context, 5),
DensityUtil.dip2px(context, 5),
DensityUtil.dip2px(context, 5));
tv.setTextColor(context.getResources().getColor(R.color.black));
return tv;
}
static class ViewHolder {
/** 启动App */
TextView mLuanchAppTV;
/** 卸载App */
TextView mUninstallTV;
/** 分享App */
TextView mShareAppTV;
/** 设置App */
TextView mSettingAppTV;
/** app 图标 */
ImageView mAppIconImgv;
/** app位置 */
TextView mAppLocationTV;
/** app大小 */
TextView mAppSizeTV;
/** app名称 */
TextView mAppNameTV;
/** 操作App的线性布局 */
LinearLayout mAppOptionLL;
}
class MyClickListener implements OnClickListener {
private AppInfo appInfo;
public MyClickListener(AppInfo appInfo) {
super();
this.appInfo = appInfo;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_launch_app:
// 启动应用
EngineUtils.startApplication(context, appInfo);
break;
case R.id.tv_share_app:
// 分享应用
EngineUtils.shareApplication(context, appInfo);
break;
case R.id.tv_setting_app:
// 设置应用
EngineUtils.SettingAppDetail(context, appInfo);
break;
case R.id.tv_uninstall_app:
// 卸载应用,需要注册广播接收者
if(appInfo.packageName.equals(context.getPackageName())){
Toast.makeText(context, "您没有权限卸载此应用!", 0).show();
return;
}
EngineUtils.uninstallApplication(context, appInfo);
break;
}
}
}
}
我们的adapter继承自BaseAdapter,主要是重写getView方法,用的是ViewHold来填充item
最后我们来接软件管家的Activity
package com.yangmiaoqing.example.myassitant;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.format.Formatter;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class AppManagerActivity extends Activity implements OnClickListener{
/**手机剩余内存TextView*/
private TextView mPhoneMemoryTV;
/**展示SD卡剩余内存TextView*/
private TextView mSDMemoryTV;
private ListView mListView;
private List<AppInfo> appInfos;
private List<AppInfo> userAppInfos = new ArrayList<AppInfo>();
private List<AppInfo> systemAppInfos = new ArrayList<AppInfo>();
private AppManagerAdapter adapter;
/**接收应用程序卸载成功的广播*/
private UninstallRececiver receciver;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 10:
if(adapter == null){
adapter = new AppManagerAdapter(userAppInfos, systemAppInfos, AppManagerActivity.this);
}
mListView.setAdapter(adapter);
adapter.notifyDataSetChanged();
break;
case 15:
adapter.notifyDataSetChanged();
break;
}
};
};
private TextView mAppNumTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_app_manager);
//注册广播
receciver = new UninstallRececiver();
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
registerReceiver(receciver, intentFilter);
initView();
}
/**初始化控件*/
private void initView() {
findViewById(R.id.rl_titlebar).setBackgroundColor(
getResources().getColor(R.color.bright_yellow));
ImageView mLeftImgv = (ImageView) findViewById(R.id.imgv_leftbtn);
((TextView) findViewById(R.id.tv_title)).setText("软件管家");
mLeftImgv.setOnClickListener(this);
mLeftImgv.setImageResource(R.drawable.back);
mPhoneMemoryTV = (TextView) findViewById(R.id.tv_phonememory_appmanager);
mSDMemoryTV = (TextView) findViewById(R.id.tv_sdmemory_appmanager);
mAppNumTV = (TextView) findViewById(R.id.tv_appnumber);
mListView = (ListView) findViewById(R.id.lv_appmanager);
//拿到手机剩余内存和SD卡剩余内存
getMemoryFromPhone();
initData();
initListener();
}
private void initListener() {
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
if (adapter != null) {
new Thread(){
public void run() {
AppInfo mappInfo = (AppInfo) adapter.getItem(position);
//记住当前条目的状态
boolean flag = mappInfo.isSelected;
//先将集合中所有条目的AppInfo变为未选中状态
for(AppInfo appInfo :userAppInfos){
appInfo.isSelected = false;
}
for(AppInfo appInfo : systemAppInfos){
appInfo.isSelected = false;
}
if(mappInfo != null){
//如果已经选中,则变为未选中
if(flag){
mappInfo.isSelected = false;
}else{
mappInfo.isSelected = true;
}
mHandler.sendEmptyMessage(15);
}
};
}.start();
}
}
});
mListView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem >= userAppInfos.size()+1){
mAppNumTV.setText("系统程序:"+systemAppInfos.size()+"个");
}else{
mAppNumTV.setText("用户程序:"+userAppInfos.size()+"个");
}
}
});
}
private void initData() {
appInfos = new ArrayList<AppInfo>();
new Thread(){
public void run() {
appInfos.clear();
userAppInfos.clear();
systemAppInfos.clear();
appInfos.addAll(AppInfoParser.getAppInfos(AppManagerActivity.this));
for( AppInfo appInfo : appInfos){
//如果是用户App
if(appInfo.isUserApp){
userAppInfos.add(appInfo);
}else{
systemAppInfos.add(appInfo);
}
}
mHandler.sendEmptyMessage(10);
};
}.start();
}
/**拿到手机和SD卡剩余内存*/
private void getMemoryFromPhone() {
long avail_sd = Environment.getExternalStorageDirectory()
.getFreeSpace();
long avail_rom = Environment.getDataDirectory().getFreeSpace();
//格式化内存
String str_avail_sd = Formatter.formatFileSize(this, avail_sd);
String str_avail_rom = Formatter.formatFileSize(this, avail_rom);
mPhoneMemoryTV.setText("剩余手机内存:" + str_avail_rom);
mSDMemoryTV.setText("剩余SD卡内存:" + str_avail_sd);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imgv_leftbtn:
finish();
break;
}
}
/***
* 接收应用程序卸载的广播
* @author admin
*/
class UninstallRececiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// 收到广播了
initData();
}
}
@Override
protected void onDestroy() {
unregisterReceiver(receciver);
receciver = null;
super.onDestroy();
}
}
在appManageActivity中主要是处理改变Ui事件。在这里,ui改变主要是这么几种情况,第一种是item被选中,第二种是卸载了应用需要重新初始化数据。我们知道,如果要在非主线程中改变ui,要用handle。在handleMessage中有两种情况,第一种就是初始化数据需要全部重新加载;第二种是item的状态改变。在这里需要注册receiver来监测卸载成功的广播。notifyDataSetChanged方法通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容。
在initData中是初始化数据即userAppInfos和systemAppInfos,initlistener中改变item的选中状态。另外,提一下,卸载,设置等的动作以及item被选中后操作选项的显示都是在adapter中完成的