HardBirch

说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加

时间:11-11-23 栏目:安卓学习笔记 作者:张飞不张,文采横飞 评论:5 点击: 2,433 次

上篇中,讲到了第一个功能中需要获取应用程序的信息,然后添加到桌面。这里,先记录下如何获取Android中的应用程序信息。

一、调用系统快捷方式列表

         Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
        pickIntent.putExtra(Intent.EXTRA_INTENT,
                new Intent(Intent.ACTION_CREATE_SHORTCUT));
        pickIntent.putExtra(Intent.EXTRA_TITLE,
                res.getString(R.string.title_select_app));

        pickIntent.putExtras(bundle);

        startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);

 

这个获取到的就是所有可以创建的快捷方式,但是我们需要在这个列表中加入其他项怎么办呢?因为我们知道,我需要在这个列表中加入“应用程序”,这一项,这样当我们点击应用程序的时候,就可以显示应用程序列表。这个时候,我们只需要传入额外的信息就可以了,如下:

 

	Resources res = getResources();
		/**
		 * 用一个Bundle对象,传递两个list信息
		 * 一个list中存放需要附加到快捷列表中的项的文字
		 * 一个list中存放每一个对应的图标信息
		 */
        Bundle bundle = new Bundle();

        ArrayList<String> shortcutNames = new ArrayList<String>();
        shortcutNames.add(res.getString(R.string.group_application));
        shortcutNames.add("其他");
        //显示在List第一个的应用快捷方式的名字
        bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);

        //显示图标
        ArrayList<ShortcutIconResource> shortcutIcons =
                new ArrayList<ShortcutIconResource>();
        shortcutIcons.add(ShortcutIconResource.fromContext(UorderLauncher.this,
                R.drawable.icon));
        shortcutIcons.add(ShortcutIconResource.fromContext(UorderLauncher.this,
                R.drawable.icon));
        bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);

        Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
        pickIntent.putExtra(Intent.EXTRA_INTENT,
                new Intent(Intent.ACTION_CREATE_SHORTCUT));
        pickIntent.putExtra(Intent.EXTRA_TITLE,
                res.getString(R.string.title_select_app));
        //将附加信息加入到pickIntent
        pickIntent.putExtras(bundle);

        startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);

二、调用应用程序列表

当我们点击我们附加的项“应用程序”时,我们希望弹出应用程序列表,这个也可以条用系统自带列表,也可以使用自己定义的列表。

1、调用系统应用信息列表

在上面我们加上了一个附加项“应用程序”,那么我们怎么知道,当前点击的是“应用程序”这一项呢?注意上面我们启动的时候是startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);

在onActivityResult中处理该请求对应的逻辑:如果用户选择的是“应用程序”,则调用系统应用程序列表,否则,直接请求创建快捷方式

	private void addShortcut(Intent data){
		Resources res = getResources();

		final String appName = res.getString(R.string.group_application);
		final String shortcutName = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
		if(appName.equals(shortcutName)){
			//说明用户选择的是应用程序,进入应用程序列表
			Intent mainIntent = new Intent(Intent.ACTION_MAIN,null);
			mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

			Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
			pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
			startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
		}else{
			//否则,直接创建快捷方式
			startActivityForResult(data, REQUEST_CREATE_SHORTCUT);
		}
	}

这样,就实现点击“应用程序”则显示应用程序列表,否则,创建快捷方式

2、获取所有应用程序信息,实现自定义的应用程序列表

其实,对于系统中所有应用程序的信息,程序中都是可以获取到的。在桌面点击的时候用的是系统自带的应用程序列表。但是,当点击桌面下方的应用程序图标的时候,就需要显示一个GridView显示所有的应用程序信息,这里,就需要获取应用程序信息,然后放入每一个item中。这里就顺带实现一下。布局和效果略过,只记录如果获取应用程序信息。

		/**
		 * 同样,以ACTION_MAIN和CATEGORY_LAUNCHER作为过滤条件
		 * 查询所有符合的应用信息(ResolveInfo)
		 * ResolveInfo中就包含了我们需要的主要信息。
		 * 当然还有其他的方式获取应用信息,如PackageInfo,关于这些信息,可以参看
		 * http://android.tgbus.com/Android/tutorial/201108/364210.shtml
		 */

		final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		final PackageManager pManager = this.getPackageManager();
		/**
		 * queryIntentActivities通过解析所有应用程序中含有如下Intent-filter的App
		 * <intent-filter>
		 * 		<action android:name="android.intent.action.MAIN" />
		 * 		<category android:name="android.intent.category.LAUNCHER" />
		 * </intent-filter>
		 */
		final List<ResolveInfo> infoList = pManager.queryIntentActivities(mainIntent, 0);
		if(infoList != null){
			ArrayList<AppInfo> appList = new ArrayList<AppInfo>();
			for(ResolveInfo info : infoList){
				AppInfo app = makeAppInfo(pManager, info);
				appList.add(app);
			}
			return appList;
		}

		return null;

程序还包含了一个makeAppInfo(pManager, info);这个方法源码是:

	private AppInfo makeAppInfo(PackageManager pManager, ResolveInfo info) {
		//有了ComponentName,就可以保存每个应用程序的启动信息
		//下次我们可以直接启动它
		ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName,
				info.activityInfo.name);
		//这个是自己定义的一个用来封装我们需要的应用程序的信息
		AppInfo app = new AppInfo();

		//获取应用的名称
		CharSequence appName = info.loadLabel(pManager);
		if(appName == null){
			//如果没有成功获取到,则用其主Activity的名字作为应用名称
			appName = info.activityInfo.name;
		}
		app.name = appName.toString();

		//获取应用程序的图标
		Drawable draw = info.activityInfo.loadIcon(pManager);

		//应用程序图片可以大小不一,这里需要将他们的size限定在一定的大小
		app.icon = BitmapUtils.createIconThumbnail(draw, getApplicationContext());

		//将启动信息保存在AppInfo中,在我们的应用中启动另一个应用程序,使用FLAG_ACTIVITY_NEW_TASK
		app.setActivity(component, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

		return app;
	}

 

这样就得到了所有的应用程序信息。系统Launcher在其GridView中列出的所有应用就是这么获取的。

 

三、获取应用程序信息的其他方式:

下面这个获取到的应用信息,你会发现比上面的方法多了很多,因为其获得的是系统中所有的安装包信息

		List<PackageInfo> packageList = this.getPackageManager().getInstalledPackages(0);
		appList = new ArrayList<AppInfo>();
		for(PackageInfo info : packageList){
			CharSequence appName = info.applicationInfo.loadLabel(getPackageManager());
			if(TextUtils.isEmpty(appName)){
				appName = info.packageName;
			}
			//加上下面这个if条件就把系统自带的应用给过滤掉了,获取到的仅仅是我们自己安装的
			if((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)<=0){
				ComponentName comp = getComponentName(info.packageName);

				AppInfo appInfo = new AppInfo();
				appInfo.icon = info.applicationInfo.loadIcon(getPackageManager());
				appInfo.name = appName.toString();
				appInfo.setActivity(comp, Intent.FLAG_ACTIVITY_NEW_TASK|
						Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

				appList.add(appInfo);
			}
		}

程序中调用了getComponentName,其源码是:

	private ComponentName getComponentName(String packageName) {
		Intent intent = new Intent(Intent.ACTION_MAIN, null);
		intent.addCategory(Intent.CATEGORY_LAUNCHER);
		intent.setPackage(packageName);

		List<ResolveInfo> infoList = getPackageManager().queryIntentActivities(intent, 0);
		if(infoList != null && infoList.size()>0){
			ResolveInfo info = infoList.get(0);
			if(info != null){
				String pkgName = info.activityInfo.packageName;
				String clsName = info.activityInfo.name;
				return new ComponentName(pkgName, clsName);
			}
		}
		return null;
	}

 

到处,也就很清楚Launcher中长按桌面,应用程序是如何选择和在GridView中的应用程序信息是如何获取到的了。

下一篇,将继续介绍CellLayout自定义控件的实现原理!

说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加:目前有5 条留言

  1. 我想要Launcher应用里讲到的代码,能给我吗,我将感激不尽

    2012-03-12 16:43 [回复]
  2. 4楼
    nicnac:

    好文章,祝楼主全家福泰安康~

    2012-03-13 10:45 [回复]
  3. 地板
    caini_gu:

    感激楼主的奉献!最近也在研究Launcher,能发下Launcher的所有代码吗?邮箱:1223964666@qq.com.感激不尽!

    2012-03-30 18:11 [回复]
  4. 板凳
    zhongsw168:

    感谢楼主,最近研究launcher,能发份源码学习一下吗?879516804@qq.com

    2012-05-04 08:39 [回复]
  5. 沙发
    CherryShmilly:

    楼主,您好!能给下launch的代码吗?谢谢了!728043829@qq.com

    2012-08-08 16:34 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐