Android项目实战--手机卫士21--运行应用以及美化PopupWindow

好啦,我们昨天就已经把用户里面所有的应用都可以读取出来了,所以,今天我们就把那些逻辑写一下,我们今天主要写的就是,点击那些应用的条目时,会弹出一个PopupWindow,上面有三个菜单,一个是运行,一个是卸载,和个是分享,今天我们就把PopupWindow和运行的逻辑写一下,先来看一下效果

Android项目实战--手机卫士21--运行应用以及美化PopupWindow_第1张图片

上面那些弹出来的窗体,其实就是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的布局文件之后,我们就要把它展示在Activity上面啦,其实我们可以把PopupWindow当成一个Activity一样来看待,它的初始化也很简单的

只要加入下面的代码,我们就可以初始化好这个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加背景的问题,PopupWindow一定要给它加上背景,不然会出现一些莫名奇妙的问题的。


好啦,到这里为止,我们就把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();
				}

大家可以看到,我们主要是指定了两个flag,PackageManager.GET_UNINSTALLED_PACKAGES和PackageManager.GET_ACTIVITIES,它们的作用就是

第一个就是之前讲过的,所有的安装过的应用程序都找出来,包括卸载了但没清除数据的
第二个就是指定它去扫描这个应用的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;
	}

}


好啦,今天就讲到这里了,今天的代码量比较少,但是很重要,都是新东西,大家可以认真看看,明天我们再讲卸载和分享的功能


今天源码下载




你可能感兴趣的:(Android开发,PopupWindow,项目实战,运行应用,手机卫士)