Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bc89af3 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Add API for apps to declare their "category".

Upcoming platform features need to cluster apps together into broad
categories to help summarize information to users.  (For example,
when presenting battery, network, and disk usage.)

We are tightly limiting the set of categories to keep them easily
presentable to users when summarizing information.  This feature is
not designed to be a general-purpose taxonomy, nor should it be
allowed to become one.

Older apps may not have defined a category in their manifests, so
allow the installing app to define a category on their behalf.

Test: builds, boots
Bug: 33815939
Change-Id: I785b882ee7c18072ef47d56e0fc19ad72888e1b7
parent cb2c5733
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -284,6 +284,7 @@ package android {
    field public static final int anyDensity = 16843372; // 0x101026c
    field public static final int apduServiceBanner = 16843757; // 0x10103ed
    field public static final int apiKey = 16843281; // 0x1010211
    field public static final int appCategory = 16844101; // 0x1010545
    field public static final int author = 16843444; // 0x10102b4
    field public static final int authorities = 16842776; // 0x1010018
    field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -9592,7 +9593,17 @@ package android.content.pm {
    ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
    method public int describeContents();
    method public void dump(android.util.Printer, java.lang.String);
    method public static java.lang.CharSequence getCategoryTitle(android.content.Context, int);
    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
    field public static final int CATEGORY_AUDIO = 1; // 0x1
    field public static final int CATEGORY_GAME = 0; // 0x0
    field public static final int CATEGORY_IMAGE = 3; // 0x3
    field public static final int CATEGORY_MAPS = 6; // 0x6
    field public static final int CATEGORY_NEWS = 5; // 0x5
    field public static final int CATEGORY_PRODUCTIVITY = 7; // 0x7
    field public static final int CATEGORY_SOCIAL = 4; // 0x4
    field public static final int CATEGORY_UNDEFINED = -1; // 0xffffffff
    field public static final int CATEGORY_VIDEO = 2; // 0x2
    field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
    field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
    field public static final int FLAG_ALLOW_CLEAR_USER_DATA = 64; // 0x40
@@ -9606,7 +9617,7 @@ package android.content.pm {
    field public static final int FLAG_HAS_CODE = 4; // 0x4
    field public static final int FLAG_INSTALLED = 8388608; // 0x800000
    field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
    field public static final int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final deprecated int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
    field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
    field public static final int FLAG_MULTIARCH = -2147483648; // 0x80000000
@@ -9627,6 +9638,7 @@ package android.content.pm {
    field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
    field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
    field public java.lang.String backupAgentName;
    field public int category;
    field public java.lang.String className;
    field public int compatibleWidthLimitDp;
    field public java.lang.String dataDir;
@@ -10046,6 +10058,7 @@ package android.content.pm {
    method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
    method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public abstract void setApplicationCategoryHint(java.lang.String, int);
    method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
    method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
@@ -39019,6 +39032,7 @@ package android.test.mock {
    method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
    method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public void setApplicationCategoryHint(java.lang.String, int);
    method public void setApplicationEnabledSetting(java.lang.String, int, int);
    method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public void setInstallerPackageName(java.lang.String, java.lang.String);
+15 −1
Original line number Diff line number Diff line
@@ -393,6 +393,7 @@ package android {
    field public static final int anyDensity = 16843372; // 0x101026c
    field public static final int apduServiceBanner = 16843757; // 0x10103ed
    field public static final int apiKey = 16843281; // 0x1010211
    field public static final int appCategory = 16844101; // 0x1010545
    field public static final int author = 16843444; // 0x10102b4
    field public static final int authorities = 16842776; // 0x1010018
    field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -9975,7 +9976,17 @@ package android.content.pm {
    ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
    method public int describeContents();
    method public void dump(android.util.Printer, java.lang.String);
    method public static java.lang.CharSequence getCategoryTitle(android.content.Context, int);
    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
    field public static final int CATEGORY_AUDIO = 1; // 0x1
    field public static final int CATEGORY_GAME = 0; // 0x0
    field public static final int CATEGORY_IMAGE = 3; // 0x3
    field public static final int CATEGORY_MAPS = 6; // 0x6
    field public static final int CATEGORY_NEWS = 5; // 0x5
    field public static final int CATEGORY_PRODUCTIVITY = 7; // 0x7
    field public static final int CATEGORY_SOCIAL = 4; // 0x4
    field public static final int CATEGORY_UNDEFINED = -1; // 0xffffffff
    field public static final int CATEGORY_VIDEO = 2; // 0x2
    field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
    field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
    field public static final int FLAG_ALLOW_CLEAR_USER_DATA = 64; // 0x40
@@ -9989,7 +10000,7 @@ package android.content.pm {
    field public static final int FLAG_HAS_CODE = 4; // 0x4
    field public static final int FLAG_INSTALLED = 8388608; // 0x800000
    field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
    field public static final int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final deprecated int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
    field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
    field public static final int FLAG_MULTIARCH = -2147483648; // 0x80000000
@@ -10010,6 +10021,7 @@ package android.content.pm {
    field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
    field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
    field public java.lang.String backupAgentName;
    field public int category;
    field public java.lang.String className;
    field public int compatibleWidthLimitDp;
    field public java.lang.String credentialProtectedDataDir;
@@ -10475,6 +10487,7 @@ package android.content.pm {
    method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
    method public abstract void setApplicationCategoryHint(java.lang.String, int);
    method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
    method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
@@ -42241,6 +42254,7 @@ package android.test.mock {
    method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
    method public void setApplicationCategoryHint(java.lang.String, int);
    method public void setApplicationEnabledSetting(java.lang.String, int, int);
    method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public void setInstallerPackageName(java.lang.String, java.lang.String);
+15 −1
Original line number Diff line number Diff line
@@ -284,6 +284,7 @@ package android {
    field public static final int anyDensity = 16843372; // 0x101026c
    field public static final int apduServiceBanner = 16843757; // 0x10103ed
    field public static final int apiKey = 16843281; // 0x1010211
    field public static final int appCategory = 16844101; // 0x1010545
    field public static final int author = 16843444; // 0x10102b4
    field public static final int authorities = 16842776; // 0x1010018
    field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -9617,9 +9618,19 @@ package android.content.pm {
    ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
    method public int describeContents();
    method public void dump(android.util.Printer, java.lang.String);
    method public static java.lang.CharSequence getCategoryTitle(android.content.Context, int);
    method public boolean isPrivilegedApp();
    method public boolean isSystemApp();
    method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
    field public static final int CATEGORY_AUDIO = 1; // 0x1
    field public static final int CATEGORY_GAME = 0; // 0x0
    field public static final int CATEGORY_IMAGE = 3; // 0x3
    field public static final int CATEGORY_MAPS = 6; // 0x6
    field public static final int CATEGORY_NEWS = 5; // 0x5
    field public static final int CATEGORY_PRODUCTIVITY = 7; // 0x7
    field public static final int CATEGORY_SOCIAL = 4; // 0x4
    field public static final int CATEGORY_UNDEFINED = -1; // 0xffffffff
    field public static final int CATEGORY_VIDEO = 2; // 0x2
    field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
    field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
    field public static final int FLAG_ALLOW_CLEAR_USER_DATA = 64; // 0x40
@@ -9633,7 +9644,7 @@ package android.content.pm {
    field public static final int FLAG_HAS_CODE = 4; // 0x4
    field public static final int FLAG_INSTALLED = 8388608; // 0x800000
    field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
    field public static final int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final deprecated int FLAG_IS_GAME = 33554432; // 0x2000000
    field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
    field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
    field public static final int FLAG_MULTIARCH = -2147483648; // 0x80000000
@@ -9654,6 +9665,7 @@ package android.content.pm {
    field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
    field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
    field public java.lang.String backupAgentName;
    field public int category;
    field public java.lang.String className;
    field public int compatibleWidthLimitDp;
    field public java.lang.String dataDir;
@@ -10075,6 +10087,7 @@ package android.content.pm {
    method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
    method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public abstract void setApplicationCategoryHint(java.lang.String, int);
    method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
    method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
@@ -39139,6 +39152,7 @@ package android.test.mock {
    method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
    method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
    method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
    method public void setApplicationCategoryHint(java.lang.String, int);
    method public void setApplicationEnabledSetting(java.lang.String, int, int);
    method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
    method public void setInstallerPackageName(java.lang.String, java.lang.String);
+11 −0
Original line number Diff line number Diff line
@@ -2027,6 +2027,17 @@ public class ApplicationPackageManager extends PackageManager {
        }
    }

    /** @hide */
    @Override
    public void setApplicationCategoryHint(String packageName, int categoryHint) {
        try {
            mPM.setApplicationCategoryHint(packageName, categoryHint,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public void getPackageSizeInfoAsUser(String packageName, int userHandle,
            IPackageStatsObserver observer) {
+144 −4
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.content.pm;

import static android.os.Build.VERSION_CODES.DONUT;

import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
@@ -31,13 +34,13 @@ import android.util.Printer;

import com.android.internal.util.ArrayUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;

import static android.os.Build.VERSION_CODES.DONUT;

/**
 * Information you can retrieve about a particular application.  This
 * corresponds to information collected from the AndroidManifest.xml's
@@ -344,9 +347,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    public static final int FLAG_IS_DATA_ONLY = 1<<24;

    /**
     * Value for {@link #flags}: true if the application was declared to be a game, or
     * false if it is a non-game application.
     * Value for {@link #flags}: true if the application was declared to be a
     * game, or false if it is a non-game application.
     *
     * @deprecated use {@link #CATEGORY_GAME} instead.
     */
    @Deprecated
    public static final int FLAG_IS_GAME = 1<<25;

    /**
@@ -779,6 +785,134 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     */
    public int networkSecurityConfigRes;

    /**
     * The category of this app. Categories are used to cluster multiple apps
     * together into meaningful groups, such as when summarizing battery,
     * network, or disk usage. Apps should only define this value when they fit
     * well into one of the specific categories.
     * <p>
     * Set from the {@link android.R.attr#appCategory} attribute in the
     * manifest. If the manifest doesn't define a category, this value may have
     * been provided by the installer via
     * {@link PackageManager#setApplicationCategoryHint(String, int)}.
     */
    public @Category int category = CATEGORY_UNDEFINED;

    /** {@hide} */
    @IntDef({
            CATEGORY_UNDEFINED,
            CATEGORY_GAME,
            CATEGORY_AUDIO,
            CATEGORY_VIDEO,
            CATEGORY_IMAGE,
            CATEGORY_SOCIAL,
            CATEGORY_NEWS,
            CATEGORY_MAPS,
            CATEGORY_PRODUCTIVITY
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Category {
    }

    /**
     * Value when category is undefined.
     *
     * @see #category
     */
    public static final int CATEGORY_UNDEFINED = -1;

    /**
     * Category for apps which are primarily games.
     *
     * @see #category
     */
    public static final int CATEGORY_GAME = 0;

    /**
     * Category for apps which primarily work with audio or music, such as music
     * players.
     *
     * @see #category
     */
    public static final int CATEGORY_AUDIO = 1;

    /**
     * Category for apps which primarily work with video or movies, such as
     * streaming video apps.
     *
     * @see #category
     */
    public static final int CATEGORY_VIDEO = 2;

    /**
     * Category for apps which primarily work with images or photos, such as
     * camera or gallery apps.
     *
     * @see #category
     */
    public static final int CATEGORY_IMAGE = 3;

    /**
     * Category for apps which are primarily social apps, such as messaging,
     * communication, or social network apps.
     *
     * @see #category
     */
    public static final int CATEGORY_SOCIAL = 4;

    /**
     * Category for apps which are primarily news apps, such as newspapers,
     * magazines, or sports apps.
     *
     * @see #category
     */
    public static final int CATEGORY_NEWS = 5;

    /**
     * Category for apps which are primarily maps apps, such as navigation apps.
     *
     * @see #category
     */
    public static final int CATEGORY_MAPS = 6;

    /**
     * Category for apps which are primarily productivity apps, such as cloud
     * storage or workplace apps.
     *
     * @see #category
     */
    public static final int CATEGORY_PRODUCTIVITY = 7;

    /**
     * Return a concise, localized title for the given
     * {@link ApplicationInfo#category} value, or {@code null} for unknown
     * values such as {@link #CATEGORY_UNDEFINED}.
     *
     * @see #category
     */
    public static CharSequence getCategoryTitle(Context context, @Category int category) {
        switch (category) {
            case ApplicationInfo.CATEGORY_GAME:
                return context.getText(com.android.internal.R.string.app_category_game);
            case ApplicationInfo.CATEGORY_AUDIO:
                return context.getText(com.android.internal.R.string.app_category_audio);
            case ApplicationInfo.CATEGORY_VIDEO:
                return context.getText(com.android.internal.R.string.app_category_video);
            case ApplicationInfo.CATEGORY_IMAGE:
                return context.getText(com.android.internal.R.string.app_category_image);
            case ApplicationInfo.CATEGORY_SOCIAL:
                return context.getText(com.android.internal.R.string.app_category_social);
            case ApplicationInfo.CATEGORY_NEWS:
                return context.getText(com.android.internal.R.string.app_category_news);
            case ApplicationInfo.CATEGORY_MAPS:
                return context.getText(com.android.internal.R.string.app_category_maps);
            case ApplicationInfo.CATEGORY_PRODUCTIVITY:
                return context.getText(com.android.internal.R.string.app_category_productivity);
            default:
                return null;
        }
    }

    public void dump(Printer pw, String prefix) {
        dump(pw, prefix, DUMP_FLAG_ALL);
    }
@@ -854,6 +988,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
                pw.println(prefix + "networkSecurityConfigRes=0x"
                        + Integer.toHexString(networkSecurityConfigRes));
            }
            if (category != CATEGORY_UNDEFINED) {
                pw.println(prefix + "category=" + category);
            }
        }
        super.dumpBack(pw, prefix);
    }
@@ -941,6 +1078,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        backupAgentName = orig.backupAgentName;
        fullBackupContent = orig.fullBackupContent;
        networkSecurityConfigRes = orig.networkSecurityConfigRes;
        category = orig.category;
    }

    public String toString() {
@@ -997,6 +1135,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        dest.writeInt(uiOptions);
        dest.writeInt(fullBackupContent);
        dest.writeInt(networkSecurityConfigRes);
        dest.writeInt(category);
    }

    public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1053,6 +1192,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        uiOptions = source.readInt();
        fullBackupContent = source.readInt();
        networkSecurityConfigRes = source.readInt();
        category = source.readInt();
    }

    /**
Loading