好啦,我们昨天就已经把用户里面所有的应用都可以读取出来了,所以,今天我们就把那些逻辑写一下,我们今天主要写的就是,点击那些应用的条目时,会弹出一个PopupWindow,上面有三个菜单,一个是运行,一个是卸载,和个是分享,今天我们就把PopupWindow和运行的逻辑写一下,先来看一下效果
上面那些弹出来的窗体,其实就是Android里面的PopupWindow这样一个组件来的,现在我们就来熟悉一下它是怎么用的。
要做成这样一个窗体,肯定就有一个布局文件啦,所以我们就先写一下布局文件
popup_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll_app_popup" android:layout_width="230dip" android:layout_height="70dip" android:background="@drawable/local_popup_bg" android:gravity="center_vertical" android:orientation="horizontal" > <LinearLayout android:id="@+id/ll_app_uninstall" android:layout_width="70dip" android:layout_height="70dip" android:layout_marginLeft="8dip" android:gravity="center_horizontal|center_vertical" android:orientation="vertical" > <ImageView android:layout_width="35dip" android:layout_height="35dip" android:scaleType="fitXY" android:src="@drawable/img1" android:contentDescription="@string/hello_world" /> <TextView android:layout_width="35dip" android:layout_height="20dip" android:text="@string/app_manager_delete" /> </LinearLayout> <View android:layout_width="1dip" android:layout_height="50dip" android:background="#ff00ff66" /> <LinearLayout android:id="@+id/ll_app_start" android:layout_width="70dip" android:layout_height="70dip" android:gravity="center_horizontal|center_vertical" android:orientation="vertical" > <ImageView android:layout_width="35dip" android:layout_height="35dip" android:scaleType="fitXY" android:src="@drawable/img2" android:contentDescription="@string/hello_world" /> <TextView android:layout_width="35dip" android:layout_height="20dip" android:text="@string/app_manager_run" /> </LinearLayout> <View android:layout_width="1dip" android:layout_height="50dip" android:background="#ff00ff66" /> <LinearLayout android:id="@+id/ll_app_share" android:layout_width="70dip" android:layout_height="70dip" android:gravity="center_horizontal|center_vertical" android:orientation="vertical" > <ImageView android:layout_width="35dip" android:layout_height="35dip" android:scaleType="fitXY" android:src="@drawable/img3" android:contentDescription="@string/hello_world" /> <TextView android:layout_width="35dip" android:layout_height="20dip" android:text="@string/app_manager_share"/> </LinearLayout> </LinearLayout>
只要加入下面的代码,我们就可以初始化好这个PopupWindow的啦
//用来存放当前的item的坐标值,第一个是x的坐标,第二个是y的坐标 int[] location = new int[2]; //把当前的item的坐标值放到int数组里面 view.getLocationInWindow(location); View popupView = View.inflate(AppManagerActivity.this, R.layout.popup_item, null); LinearLayout ll_app_uninstall = (LinearLayout) popupView.findViewById(R.id.ll_app_uninstall); LinearLayout ll_app_run = (LinearLayout) popupView.findViewById(R.id.ll_app_start); LinearLayout ll_app_share = (LinearLayout) popupView.findViewById(R.id.ll_app_share); ll_app_uninstall.setOnClickListener(AppManagerActivity.this); ll_app_run.setOnClickListener(AppManagerActivity.this); ll_app_share.setOnClickListener(AppManagerActivity.this); //拿到当时点击的条目,并设置到view里面 AppInfo info = (AppInfo) lv_app_manager.getItemAtPosition(position); ll_app_uninstall.setTag(info); ll_app_run.setTag(info); ll_app_share.setTag(info); //添加动画 LinearLayout ll_app_popup = (LinearLayout) popupView.findViewById(R.id.ll_app_popup); ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f); scaleAnimation.setDuration(300); //new 一个PopupWindow出来 popupWindow = new PopupWindow(popupView, 230, 70); //一定要给PopupWindow设置一个背景图片,不然的话,会有很多未知的问题的 //如没办法给它加上动画,还有显示会有问题等, //如果我们没有要设置的图片,那么我们就给它加上了一个透明的背景图片 Drawable drawable = new ColorDrawable(Color.TRANSPARENT); popupWindow.setBackgroundDrawable(drawable); int x = location[0] + 60; int y = location[1]; //把PopupWindow显示出来 popupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, x, y); //开启动画 ll_app_popup.startAnimation(scaleAnimation);
好啦,到这里为止,我们就把PopupWindow给做好的啦,也就是说我们的整个界面就写好的啦,那么我们现在就要来写一下逻辑啦
我们今天先把运行的逻辑写一下
那么怎样运行点击的条目呢,这就是核心了,我们上一节课已经把我们所以应用的包名都读取出来的了,那么我们就可以通过我们点击的条目的包名来拿到一个PackageInfo的对象,然后再通过PackageInfo对象,扫描它所对应的AndroidMainfest里面的节点,然后拿到具有启动意义的Activity,然后,我们就可以通过startActivity来启动我们想要启动的Activity啦,
好,废话不多说,直接上代码
try { //拿到这个包对应的PackageInfo对象,这里我们指定了两个flag, //一个就是之前讲过的,所有的安装过的应用程序都找出来,包括卸载了但没清除数据的 //一个就是指定它去扫描这个应用的AndroidMainfest文件时候的activity节点, //这样我们才能拿到具有启动意义的ActivityInfo,如果不指定,是无法扫描出来的 PackageInfo packageInfo = getPackageManager().getPackageInfo(item.getPackageName(), PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES); //扫描出来的所以activity节点的信息 ActivityInfo[] activityInfos = packageInfo.activities; //有些应用是无法启动的,所以我们就要判断一下 if(activityInfos != null && activityInfos.length > 0) { //在扫描出来的应用里面,第一个是具有启动意义的 ActivityInfo startActivity = activityInfos[0]; //设置好Intent,启动activity Intent intent = new Intent(); intent.setClassName(item.getPackageName(), startActivity.name); startActivity(intent); } else { Toast.makeText(AppManagerActivity.this, "这个应用程序无法启动", Toast.LENGTH_SHORT).show(); } } catch (NameNotFoundException e) { e.printStackTrace(); }
第一个就是之前讲过的,所有的安装过的应用程序都找出来,包括卸载了但没清除数据的
第二个就是指定它去扫描这个应用的AndroidMainfest文件时候的activity节点,
好啦,到这里为止,我们运行的核心代码就写完的啦,由于那个卸载有点麻烦的,卸载完之后,还要更新列表,以保持一致,所以我们今天先不讲,我们明天就把卸载和分享一些讲完,还有把用户应用与所有应用做一个切换。
下面把我们完成的activity类粘出来
com.xiaobin.security.ui.AppManagerActivity
package com.xiaobin.security.ui; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.ScaleAnimation; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; import com.xiaobin.security.R; import com.xiaobin.security.domain.AppInfo; import com.xiaobin.security.engine.AppInfoProvider; public class AppManagerActivity extends Activity implements OnClickListener { private static final int GET_ALL_APP_FINISH = 1; private ListView lv_app_manager; private LinearLayout ll_app_manager_progress; private AppInfoProvider provider; private AppManagerAdapter adapter; private PopupWindow popupWindow; private List<AppInfo> list; @SuppressLint("HandlerLeak") private Handler handler = new Handler() { public void handleMessage(Message msg) { switch(msg.what) { case GET_ALL_APP_FINISH : //进度条设置为不可见 ll_app_manager_progress.setVisibility(View.GONE); adapter = new AppManagerAdapter(); lv_app_manager.setAdapter(adapter); break; default : break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.app_manager); lv_app_manager = (ListView) findViewById(R.id.lv_app_manager); ll_app_manager_progress = (LinearLayout) findViewById(R.id.ll_app_manager_progress); ll_app_manager_progress.setVisibility(View.VISIBLE); //因为搜索手机里面的应用程序有可能是非常耗时的,所以我们开启一个新的线程去进行搜索 //当搜索完成之后,就把一个成功的消息发送给Handler,然后handler把搜索到的数据设置进入listview里面 new Thread() { public void run() { provider = new AppInfoProvider(AppManagerActivity.this); list = provider.getAllApps(); Message msg = new Message(); msg.what = GET_ALL_APP_FINISH; handler.sendMessage(msg); }; }.start(); lv_app_manager.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { dismissPopupWindow(); //用来存放当前的item的坐标值,第一个是x的坐标,第二个是y的坐标 int[] location = new int[2]; //把当前的item的坐标值放到int数组里面 view.getLocationInWindow(location); View popupView = View.inflate(AppManagerActivity.this, R.layout.popup_item, null); LinearLayout ll_app_uninstall = (LinearLayout) popupView.findViewById(R.id.ll_app_uninstall); LinearLayout ll_app_run = (LinearLayout) popupView.findViewById(R.id.ll_app_start); LinearLayout ll_app_share = (LinearLayout) popupView.findViewById(R.id.ll_app_share); ll_app_uninstall.setOnClickListener(AppManagerActivity.this); ll_app_run.setOnClickListener(AppManagerActivity.this); ll_app_share.setOnClickListener(AppManagerActivity.this); //拿到当时点击的条目,并设置到view里面 AppInfo info = (AppInfo) lv_app_manager.getItemAtPosition(position); ll_app_uninstall.setTag(info); ll_app_run.setTag(info); ll_app_share.setTag(info); //添加动画 LinearLayout ll_app_popup = (LinearLayout) popupView.findViewById(R.id.ll_app_popup); ScaleAnimation scaleAnimation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f); scaleAnimation.setDuration(300); //new 一个PopupWindow出来 popupWindow = new PopupWindow(popupView, 230, 70); //一定要给PopupWindow设置一个背景图片,不然的话,会有很多未知的问题的 //如没办法给它加上动画,还有显示会有问题等, //如果我们没有要设置的图片,那么我们就给它加上了一个透明的背景图片 Drawable drawable = new ColorDrawable(Color.TRANSPARENT); popupWindow.setBackgroundDrawable(drawable); int x = location[0] + 60; int y = location[1]; //把PopupWindow显示出来 popupWindow.showAtLocation(view, Gravity.LEFT | Gravity.TOP, x, y); //开启动画 ll_app_popup.startAnimation(scaleAnimation); } }); //当listview滚动的时候调用的方法 lv_app_manager.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { dismissPopupWindow(); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { dismissPopupWindow(); } }); } //判断PopupWindow是不是存在,存在就把它dismiss掉 private void dismissPopupWindow() { if(popupWindow != null) { popupWindow.dismiss(); popupWindow = null; } } @Override public void onClick(View v) { AppInfo item = (AppInfo) v.getTag(); switch(v.getId()) { case R.id.ll_app_uninstall : if(item.isSystemApp()) { Toast.makeText(AppManagerActivity.this, "不能卸载系统的应用程序", Toast.LENGTH_SHORT).show(); } else { } break; case R.id.ll_app_start : try { //拿到这个包对应的PackageInfo对象,这里我们指定了两个flag, //一个就是之前讲过的,所有的安装过的应用程序都找出来,包括卸载了但没清除数据的 //一个就是指定它去扫描这个应用的AndroidMainfest文件时候的activity节点, //这样我们才能拿到具有启动意义的ActivityInfo,如果不指定,是无法扫描出来的 PackageInfo packageInfo = getPackageManager().getPackageInfo(item.getPackageName(), PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES); //扫描出来的所以activity节点的信息 ActivityInfo[] activityInfos = packageInfo.activities; //有些应用是无法启动的,所以我们就要判断一下 if(activityInfos != null && activityInfos.length > 0) { //在扫描出来的应用里面,第一个是具有启动意义的 ActivityInfo startActivity = activityInfos[0]; //设置好Intent,启动activity Intent intent = new Intent(); intent.setClassName(item.getPackageName(), startActivity.name); startActivity(intent); } else { Toast.makeText(AppManagerActivity.this, "这个应用程序无法启动", Toast.LENGTH_SHORT).show(); } } catch (NameNotFoundException e) { e.printStackTrace(); } break; case R.id.ll_app_share : break; default : break; } dismissPopupWindow(); } //====================================================================== private class AppManagerAdapter extends BaseAdapter { @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { AppInfo info = list.get(position); if(convertView == null) { View view = View.inflate(AppManagerActivity.this, R.layout.app_manager_item, null); AppManagerViews views = new AppManagerViews(); views.iv_app_icon = (ImageView) view.findViewById(R.id.iv_app_manager_icon); views.tv_app_name = (TextView) view.findViewById(R.id.tv_app_manager_name); views.iv_app_icon.setImageDrawable(info.getIcon()); views.tv_app_name.setText(info.getAppName()); view.setTag(views); return view; } else { AppManagerViews views = (AppManagerViews) convertView.getTag(); views.iv_app_icon.setImageDrawable(info.getIcon()); views.tv_app_name.setText(info.getAppName()); return convertView; } } } //用来优化listview的类 private class AppManagerViews { ImageView iv_app_icon; TextView tv_app_name; } }
好啦,今天就讲到这里了,今天的代码量比较少,但是很重要,都是新东西,大家可以认真看看,明天我们再讲卸载和分享的功能
今天源码下载