diff options
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 35 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageInstaller.aidl | 12 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageInstallerCallback.aidl (renamed from core/java/android/content/pm/IPackageInstallerObserver.aidl) | 8 | ||||
-rw-r--r-- | core/java/android/content/pm/IPackageInstallerSession.aidl | 9 | ||||
-rw-r--r-- | core/java/android/content/pm/InstallSessionInfo.java | 51 | ||||
-rw-r--r-- | core/java/android/content/pm/InstallSessionParams.java | 154 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageInstaller.java | 407 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageManager.java | 109 |
8 files changed, 476 insertions, 309 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 1cb0fd4..68d4cf1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -61,7 +61,10 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.Log; import android.view.Display; + +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; + import dalvik.system.VMRuntime; import java.lang.ref.WeakReference; @@ -74,13 +77,20 @@ final class ApplicationPackageManager extends PackageManager { private final static boolean DEBUG = false; private final static boolean DEBUG_ICONS = false; - UserManager mUserManager; + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private UserManager mUserManager; + @GuardedBy("mLock") + private PackageInstaller mInstaller; UserManager getUserManager() { - if (mUserManager == null) { - mUserManager = UserManager.get(mContext); + synchronized (mLock) { + if (mUserManager == null) { + mUserManager = UserManager.get(mContext); + } + return mUserManager; } - return mUserManager; } @Override @@ -1543,12 +1553,17 @@ final class ApplicationPackageManager extends PackageManager { } @Override - public PackageInstaller getInstaller() { - try { - return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getPackageName(), - mContext.getUserId()); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public PackageInstaller getPackageInstaller() { + synchronized (mLock) { + if (mInstaller == null) { + try { + mInstaller = new PackageInstaller(this, mPM.getPackageInstaller(), + mContext.getPackageName(), mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + return mInstaller; } } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 32460c9..0c65034 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -17,7 +17,7 @@ package android.content.pm; import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallerObserver; +import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; import android.content.pm.InstallSessionInfo; import android.content.pm.InstallSessionParams; @@ -25,13 +25,15 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstaller { - int createSession(String installerPackageName, in InstallSessionParams params, int userId); + int createSession(in InstallSessionParams params, String installerPackageName, int userId); IPackageInstallerSession openSession(int sessionId); - List<InstallSessionInfo> getSessions(int userId); + InstallSessionInfo getSessionInfo(int sessionId); + List<InstallSessionInfo> getAllSessions(int userId); + List<InstallSessionInfo> getMySessions(String installerPackageName, int userId); - void registerObserver(IPackageInstallerObserver observer, int userId); - void unregisterObserver(IPackageInstallerObserver observer, int userId); + void registerCallback(IPackageInstallerCallback callback, int userId); + void unregisterCallback(IPackageInstallerCallback callback); void uninstall(String packageName, int flags, in IPackageDeleteObserver observer, int userId); void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId); diff --git a/core/java/android/content/pm/IPackageInstallerObserver.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl index 85660e4..a31ae54 100644 --- a/core/java/android/content/pm/IPackageInstallerObserver.aidl +++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl @@ -16,11 +16,9 @@ package android.content.pm; -import android.content.pm.InstallSessionInfo; - /** {@hide} */ -oneway interface IPackageInstallerObserver { - void onSessionCreated(in InstallSessionInfo info); - void onSessionProgress(int sessionId, int progress); +oneway interface IPackageInstallerCallback { + void onSessionCreated(int sessionId); + void onSessionProgressChanged(int sessionId, float progress); void onSessionFinished(int sessionId, boolean success); } diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index d6775d4..2fd7ddb 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -21,11 +21,12 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstallerSession { - void setClientProgress(int progress); - void addClientProgress(int progress); + void setClientProgress(float progress); + void addClientProgress(float progress); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); - void install(in IPackageInstallObserver2 observer); - void destroy(); + void close(); + void commit(in IPackageInstallObserver2 observer); + void abandon(); } diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java index 3336727..a9c574a 100644 --- a/core/java/android/content/pm/InstallSessionInfo.java +++ b/core/java/android/content/pm/InstallSessionInfo.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.Nullable; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; @@ -30,16 +31,18 @@ public class InstallSessionInfo implements Parcelable { /** {@hide} */ public String installerPackageName; /** {@hide} */ - public int progress; + public float progress; /** {@hide} */ public int mode; /** {@hide} */ - public String packageName; + public long sizeBytes; /** {@hide} */ - public Bitmap icon; + public String appPackageName; /** {@hide} */ - public CharSequence title; + public Bitmap appIcon; + /** {@hide} */ + public CharSequence appLabel; /** {@hide} */ public InstallSessionInfo() { @@ -49,12 +52,13 @@ public class InstallSessionInfo implements Parcelable { public InstallSessionInfo(Parcel source) { sessionId = source.readInt(); installerPackageName = source.readString(); - progress = source.readInt(); + progress = source.readFloat(); mode = source.readInt(); - packageName = source.readString(); - icon = source.readParcelable(null); - title = source.readString(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); } /** @@ -67,19 +71,19 @@ public class InstallSessionInfo implements Parcelable { /** * Return the package name of the app that owns this session. */ - public String getInstallerPackageName() { + public @Nullable String getInstallerPackageName() { return installerPackageName; } /** - * Return current overall progress of this session, between 0 and 100. + * Return current overall progress of this session, between 0 and 1. * <p> * Note that this progress may not directly correspond to the value reported - * by {@link PackageInstaller.Session#setProgress(int)}, as the system may + * by {@link PackageInstaller.Session#setProgress(float)}, as the system may * carve out a portion of the overall progress to represent its own internal * installation work. */ - public int getProgress() { + public float getProgress() { return progress; } @@ -87,24 +91,24 @@ public class InstallSessionInfo implements Parcelable { * Return the package name this session is working with. May be {@code null} * if unknown. */ - public String getPackageName() { - return packageName; + public @Nullable String getAppPackageName() { + return appPackageName; } /** * Return an icon representing the app being installed. May be {@code null} * if unavailable. */ - public Bitmap getIcon() { - return icon; + public @Nullable Bitmap getAppIcon() { + return appIcon; } /** - * Return a title representing the app being installed. May be {@code null} + * Return a label representing the app being installed. May be {@code null} * if unavailable. */ - public CharSequence getTitle() { - return title; + public @Nullable CharSequence getAppLabel() { + return appLabel; } @Override @@ -116,12 +120,13 @@ public class InstallSessionInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(sessionId); dest.writeString(installerPackageName); - dest.writeInt(progress); + dest.writeFloat(progress); dest.writeInt(mode); - dest.writeString(packageName); - dest.writeParcelable(icon, flags); - dest.writeString(title != null ? title.toString() : null); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel != null ? appLabel.toString() : null); } public static final Parcelable.Creator<InstallSessionInfo> diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java index e039699..3de9863 100644 --- a/core/java/android/content/pm/InstallSessionParams.java +++ b/core/java/android/content/pm/InstallSessionParams.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.Nullable; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -29,17 +30,25 @@ import com.android.internal.util.IndentingPrintWriter; */ public class InstallSessionParams implements Parcelable { - // TODO: extend to support remaining VerificationParams - - /** {@hide} */ - public static final int MODE_INVALID = 0; - /** {@hide} */ + /** + * Mode for an install session whose staged APKs should fully replace any + * existing APKs for the target app. + */ public static final int MODE_FULL_INSTALL = 1; - /** {@hide} */ + + /** + * Mode for an install session that should inherit any existing APKs for the + * target app, unless they have been explicitly overridden (based on split + * name) by the session. For example, this can be used to add one or more + * split APKs to an existing installation. + * <p> + * If there are no existing APKs for the target app, this behaves like + * {@link #MODE_FULL_INSTALL}. + */ public static final int MODE_INHERIT_EXISTING = 2; /** {@hide} */ - public int mode = MODE_INVALID; + public int mode; /** {@hide} */ public int installFlags; /** {@hide} */ @@ -47,15 +56,13 @@ public class InstallSessionParams implements Parcelable { /** {@hide} */ public Signature[] signatures; /** {@hide} */ - public long deltaSize = -1; + public long sizeBytes = -1; /** {@hide} */ - public int progressMax = 100; + public String appPackageName; /** {@hide} */ - public String packageName; + public Bitmap appIcon; /** {@hide} */ - public Bitmap icon; - /** {@hide} */ - public CharSequence title; + public CharSequence appLabel; /** {@hide} */ public Uri originatingUri; /** {@hide} */ @@ -63,7 +70,15 @@ public class InstallSessionParams implements Parcelable { /** {@hide} */ public String abiOverride; - public InstallSessionParams() { + /** + * Construct parameters for a new package install session. + * + * @param mode one of {@link #MODE_FULL_INSTALL} or + * {@link #MODE_INHERIT_EXISTING} describing how the session + * should interact with an existing app. + */ + public InstallSessionParams(int mode) { + this.mode = mode; } /** {@hide} */ @@ -72,34 +87,16 @@ public class InstallSessionParams implements Parcelable { installFlags = source.readInt(); installLocation = source.readInt(); signatures = (Signature[]) source.readParcelableArray(null); - deltaSize = source.readLong(); - progressMax = source.readInt(); - packageName = source.readString(); - icon = source.readParcelable(null); - title = source.readString(); + sizeBytes = source.readLong(); + appPackageName = source.readString(); + appIcon = source.readParcelable(null); + appLabel = source.readString(); originatingUri = source.readParcelable(null); referrerUri = source.readParcelable(null); abiOverride = source.readString(); } /** - * Set session mode indicating that it should fully replace any existing - * APKs for this application. - */ - public void setModeFullInstall() { - this.mode = MODE_FULL_INSTALL; - } - - /** - * Set session mode indicating that it should inherit any existing APKs for - * this application, unless they are explicitly overridden (by split name) - * in the session. - */ - public void setModeInheritExisting() { - this.mode = MODE_INHERIT_EXISTING; - } - - /** * Provide value of {@link PackageInfo#installLocation}, which may be used * to determine where the app will be staged. Defaults to * {@link PackageInfo#INSTALL_LOCATION_INTERNAL_ONLY}. @@ -109,56 +106,57 @@ public class InstallSessionParams implements Parcelable { } /** - * Optionally provide the required value of {@link PackageInfo#signatures}. - * This can be used to assert that all staged APKs have been signed with - * this set of specific certificates. Regardless of this value, all APKs in - * the application must have the same signing certificates. - */ - public void setSignatures(Signature[] signatures) { - this.signatures = signatures; - } - - /** - * Indicate the expected growth in disk usage resulting from this session. - * This may be used to ensure enough disk space exists before proceeding, or - * to estimate container size for installations living on external storage. + * Optionally provide a set of certificates for the app being installed. * <p> - * This value should only reflect APK sizes. + * If the APKs staged in the session aren't consistent with these + * signatures, the install will fail. Regardless of this value, all APKs in + * the app must have the same signing certificates. + * + * @see PackageInfo#signatures */ - public void setDeltaSize(long deltaSize) { - this.deltaSize = deltaSize; + public void setSignatures(@Nullable Signature[] signatures) { + this.signatures = signatures; } /** - * Set the maximum progress for this session, used for normalization - * purposes. + * Optionally indicate the total size (in bytes) of all APKs that will be + * delivered in this session. The system may use this to ensure enough disk + * space exists before proceeding, or to estimate container size for + * installations living on external storage. * - * @see PackageInstaller.Session#setProgress(int) + * @see PackageInfo#INSTALL_LOCATION_AUTO + * @see PackageInfo#INSTALL_LOCATION_PREFER_EXTERNAL */ - public void setProgressMax(int progressMax) { - this.progressMax = progressMax; + public void setSize(long sizeBytes) { + this.sizeBytes = sizeBytes; } /** - * Optionally set the package name this session will be working with. It's - * strongly recommended that you provide this value when known. + * Optionally set the package name of the app being installed. It's strongly + * recommended that you provide this value when known, so that observers can + * communicate installing apps to users. + * <p> + * If the APKs staged in the session aren't consistent with this package + * name, the install will fail. Regardless of this value, all APKs in the + * app must have the same package name. */ - public void setPackageName(String packageName) { - this.packageName = packageName; + public void setAppPackageName(@Nullable String appPackageName) { + this.appPackageName = appPackageName; } /** - * Optionally set an icon representing the app being installed. + * Optionally set an icon representing the app being installed. This should + * be at least {@link android.R.dimen#app_icon_size} in both dimensions. */ - public void setIcon(Bitmap icon) { - this.icon = icon; + public void setAppIcon(@Nullable Bitmap appIcon) { + this.appIcon = appIcon; } /** - * Optionally set a title representing the app being installed. + * Optionally set a label representing the app being installed. */ - public void setTitle(CharSequence title) { - this.title = title; + public void setAppLabel(@Nullable CharSequence appLabel) { + this.appLabel = appLabel; } /** @@ -167,7 +165,7 @@ public class InstallSessionParams implements Parcelable { * * @see Intent#EXTRA_ORIGINATING_URI */ - public void setOriginatingUri(Uri originatingUri) { + public void setOriginatingUri(@Nullable Uri originatingUri) { this.originatingUri = originatingUri; } @@ -177,7 +175,7 @@ public class InstallSessionParams implements Parcelable { * * @see Intent#EXTRA_REFERRER */ - public void setReferrerUri(Uri referrerUri) { + public void setReferrerUri(@Nullable Uri referrerUri) { this.referrerUri = referrerUri; } @@ -187,11 +185,10 @@ public class InstallSessionParams implements Parcelable { pw.printHexPair("installFlags", installFlags); pw.printPair("installLocation", installLocation); pw.printPair("signatures", (signatures != null)); - pw.printPair("deltaSize", deltaSize); - pw.printPair("progressMax", progressMax); - pw.printPair("packageName", packageName); - pw.printPair("icon", (icon != null)); - pw.printPair("title", title); + pw.printPair("sizeBytes", sizeBytes); + pw.printPair("appPackageName", appPackageName); + pw.printPair("appIcon", (appIcon != null)); + pw.printPair("appLabel", appLabel); pw.printPair("originatingUri", originatingUri); pw.printPair("referrerUri", referrerUri); pw.printPair("abiOverride", abiOverride); @@ -209,11 +206,10 @@ public class InstallSessionParams implements Parcelable { dest.writeInt(installFlags); dest.writeInt(installLocation); dest.writeParcelableArray(signatures, flags); - dest.writeLong(deltaSize); - dest.writeInt(progressMax); - dest.writeString(packageName); - dest.writeParcelable(icon, flags); - dest.writeString(title != null ? title.toString() : null); + dest.writeLong(sizeBytes); + dest.writeString(appPackageName); + dest.writeParcelable(appIcon, flags); + dest.writeString(appLabel != null ? appLabel.toString() : null); dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); dest.writeString(abiOverride); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index df82d26..a114bb8 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -16,11 +16,16 @@ package android.content.pm; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PackageInstallObserver; import android.app.PackageUninstallObserver; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.FileBridge; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.ExceptionUtils; @@ -28,6 +33,8 @@ import android.util.ExceptionUtils; import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** @@ -61,6 +68,8 @@ public class PackageInstaller { private final int mUserId; private final String mInstallerPackageName; + private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); + /** {@hide} */ public PackageInstaller(PackageManager pm, IPackageInstaller installer, String installerPackageName, int userId) { @@ -71,28 +80,6 @@ public class PackageInstaller { } /** - * Quickly test if the given package is already available on the device. - * This is typically used in multi-user scenarios where another user on the - * device has already installed the package. - * - * @hide - */ - public boolean isPackageAvailable(String packageName) { - return mPm.isPackageAvailable(packageName); - } - - /** {@hide} */ - public void installAvailablePackage(String packageName, PackageInstallObserver observer) { - int returnCode; - try { - returnCode = mPm.installExistingPackage(packageName); - } catch (NameNotFoundException e) { - returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; - } - observer.packageInstalled(packageName, null, returnCode); - } - - /** * Create a new session using the given parameters, returning a unique ID * that represents the session. Once created, the session can be opened * multiple times across multiple device boots. @@ -104,9 +91,9 @@ public class PackageInstaller { * @throws IOException if parameters were unsatisfiable, such as lack of * disk space or unavailable media. */ - public int createSession(InstallSessionParams params) throws IOException { + public int createSession(@NonNull InstallSessionParams params) throws IOException { try { - return mInstaller.createSession(mInstallerPackageName, params, mUserId); + return mInstaller.createSession(params, mInstallerPackageName, mUserId); } catch (RuntimeException e) { ExceptionUtils.maybeUnwrapIOException(e); throw e; @@ -116,9 +103,10 @@ public class PackageInstaller { } /** - * Open an existing session to actively perform work. + * Open an existing session to actively perform work. To succeed, the caller + * must be the owner of the install session. */ - public Session openSession(int sessionId) { + public @NonNull Session openSession(int sessionId) { try { return new Session(mInstaller.openSession(sessionId)); } catch (RemoteException e) { @@ -127,13 +115,35 @@ public class PackageInstaller { } /** - * Return list of all active install sessions on the device. + * Return details for a specific session. To succeed, the caller must either + * own this session, or be the current home app. */ - public List<InstallSessionInfo> getActiveSessions() { - // TODO: filter based on caller - // TODO: let launcher app see all active sessions + public @Nullable InstallSessionInfo getSessionInfo(int sessionId) { try { - return mInstaller.getSessions(mUserId); + return mInstaller.getSessionInfo(sessionId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Return list of all active install sessions, regardless of the installer. + * To succeed, the caller must be the current home app. + */ + public @NonNull List<InstallSessionInfo> getAllSessions() { + try { + return mInstaller.getAllSessions(mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Return list of all install sessions owned by the calling app. + */ + public @NonNull List<InstallSessionInfo> getMySessions() { + try { + return mInstaller.getMySessions(mInstallerPackageName, mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -144,10 +154,10 @@ public class PackageInstaller { * method is only available to the current "installer of record" for the * package. */ - public void uninstall(String packageName, UninstallResultCallback callback) { + public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) { try { mInstaller.uninstall(packageName, 0, - new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); + new UninstallCallbackDelegate(callback).getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -158,10 +168,11 @@ public class PackageInstaller { * * @hide */ - public void uninstall(String packageName, String splitName, UninstallResultCallback callback) { + public void uninstall(@NonNull String packageName, @NonNull String splitName, + @NonNull UninstallCallback callback) { try { mInstaller.uninstallSplit(packageName, splitName, 0, - new UninstallResultCallbackDelegate(callback).getBinder(), mUserId); + new UninstallCallbackDelegate(callback).getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -170,69 +181,121 @@ public class PackageInstaller { /** * Events for observing session lifecycle. */ - public static abstract class SessionObserver { - private final IPackageInstallerObserver.Stub mBinder = new IPackageInstallerObserver.Stub() { - @Override - public void onSessionCreated(InstallSessionInfo info) { - SessionObserver.this.onCreated(info); - } - - @Override - public void onSessionProgress(int sessionId, int progress) { - SessionObserver.this.onProgress(sessionId, progress); - } - - @Override - public void onSessionFinished(int sessionId, boolean success) { - SessionObserver.this.onFinalized(sessionId, success); - } - }; - - /** {@hide} */ - public IPackageInstallerObserver getBinder() { - return mBinder; - } - + public static abstract class SessionCallback { /** * New session has been created. */ - public abstract void onCreated(InstallSessionInfo info); + public abstract void onCreated(int sessionId); /** * Progress for given session has been updated. * <p> * Note that this progress may not directly correspond to the value - * reported by {@link PackageInstaller.Session#setProgress(int)}, as the - * system may carve out a portion of the overall progress to represent - * its own internal installation work. + * reported by {@link PackageInstaller.Session#setProgress(float)}, as + * the system may carve out a portion of the overall progress to + * represent its own internal installation work. */ - public abstract void onProgress(int sessionId, int progress); + public abstract void onProgressChanged(int sessionId, float progress); /** - * Session has been finalized, either with success or failure. + * Session has completely finished, either with success or failure. */ - public abstract void onFinalized(int sessionId, boolean success); + public abstract void onFinished(int sessionId, boolean success); + } + + /** {@hide} */ + private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements + Handler.Callback { + private static final int MSG_SESSION_CREATED = 1; + private static final int MSG_SESSION_PROGRESS_CHANGED = 2; + private static final int MSG_SESSION_FINISHED = 3; + + final SessionCallback mCallback; + final Handler mHandler; + + public SessionCallbackDelegate(SessionCallback callback, Looper looper) { + mCallback = callback; + mHandler = new Handler(looper, this); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_SESSION_CREATED: + mCallback.onCreated(msg.arg1); + return true; + case MSG_SESSION_PROGRESS_CHANGED: + mCallback.onProgressChanged(msg.arg1, (float) msg.obj); + return true; + case MSG_SESSION_FINISHED: + mCallback.onFinished(msg.arg1, msg.arg2 != 0); + return true; + } + return false; + } + + @Override + public void onSessionCreated(int sessionId) { + mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget(); + } + + @Override + public void onSessionProgressChanged(int sessionId, float progress) { + mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) + .sendToTarget(); + } + + @Override + public void onSessionFinished(int sessionId, boolean success) { + mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) + .sendToTarget(); + } } /** - * Register to watch for session lifecycle events. + * Register to watch for session lifecycle events. To succeed, the caller + * must be the current home app. */ - public void registerSessionObserver(SessionObserver observer) { - try { - mInstaller.registerObserver(observer.getBinder(), mUserId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public void addSessionCallback(@NonNull SessionCallback callback) { + addSessionCallback(callback, new Handler()); + } + + /** + * Register to watch for session lifecycle events. To succeed, the caller + * must be the current home app. + * + * @param handler to dispatch callback events through, otherwise uses + * calling thread. + */ + public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { + synchronized (mDelegates) { + final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, + handler.getLooper()); + try { + mInstaller.registerCallback(delegate, mUserId); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + mDelegates.add(delegate); } } /** - * Unregister an existing observer. + * Unregister an existing callback. */ - public void unregisterSessionObserver(SessionObserver observer) { - try { - mInstaller.unregisterObserver(observer.getBinder(), mUserId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + public void removeSessionCallback(@NonNull SessionCallback callback) { + synchronized (mDelegates) { + for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { + final SessionCallbackDelegate delegate = i.next(); + if (delegate.mCallback == callback) { + try { + mInstaller.unregisterCallback(delegate); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + i.remove(); + } + } } } @@ -244,9 +307,9 @@ public class PackageInstaller { * A session may contain any number of split packages. If the application * does not yet exist, this session must include a base package. * <p> - * If a package included in this session is already defined by the existing - * installation (for example, the same split name), the package in this - * session will replace the existing package. + * If an APK included in this session is already defined by the existing + * installation (for example, the same split name), the APK in this session + * will replace the existing APK. */ public static class Session implements Closeable { private IPackageInstallerSession mSession; @@ -257,10 +320,9 @@ public class PackageInstaller { } /** - * Set current progress. Valid values are anywhere between 0 and - * {@link InstallSessionParams#setProgressMax(int)}. + * Set current progress. Valid values are anywhere between 0 and 1. */ - public void setProgress(int progress) { + public void setProgress(float progress) { try { mSession.setClientProgress(progress); } catch (RemoteException e) { @@ -269,7 +331,7 @@ public class PackageInstaller { } /** {@hide} */ - public void addProgress(int progress) { + public void addProgress(float progress) { try { mSession.addClientProgress(progress); } catch (RemoteException e) { @@ -278,15 +340,33 @@ public class PackageInstaller { } /** - * Open an APK file for writing, starting at the given offset. You can - * then stream data into the file, periodically calling - * {@link #fsync(OutputStream)} to ensure bytes have been written to - * disk. + * Open a stream to write an APK file into the session. + * <p> + * The returned stream will start writing data at the requested offset + * in the underlying file, which can be used to resume a partially + * written file. If a valid file length is specified, the system will + * preallocate the underlying disk space to optimize placement on disk. + * It's strongly recommended to provide a valid file length when known. + * <p> + * You can write data into the returned stream, optionally call + * {@link #fsync(OutputStream)} as needed to ensure bytes have been + * persisted to disk, and then close when finished. All streams must be + * closed before calling {@link #commit(CommitCallback)}. + * + * @param name arbitrary, unique name of your choosing to identify the + * APK being written. You can open a file again for + * additional writes (such as after a reboot) by using the + * same name. This name is only meaningful within the context + * of a single install session. + * @param offsetBytes offset into the file to begin writing at, or 0 to + * start at the beginning of the file. + * @param lengthBytes total size of the file being written, used to + * preallocate the underlying disk space, or -1 if unknown. */ - public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes) - throws IOException { + public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, + long lengthBytes) throws IOException { try { - final ParcelFileDescriptor clientSocket = mSession.openWrite(splitName, + final ParcelFileDescriptor clientSocket = mSession.openWrite(name, offsetBytes, lengthBytes); return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor()); } catch (RuntimeException e) { @@ -302,7 +382,7 @@ public class PackageInstaller { * to disk. This is only valid for streams returned from * {@link #openWrite(String, long, long)}. */ - public void fsync(OutputStream out) throws IOException { + public void fsync(@NonNull OutputStream out) throws IOException { if (out instanceof FileBridge.FileBridgeOutputStream) { ((FileBridge.FileBridgeOutputStream) out).fsync(); } else { @@ -319,9 +399,9 @@ public class PackageInstaller { * on the session. If the device reboots before the session has been * finalized, you may commit the session again. */ - public void commit(CommitResultCallback callback) { + public void commit(@NonNull CommitCallback callback) { try { - mSession.install(new CommitResultCallbackDelegate(callback).getBinder()); + mSession.commit(new CommitCallbackDelegate(callback).getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -333,15 +413,20 @@ public class PackageInstaller { */ @Override public void close() { - // No resources to release at the moment + try { + mSession.close(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } } /** - * Completely destroy this session, rendering it invalid. + * Completely abandon this session, destroying all staged data and + * rendering it invalid. */ - public void destroy() { + public void abandon() { try { - mSession.destroy(); + mSession.abandon(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -351,30 +436,26 @@ public class PackageInstaller { /** * Final result of an uninstall request. */ - public static abstract class UninstallResultCallback { + public static abstract class UninstallCallback { public abstract void onSuccess(); public abstract void onFailure(String msg); } /** {@hide} */ - private static class UninstallResultCallbackDelegate extends PackageUninstallObserver { - private final UninstallResultCallback target; + private static class UninstallCallbackDelegate extends PackageUninstallObserver { + private final UninstallCallback target; - public UninstallResultCallbackDelegate(UninstallResultCallback target) { + public UninstallCallbackDelegate(UninstallCallback target) { this.target = target; } @Override public void onUninstallFinished(String basePackageName, int returnCode) { - final String msg = null; - - switch (returnCode) { - case PackageManager.DELETE_SUCCEEDED: target.onSuccess(); break; - case PackageManager.DELETE_FAILED_INTERNAL_ERROR: target.onFailure("DELETE_FAILED_INTERNAL_ERROR: " + msg); break; - case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: target.onFailure("DELETE_FAILED_DEVICE_POLICY_MANAGER: " + msg); break; - case PackageManager.DELETE_FAILED_USER_RESTRICTED: target.onFailure("DELETE_FAILED_USER_RESTRICTED: " + msg); break; - case PackageManager.DELETE_FAILED_OWNER_BLOCKED: target.onFailure("DELETE_FAILED_OWNER_BLOCKED: " + msg); break; - default: target.onFailure(msg); break; + if (returnCode == PackageManager.DELETE_SUCCEEDED) { + target.onSuccess(); + } else { + final String msg = PackageManager.deleteStatusToString(returnCode); + target.onFailure(msg); } } } @@ -382,16 +463,13 @@ public class PackageInstaller { /** * Final result of a session commit request. */ - public static abstract class CommitResultCallback { - public abstract void onSuccess(); - + public static abstract class CommitCallback { /** - * Generic failure occurred. You can override methods (such as - * {@link #onFailureInvalid(String)}) to handle more specific categories - * of failure. By default, those specific categories all flow into this - * generic failure. + * Generic unknown failure. The system will always try to provide a more + * specific failure reason, but in some rare cases this may be + * delivered. */ - public abstract void onFailure(String msg); + public static final int FAILURE_UNKNOWN = 0; /** * One or more of the APKs included in the session was invalid. For @@ -399,23 +477,19 @@ public class PackageInstaller { * mismatched, etc. The installer may want to try downloading and * installing again. */ - public void onFailureInvalid(String msg) { - onFailure(msg); - } + public static final int FAILURE_INVALID = 1; /** * This install session conflicts (or is inconsistent with) with another * package already installed on the device. For example, an existing * permission, incompatible certificates, etc. The user may be able to * uninstall another app to fix the issue. - * - * @param otherPackageName if one specific package was identified as the - * cause of the conflict, it's named here. If unknown, or - * multiple packages, this may be {@code null}. + * <p> + * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} if one + * specific package was identified as the cause of the conflict. If + * unknown, or multiple packages, the extra may be {@code null}. */ - public void onFailureConflict(String msg, String otherPackageName) { - onFailure(msg); - } + public static final int FAILURE_CONFLICT = 2; /** * This install session failed due to storage issues. For example, @@ -423,9 +497,7 @@ public class PackageInstaller { * media may be unavailable. The user may be able to help free space * or insert the correct media. */ - public void onFailureStorage(String msg) { - onFailure(msg); - } + public static final int FAILURE_STORAGE = 3; /** * This install session is fundamentally incompatible with this @@ -434,66 +506,37 @@ public class PackageInstaller { * ABI, or it requires a newer SDK version, etc. This install would * never succeed. */ - public void onFailureIncompatible(String msg) { - onFailure(msg); - } + public static final int FAILURE_INCOMPATIBLE = 4; + + public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; + + public abstract void onSuccess(); + public abstract void onFailure(int failureReason, String msg, Bundle extras); } /** {@hide} */ - private static class CommitResultCallbackDelegate extends PackageInstallObserver { - private final CommitResultCallback target; + private static class CommitCallbackDelegate extends PackageInstallObserver { + private final CommitCallback target; - public CommitResultCallbackDelegate(CommitResultCallback target) { + public CommitCallbackDelegate(CommitCallback target) { this.target = target; } @Override public void packageInstalled(String basePackageName, Bundle extras, int returnCode, String msg) { - final String otherPackage = null; - - switch (returnCode) { - case PackageManager.INSTALL_SUCCEEDED: target.onSuccess(); break; - case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: target.onFailureConflict("INSTALL_FAILED_ALREADY_EXISTS: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_INVALID_APK: target.onFailureInvalid("INSTALL_FAILED_INVALID_APK: " + msg); break; - case PackageManager.INSTALL_FAILED_INVALID_URI: target.onFailureInvalid("INSTALL_FAILED_INVALID_URI: " + msg); break; - case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: target.onFailureStorage("INSTALL_FAILED_INSUFFICIENT_STORAGE: " + msg); break; - case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PACKAGE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NO_SHARED_USER: target.onFailureConflict("INSTALL_FAILED_NO_SHARED_USER: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_UPDATE_INCOMPATIBLE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: target.onFailureConflict("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: target.onFailureIncompatible("INSTALL_FAILED_MISSING_SHARED_LIBRARY: " + msg); break; - case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: target.onFailureConflict("INSTALL_FAILED_REPLACE_COULDNT_DELETE: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_DEXOPT: target.onFailureInvalid("INSTALL_FAILED_DEXOPT: " + msg); break; - case PackageManager.INSTALL_FAILED_OLDER_SDK: target.onFailureIncompatible("INSTALL_FAILED_OLDER_SDK: " + msg); break; - case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: target.onFailureConflict("INSTALL_FAILED_CONFLICTING_PROVIDER: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NEWER_SDK: target.onFailureIncompatible("INSTALL_FAILED_NEWER_SDK: " + msg); break; - case PackageManager.INSTALL_FAILED_TEST_ONLY: target.onFailureInvalid("INSTALL_FAILED_TEST_ONLY: " + msg); break; - case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: target.onFailureIncompatible("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: " + msg); break; - case PackageManager.INSTALL_FAILED_MISSING_FEATURE: target.onFailureIncompatible("INSTALL_FAILED_MISSING_FEATURE: " + msg); break; - case PackageManager.INSTALL_FAILED_CONTAINER_ERROR: target.onFailureStorage("INSTALL_FAILED_CONTAINER_ERROR: " + msg); break; - case PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION: target.onFailureStorage("INSTALL_FAILED_INVALID_INSTALL_LOCATION: " + msg); break; - case PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE: target.onFailureStorage("INSTALL_FAILED_MEDIA_UNAVAILABLE: " + msg); break; - case PackageManager.INSTALL_FAILED_VERIFICATION_TIMEOUT: target.onFailure("INSTALL_FAILED_VERIFICATION_TIMEOUT: " + msg); break; - case PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE: target.onFailure("INSTALL_FAILED_VERIFICATION_FAILURE: " + msg); break; - case PackageManager.INSTALL_FAILED_PACKAGE_CHANGED: target.onFailureInvalid("INSTALL_FAILED_PACKAGE_CHANGED: " + msg); break; - case PackageManager.INSTALL_FAILED_UID_CHANGED: target.onFailureInvalid("INSTALL_FAILED_UID_CHANGED: " + msg); break; - case PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE: target.onFailureInvalid("INSTALL_FAILED_VERSION_DOWNGRADE: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: target.onFailureInvalid("INSTALL_PARSE_FAILED_NOT_APK: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_MANIFEST: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: target.onFailureInvalid("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_NO_CERTIFICATES: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: target.onFailureInvalid("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: target.onFailureInvalid("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: target.onFailureInvalid("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: " + msg); break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: target.onFailureInvalid("INSTALL_PARSE_FAILED_MANIFEST_EMPTY: " + msg); break; - case PackageManager.INSTALL_FAILED_INTERNAL_ERROR: target.onFailure("INSTALL_FAILED_INTERNAL_ERROR: " + msg); break; - case PackageManager.INSTALL_FAILED_USER_RESTRICTED: target.onFailureIncompatible("INSTALL_FAILED_USER_RESTRICTED: " + msg); break; - case PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION: target.onFailureConflict("INSTALL_FAILED_DUPLICATE_PERMISSION: " + msg, otherPackage); break; - case PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS: target.onFailureInvalid("INSTALL_FAILED_NO_MATCHING_ABIS: " + msg); break; - default: target.onFailure(msg); break; + if (returnCode == PackageManager.INSTALL_SUCCEEDED) { + target.onSuccess(); + } else { + final int failureReason = PackageManager.installStatusToFailureReason(returnCode); + msg = PackageManager.installStatusToString(returnCode) + ": " + msg; + + if (extras != null) { + extras.putString(CommitCallback.EXTRA_PACKAGE_NAME, + extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE)); + } + + target.onFailure(failureReason, msg, extras); } } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 8b6ae41..62611efa 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -17,6 +17,7 @@ package android.content.pm; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -26,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.PackageInstaller.CommitCallback; import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -3723,7 +3725,7 @@ public abstract class PackageManager { * Return interface that offers the ability to install, upgrade, and remove * applications on the device. */ - public abstract PackageInstaller getInstaller(); + public abstract @NonNull PackageInstaller getPackageInstaller(); /** * Returns the data directory for a particular user and package, given the uid of the package. @@ -3772,4 +3774,109 @@ public abstract class PackageManager { /** {@hide} */ public abstract boolean isPackageAvailable(String packageName); + + /** {@hide} */ + public static String installStatusToString(int status) { + switch (status) { + case INSTALL_SUCCEEDED: return "INSTALL_SUCCEEDED"; + case INSTALL_FAILED_ALREADY_EXISTS: return "INSTALL_FAILED_ALREADY_EXISTS"; + case INSTALL_FAILED_INVALID_APK: return "INSTALL_FAILED_INVALID_APK"; + case INSTALL_FAILED_INVALID_URI: return "INSTALL_FAILED_INVALID_URI"; + case INSTALL_FAILED_INSUFFICIENT_STORAGE: return "INSTALL_FAILED_INSUFFICIENT_STORAGE"; + case INSTALL_FAILED_DUPLICATE_PACKAGE: return "INSTALL_FAILED_DUPLICATE_PACKAGE"; + case INSTALL_FAILED_NO_SHARED_USER: return "INSTALL_FAILED_NO_SHARED_USER"; + case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return "INSTALL_FAILED_UPDATE_INCOMPATIBLE"; + case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"; + case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return "INSTALL_FAILED_MISSING_SHARED_LIBRARY"; + case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return "INSTALL_FAILED_REPLACE_COULDNT_DELETE"; + case INSTALL_FAILED_DEXOPT: return "INSTALL_FAILED_DEXOPT"; + case INSTALL_FAILED_OLDER_SDK: return "INSTALL_FAILED_OLDER_SDK"; + case INSTALL_FAILED_CONFLICTING_PROVIDER: return "INSTALL_FAILED_CONFLICTING_PROVIDER"; + case INSTALL_FAILED_NEWER_SDK: return "INSTALL_FAILED_NEWER_SDK"; + case INSTALL_FAILED_TEST_ONLY: return "INSTALL_FAILED_TEST_ONLY"; + case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return "INSTALL_FAILED_CPU_ABI_INCOMPATIBLE"; + case INSTALL_FAILED_MISSING_FEATURE: return "INSTALL_FAILED_MISSING_FEATURE"; + case INSTALL_FAILED_CONTAINER_ERROR: return "INSTALL_FAILED_CONTAINER_ERROR"; + case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return "INSTALL_FAILED_INVALID_INSTALL_LOCATION"; + case INSTALL_FAILED_MEDIA_UNAVAILABLE: return "INSTALL_FAILED_MEDIA_UNAVAILABLE"; + case INSTALL_FAILED_VERIFICATION_TIMEOUT: return "INSTALL_FAILED_VERIFICATION_TIMEOUT"; + case INSTALL_FAILED_VERIFICATION_FAILURE: return "INSTALL_FAILED_VERIFICATION_FAILURE"; + case INSTALL_FAILED_PACKAGE_CHANGED: return "INSTALL_FAILED_PACKAGE_CHANGED"; + case INSTALL_FAILED_UID_CHANGED: return "INSTALL_FAILED_UID_CHANGED"; + case INSTALL_FAILED_VERSION_DOWNGRADE: return "INSTALL_FAILED_VERSION_DOWNGRADE"; + case INSTALL_PARSE_FAILED_NOT_APK: return "INSTALL_PARSE_FAILED_NOT_APK"; + case INSTALL_PARSE_FAILED_BAD_MANIFEST: return "INSTALL_PARSE_FAILED_BAD_MANIFEST"; + case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"; + case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return "INSTALL_PARSE_FAILED_NO_CERTIFICATES"; + case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"; + case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"; + case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"; + case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"; + case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"; + case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; + case INSTALL_FAILED_INTERNAL_ERROR: return "INSTALL_FAILED_INTERNAL_ERROR"; + case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED"; + case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION"; + case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS"; + default: return Integer.toString(status); + } + } + + /** {@hide} */ + public static int installStatusToFailureReason(int status) { + switch (status) { + case INSTALL_FAILED_ALREADY_EXISTS: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_INVALID_APK: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INVALID_URI: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INSUFFICIENT_STORAGE: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_DUPLICATE_PACKAGE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NO_SHARED_USER: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_UPDATE_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_MISSING_SHARED_LIBRARY: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_REPLACE_COULDNT_DELETE: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_DEXOPT: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_OLDER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONFLICTING_PROVIDER: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NEWER_SDK: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_TEST_ONLY: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_MISSING_FEATURE: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE; + case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NOT_APK: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_MANIFEST: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_NO_CERTIFICATES: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: return CommitCallback.FAILURE_INVALID; + case INSTALL_PARSE_FAILED_MANIFEST_EMPTY: return CommitCallback.FAILURE_INVALID; + case INSTALL_FAILED_INTERNAL_ERROR: return CommitCallback.FAILURE_UNKNOWN; + case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE; + case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT; + case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE; + default: return CommitCallback.FAILURE_UNKNOWN; + } + } + + /** {@hide} */ + public static String deleteStatusToString(int status) { + switch (status) { + case DELETE_SUCCEEDED: return "DELETE_SUCCEEDED"; + case DELETE_FAILED_INTERNAL_ERROR: return "DELETE_FAILED_INTERNAL_ERROR"; + case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER"; + case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED"; + case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED"; + default: return Integer.toString(status); + } + } } |