android自定义桌面(launcher)

    有时候需要开发一个自己的桌面程序,特别是做产品开发的开发人员,android自定义桌面其实就是一个launcher,然后在相应的activity中把系统中的所有APK加载进来,显示相应的icon图标。

开发自定义桌面需要用到以下几个类

1,ComponentName:组件名称,通常用来打开其他应用程序中的Activity或服务。,

2,PackageInfo:包含了一些信息的基类,它的直接子类有:ApplicationInfo、ComponentInfo、InstrumentationInfo、PermissionGroupInfo、PermissionInfo。它的间接子类有:ActivityInfo、ProviderInfo、ServiceInfo。这个类包含的信息对于所有包中项目是平等的。这些Package items是被Package manager所持有的,这个类提供了属性的非常普通的基本设置。通过 PackageInfo 获取具体信息方法:

    包名获取方法:packageInfo.packageName
    icon获取获取方法:packageManager.getApplicationIcon(applicationInfo)
    应用名称获取方法:packageManager.getApplicationLabel(applicationInfo)
    使用权限获取方法:packageManager.getPackageInfo(packageName,PackageManager.GET_PERMISSIONS).requestedPermissions

3,ResolveInfo:这个类是通过解析一个与IntentFilter相对应的intent得到的信息。它部分地对应于从AndroidManifest.xml的<intent>标签收集到的信息。通过 ResolveInfo 获取具体信息方法:

    包名获取方法:resolve.activityInfo.packageName
    icon获取获取方法:resolve.loadIcon(packageManager)
    应用名称获取方法:resolve.loadLabel(packageManager).toString()

4,PackageManger : 获得已安装的应用程序信息,常用方法: 

 
  public abstract PackageManager getPackageManager()  //功能:获得一个PackageManger对象  
    public abstract Drawable getApplicationIcon(String packageName) //参数: packageName 包名,功能:返回给定包名的图标,否则返回null
    public abstract ApplicationInfo   getApplicationInfo(String packageName, int flags) //参数:packagename 包名 flags 该ApplicationInfo是此flags标记,通常可以直接赋予常数0即可,功能:返回该ApplicationInfo对象
    public abstract List<ApplicationInfo>  getInstalledApplications(int flags) //参数:flag为一般为GET_UNINSTALLED_PACKAGES,那么此时会返回所有ApplicationInfo。我们可以对ApplicationInfo的flags过滤,得到我们需要的。功能:返回给定条件的所有PackageInfo

    public abstract List<PackageInfo>  getInstalledPackages(int flags) //参数如上,功能:返回给定条件的所有PackageInfo

首先,需要在manifest中加入

<category android:name=”android.intent.category.HOME” />
<category android:name=”android.intent.category.DEFAULT” />

系统启动后,ActivityManagerService会寻找系统中的”android.intent.category.HOME”,然后进行加载,如果”android.intent.category.HOME”有多个,则会让其进行选择,完整的如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.launcher"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:screenOrientation="landscape"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
        <activity
            android:name="com.test.Launcher"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
  				<category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

 />
    </application>

</manifest>

需定义一个xml来定义桌面的布局:

<com.test.launcher.Test
        android:id="@+id/apps_customize_pane_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        launcher:cellCountX="4"
        launcher:cellCountY="2"
        launcher:maxAppCellCountX="@integer/apps_customize_maxCellCountX"
        launcher:maxAppCellCountY="@integer/apps_customize_maxCellCountY"
        launcher:pageLayoutWidthGap="@dimen/apps_customize_pageLayoutWidthGap"
        launcher:pageLayoutHeightGap="@dimen/apps_customize_pageLayoutHeightGap"
        launcher:pageLayoutPaddingTop="@dimen/apps_customize_pageLayoutPaddingTop"
        launcher:pageLayoutPaddingBottom="@dimen/apps_customize_pageLayoutPaddingBottom"
        launcher:pageLayoutPaddingLeft="@dimen/apps_customize_pageLayoutPaddingLeft"
        launcher:pageLayoutPaddingRight="@dimen/apps_customize_pageLayoutPaddingRight"
        launcher:widgetCellWidthGap="@dimen/apps_customize_widget_cell_width_gap"
        launcher:widgetCellHeightGap="@dimen/apps_customize_widget_cell_height_gap"
        launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
        launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
        launcher:clingFocusedX="@integer/apps_customize_cling_focused_x"
        launcher:clingFocusedY="@integer/apps_customize_cling_focused_y"
        launcher:maxGap="@dimen/workspace_max_gap"/>

然后,实现功能函数:

private ArrayList<ApplicationInfo> mApps;
private int mNumAppsPages;
private int mMaxAppCellCountX, mMaxAppCellCountY;
 
public void setApps(ArrayList<ApplicationInfo> list) {
    mApps = list;
    //Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
    updatePageCounts();
        
    if (testDataReady())requestLayout();
}

public void addApps(ArrayList<ApplicationInfo> list) {
    addAppsWithoutInvalidate(list);
    updatePageCounts();
    invalidatePageData();
}

public void removeApps(ArrayList<ApplicationInfo> list) {
    removeAppsWithoutInvalidate(list);
    updatePageCounts();
    invalidatePageData();
}

public void updateApps(ArrayList<ApplicationInfo> list) {
    removeAppsWithoutInvalidate(list);
    addAppsWithoutInvalidate(list);
    updatePageCounts();
    invalidatePageData();
}
private void updatePageCounts() {
    mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
}

private boolean testDataReady() {
    // We only do this test once, and we default to the Applications page, so we only really
    // have to wait for there to be apps.
    // TODO: What if one of them is validly empty   
	return !mApps.isEmpty();
}

private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
    // We add it in place, in alphabetical order
    int count = list.size();
    for (int i = 0; i < count; ++i) {
        ApplicationInfo info = list.get(i);
        int index = Collections.binarySearch(mApps, info, ApplicationInfoComparator());
        if (index < 0) {
            mApps.add(-(index + 1), info);
        }
    }
}

static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
	@Override
	public int compare(ApplicationInfo a, ApplicationInfo b) {
	    return a.arrID - b.arrID;
	}
}


private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
    // loop through all the apps and remove apps that have the same component
    int length = list.size();
    for (int i = 0; i < length; ++i) {
        ApplicationInfo info = list.get(i);
        int removeIndex = findAppByComponent(mApps, info);
        if (removeIndex > -1) {
            mApps.remove(removeIndex);
        }
    }
}

private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
    ComponentName removeComponent = item.intent.getComponent();
    int length = list.size();
    for (int i = 0; i < length; ++i) {
        ApplicationInfo info = list.get(i);
        if (info.intent.getComponent().equals(removeComponent)) {
            return i;
        }
    }
    return -1;
}

自定义ApplicationInfo类:

public class ApplicationInfo extends ItemInfo{
    private static final String TAG = "ApplicationInfo";

    /**
     * The application name.
     */
    CharSequence title;

    /**
     * The intent used to start the application.
     */
    Intent intent;

    /**
     * A bitmap version of the application icon.
     */
    Bitmap iconBitmap;

    /**
     * The time at which the app was first installed.
     */
    long firstInstallTime;

    ComponentName componentName;

    static final int DOWNLOADED_FLAG = 1;
    static final int UPDATED_SYSTEM_APP_FLAG = 2;

    int flags = 0;

    public int arrID;
    
    ApplicationInfo() {
        itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
    }

    /**
     * Must not hold the Context.
     */
    public ApplicationInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,
            HashMap<Object, CharSequence> labelCache, int arrId) {
        final String packageName = info.activityInfo.applicationInfo.packageName;

        this.componentName = new ComponentName(packageName, info.activityInfo.name);
        this.container = ItemInfo.NO_ID;
        this.setActivity(componentName,
                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

        try {
            int appFlags = pm.getApplicationInfo(packageName, 0).flags;
            if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
                flags |= DOWNLOADED_FLAG;

                if ((appFlags & android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
                    flags |= UPDATED_SYSTEM_APP_FLAG;
                }
            }
            firstInstallTime = pm.getPackageInfo(packageName, 0).firstInstallTime;
            
            arrID = arrId;
        } catch (NameNotFoundException e) {
            Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
        }

        iconCache.getTitleAndIcon(this, info, labelCache);
    }

    public ApplicationInfo(ApplicationInfo info) {
        super(info);
        componentName = info.componentName;
        title = info.title.toString();
        intent = new Intent(info.intent);
        flags = info.flags;
        firstInstallTime = info.firstInstallTime;
        arrID= info.arrID;

    }

    /**
     * Creates the application intent based on a component name and various launch flags.
     * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
     *
     * @param className the class name of the component representing the intent
     * @param launchFlags the launch flags
     */
    final void setActivity(ComponentName className, int launchFlags) {
        intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setComponent(className);
        intent.setFlags(launchFlags);
        itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
    }

    @Override
    public String toString() {
        return "ApplicationInfo(title=" + title.toString() + ")";
    }

    public static void dumpApplicationInfoList(String tag, String label,
            ArrayList<ApplicationInfo> list) {
        Log.d(tag, label + " size=" + list.size());
        for (ApplicationInfo info: list) {
            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap="
                    + info.iconBitmap + " firstInstallTime="
                    + info.firstInstallTime);
        }
    }

    public ShortcutInfo makeShortcut() {
        return new ShortcutInfo(this);
    }
}

由于水平较次,高手勿喷,仅供学习

    原文作者:大海方舟
    原文地址: https://blog.csdn.net/cjyusha/article/details/51508954
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞