summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ApplicationPackageManager.java35
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl12
-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.aidl9
-rw-r--r--core/java/android/content/pm/InstallSessionInfo.java51
-rw-r--r--core/java/android/content/pm/InstallSessionParams.java154
-rw-r--r--core/java/android/content/pm/PackageInstaller.java407
-rw-r--r--core/java/android/content/pm/PackageManager.java109
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);
+ }
+ }
}