From aba0bed7a4f6301c6e3067fc799d8ef47aaca0b2 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 19 Sep 2012 12:43:09 -0700 Subject: Allow side-loading of apps from other users. This will allow applications to do the desired bypass of downloading and re-installing an app if it is already installed on the device for another user. Change-Id: Ib2bc0f39bc6b495af653560cf13cb8477413186d --- AndroidManifest.xml | 2 +- .../packageinstaller/InstallAppProgress.java | 27 ++++++++-- .../packageinstaller/PackageInstallerActivity.java | 61 ++++++++++++++++------ 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0bc6866f..dfc1a6dd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -27,6 +27,7 @@ + - diff --git a/src/com/android/packageinstaller/InstallAppProgress.java b/src/com/android/packageinstaller/InstallAppProgress.java index a2feacf2..e281fd37 100755 --- a/src/com/android/packageinstaller/InstallAppProgress.java +++ b/src/com/android/packageinstaller/InstallAppProgress.java @@ -163,7 +163,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener mPackageURI = intent.getData(); final String scheme = mPackageURI.getScheme(); - if (scheme != null && !"file".equals(scheme)) { + if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { throw new IllegalArgumentException("unexpected scheme " + scheme); } @@ -227,8 +227,14 @@ public class InstallAppProgress extends Activity implements View.OnClickListener Log.w(TAG, "Replacing package:" + mAppInfo.packageName); } - final File sourceFile = new File(mPackageURI.getPath()); - PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile); + final PackageUtil.AppSnippet as; + if ("package".equals(mPackageURI.getScheme())) { + as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo), + pm.getApplicationIcon(mAppInfo)); + } else { + final File sourceFile = new File(mPackageURI.getPath()); + as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile); + } mLabel = as.label; PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); mStatusTextView = (TextView)findViewById(R.id.center_text); @@ -250,8 +256,19 @@ public class InstallAppProgress extends Activity implements View.OnClickListener referrer, null); PackageInstallObserver observer = new PackageInstallObserver(); - pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, - installerPackageName, verificationParams, null); + if ("package".equals(mPackageURI.getScheme())) { + try { + pm.installExistingPackage(mAppInfo.packageName); + observer.packageInstalled(mAppInfo.packageName, + PackageManager.INSTALL_SUCCEEDED); + } catch (PackageManager.NameNotFoundException e) { + observer.packageInstalled(mAppInfo.packageName, + PackageManager.INSTALL_FAILED_INVALID_APK); + } + } else { + pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, + installerPackageName, verificationParams, null); + } } @Override diff --git a/src/com/android/packageinstaller/PackageInstallerActivity.java b/src/com/android/packageinstaller/PackageInstallerActivity.java index 8cf9967a..93a52dff 100644 --- a/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -25,7 +25,9 @@ import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageUserState; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.graphics.Rect; @@ -66,7 +68,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private Uri mReferrerURI; private boolean localLOGV = false; PackageManager mPm; - PackageParser.Package mPkgInfo; + PackageInfo mPkgInfo; ApplicationInfo mSourceInfo; // ApplicationInfo object primarily used for already existing applications @@ -438,12 +440,19 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); if (oldName != null && oldName.length > 0 && oldName[0] != null) { pkgName = oldName[0]; - mPkgInfo.setPackageName(pkgName); + mPkgInfo.packageName = pkgName; + mPkgInfo.applicationInfo.packageName = pkgName; } // Check if package is already installed. display confirmation dialog if replacing pkg try { + // This is a little convoluted because we want to get all uninstalled + // apps, but this may include apps with just data, and if it is just + // data we still want to count it as "installed". mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.GET_UNINSTALLED_PACKAGES); + if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { + mAppInfo = null; + } } catch (NameNotFoundException e) { mAppInfo = null; } @@ -469,27 +478,49 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mPm = getPackageManager(); final String scheme = mPackageURI.getScheme(); - if (scheme != null && !"file".equals(scheme)) { - throw new IllegalArgumentException("unexpected scheme " + scheme); + if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { + Log.w(TAG, "Unsupported scheme " + scheme); + setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); + return; } - final File sourceFile = new File(mPackageURI.getPath()); - mPkgInfo = PackageUtil.getPackageInfo(sourceFile); - - // Check for parse errors - if (mPkgInfo == null) { - Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); - showDialogInner(DLG_PACKAGE_ERROR); - setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); - return; + final PackageUtil.AppSnippet as; + if ("package".equals(mPackageURI.getScheme())) { + try { + mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), + PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); + } catch (NameNotFoundException e) { + } + if (mPkgInfo == null) { + Log.w(TAG, "Requested package " + mPackageURI.getScheme() + + " not available. Discontinuing installation"); + showDialogInner(DLG_PACKAGE_ERROR); + setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); + return; + } + as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), + mPm.getApplicationIcon(mPkgInfo.applicationInfo)); + } else { + final File sourceFile = new File(mPackageURI.getPath()); + PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); + + // Check for parse errors + if (parsed == null) { + Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); + showDialogInner(DLG_PACKAGE_ERROR); + setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); + return; + } + mPkgInfo = PackageParser.generatePackageInfo(parsed, null, + PackageManager.GET_PERMISSIONS, 0, 0, null, + new PackageUserState()); + as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); } //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); - final PackageUtil.AppSnippet as = PackageUtil.getAppSnippet( - this, mPkgInfo.applicationInfo, sourceFile); PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); // Deal with install source. -- cgit v1.2.3