Loading res/values/strings.xml +18 −32 Original line number Diff line number Diff line Loading @@ -48,41 +48,27 @@ to this built-in application? Your existing data will not be lost. It does not require any special access.</string> <string name="install_failed">App not installed.</string> <!-- Reason displayed when installation fails because the installation package itself is invalid in some way (e.g., corrupt) [CHAR LIMIT=100] --> <string name="install_failed_invalid_apk">The package appears to be corrupt.</string> <!-- Reason displayed when installation fails because the package an existing package is installed with a conflicting package author signature [CHAR LIMIT=100] --> <string name="install_failed_inconsistent_certificates">An existing package by the same name with a conflicting signature is already installed.</string> <!-- Reason displayed when installation fails because the package specifies a minimum compatible OS version that is newer than our current OS version. [CHAR LIMIT=100] --> <string name="install_failed_older_sdk">The package only works on newer versions of Android.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current tablet doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="tablet">This app isn\'t <!-- Reason displayed when installation fails because the package was blocked from being installed (e.g., device policy, verification, ...) [CHAR LIMIT=100] --> <string name="install_failed_blocked">The package was blocked from being installed.</string> <!-- Reason displayed when installation fails because the package conflicts with an existing application (e.g., incompatible certificates) [CHAR LIMIT=100] --> <string name="install_failed_conflict">The package conflicts with an existing package by the same name.</string> <!-- Reason displayed when installation fails because the package is incompatible with the current tablet (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="tablet">This app isn\'t compatible with your tablet.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current TV doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="tv">This app isn\'t <!-- Reason displayed when installation fails because the package is incompatible with the current TV (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="tv">This app isn\'t compatible with your TV.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current phone doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="default">This app isn\'t <!-- Reason displayed when installation fails because the package is incompatible with the current phone (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="default">This app isn\'t compatible with your phone.</string> <!-- Reason displayed when installation fails because the package was deleted during the installation process. [CHAR LIMIT=100] --> <string name="install_failed_file_not_found">The package specified was deleted before installation could be completed.</string> <!-- Reason displayed when installation fails because the package could not be verified because the package verifier rejected it. [CHAR LIMIT=100] --> <string name="install_failed_verify_failed">The package did not pass verification and cannot be installed.</string> <!-- Reason displayed when installation fails because the package could not be verified before the internal system timer expired. [CHAR LIMIT=100] --> <string name="install_failed_verify_timeout">A timeout occurred while trying to verify this package. Try to install it again later.</string> <!-- Reason displayed when installation fails because the installation package itself is invalid in some way (e.g., corrupt) [CHAR LIMIT=100] --> <string name="install_failed_invalid_apk">The package appears to be corrupt.</string> <!-- Message presented when an application could not be installed on the tablet for some reason. [CHAR LIMIT=100] --> <string name="install_failed_msg" product="tablet"><xliff:g id="app_name">%1$s</xliff:g> couldn\'t be installed on your tablet.</string> <!-- Message presented when an application could not be installed on the TV for some reason. [CHAR LIMIT=100] --> Loading src/com/android/packageinstaller/InstallAppProgress.java +137 −47 Original line number Diff line number Diff line Loading @@ -16,16 +16,21 @@ */ package com.android.packageinstaller; import static android.content.pm.PackageInstaller.SessionParams.UID_UNKNOWN; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageInstallObserver; import android.content.pm.ManifestDigest; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; Loading @@ -34,6 +39,7 @@ import android.graphics.drawable.LevelListDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.util.Log; import android.view.View; Loading @@ -41,7 +47,13 @@ import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; /** Loading @@ -54,11 +66,14 @@ import java.util.List; */ public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener { private final String TAG="InstallAppProgress"; private boolean localLOGV = false; static final String EXTRA_MANIFEST_DIGEST = "com.android.packageinstaller.extras.manifest_digest"; static final String EXTRA_INSTALL_FLOW_ANALYTICS = "com.android.packageinstaller.extras.install_flow_analytics"; private static final String BROADCAST_ACTION = "com.android.packageinstaller.ACTION_INSTALL_COMMIT"; private static final String BROADCAST_SENDER_PERMISSION = "android.permission.INSTALL_PACKAGES"; private ApplicationInfo mAppInfo; private Uri mPackageURI; private InstallFlowAnalytics mInstallFlowAnalytics; Loading @@ -72,6 +87,8 @@ public class InstallAppProgress extends Activity implements View.OnClickListener private Intent mLaunchIntent; private static final int DLG_OUT_OF_SPACE = 1; private CharSequence mLabel; private HandlerThread mInstallThread; private Handler mInstallHandler; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { Loading @@ -81,7 +98,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { Intent result = new Intent(); result.putExtra(Intent.EXTRA_INSTALL_RESULT, msg.arg1); setResult(msg.arg1 == PackageManager.INSTALL_SUCCEEDED setResult(msg.arg1 == PackageInstaller.STATUS_SUCCESS ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER, result); finish(); Loading @@ -94,7 +111,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener int centerExplanationLabel = -1; LevelListDrawable centerTextDrawable = (LevelListDrawable) getDrawable(R.drawable.ic_result_status); if (msg.arg1 == PackageManager.INSTALL_SUCCEEDED) { if (msg.arg1 == PackageInstaller.STATUS_SUCCESS) { mLaunchButton.setVisibility(View.VISIBLE); centerTextDrawable.setLevel(0); centerTextLabel = R.string.install_done; Loading @@ -114,7 +131,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener } else { mLaunchButton.setEnabled(false); } } else if (msg.arg1 == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){ } else if (msg.arg1 == PackageInstaller.STATUS_FAILURE_STORAGE){ showDialogInner(DLG_OUT_OF_SPACE); return; } else { Loading Loading @@ -147,17 +164,30 @@ public class InstallAppProgress extends Activity implements View.OnClickListener } }; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int statusCode = intent.getIntExtra( PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); if (statusCode == PackageInstaller.STATUS_PENDING_USER_ACTION) { context.startActivity((Intent)intent.getParcelableExtra(Intent.EXTRA_INTENT)); } else { onPackageInstalled(statusCode); } } }; private int getExplanationFromErrorCode(int errCode) { Log.d(TAG, "Installation error code: " + errCode); switch (errCode) { case PackageManager.INSTALL_FAILED_INVALID_APK: case PackageInstaller.STATUS_FAILURE_BLOCKED: return R.string.install_failed_blocked; case PackageInstaller.STATUS_FAILURE_CONFLICT: return R.string.install_failed_conflict; case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: return R.string.install_failed_incompatible; case PackageInstaller.STATUS_FAILURE_INVALID: return R.string.install_failed_invalid_apk; case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return R.string.install_failed_inconsistent_certificates; case PackageManager.INSTALL_FAILED_OLDER_SDK: return R.string.install_failed_older_sdk; case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return R.string.install_failed_cpu_abi_incompatible; default: return -1; } Loading @@ -179,9 +209,19 @@ public class InstallAppProgress extends Activity implements View.OnClickListener throw new IllegalArgumentException("unexpected scheme " + scheme); } mInstallThread = new HandlerThread("InstallThread"); mInstallThread.start(); mInstallHandler = new Handler(mInstallThread.getLooper()); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BROADCAST_ACTION); registerReceiver( mBroadcastReceiver, intentFilter, BROADCAST_SENDER_PERMISSION, null /*scheduler*/); initView(); } @SuppressWarnings("deprecation") @Override public Dialog onCreateDialog(int id, Bundle bundle) { switch (id) { Loading Loading @@ -210,36 +250,85 @@ public class InstallAppProgress extends Activity implements View.OnClickListener return null; } @SuppressWarnings("deprecation") private void showDialogInner(int id) { removeDialog(id); showDialog(id); } class PackageInstallObserver extends IPackageInstallObserver.Stub { public void packageInstalled(String packageName, int returnCode) { void onPackageInstalled(int statusCode) { Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); msg.arg1 = returnCode; msg.arg1 = statusCode; mHandler.sendMessage(msg); } } public void initView() { setContentView(R.layout.op_progress); int installFlags = 0; int getInstallFlags(String packageName) { PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); if (pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; return PackageManager.INSTALL_REPLACE_EXISTING; } } catch (NameNotFoundException e) { } if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { Log.w(TAG, "Replacing package:" + mAppInfo.packageName); return 0; } private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) { final PackageInstaller packageInstaller = pm.getPackageInstaller(); PackageInstaller.Session session = null; try { final String packageLocation = mPackageURI.getPath(); final File file = new File(packageLocation); final int sessionId = packageInstaller.createSession(params); final byte[] buffer = new byte[65536]; session = packageInstaller.openSession(sessionId); final InputStream in = new FileInputStream(file); final long sizeBytes = file.length(); final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes); try { int c; while ((c = in.read(buffer)) != -1) { out.write(buffer, 0, c); if (sizeBytes > 0) { final float fraction = ((float) c / (float) sizeBytes); session.addProgress(fraction); } } session.fsync(out); } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); } // Create a PendingIntent and use it to generate the IntentSender Intent broadcastIntent = new Intent(BROADCAST_ACTION); PendingIntent pendingIntent = PendingIntent.getBroadcast( InstallAppProgress.this /*context*/, sessionId, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); } catch (IOException e) { onPackageInstalled(PackageInstaller.STATUS_FAILURE); } finally { IoUtils.closeQuietly(session); } } void initView() { setContentView(R.layout.op_progress); final PackageUtil.AppSnippet as; final PackageManager pm = getPackageManager(); final int installFlags = getInstallFlags(mAppInfo.packageName); if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { Log.w(TAG, "Replacing package:" + mAppInfo.packageName); } if ("package".equals(mPackageURI.getScheme())) { as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo), pm.getApplicationIcon(mAppInfo)); Loading @@ -255,40 +344,41 @@ public class InstallAppProgress extends Activity implements View.OnClickListener mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); mProgressBar.setIndeterminate(true); // Hide button till progress is being displayed mOkPanel = (View)findViewById(R.id.buttons_panel); mOkPanel = findViewById(R.id.buttons_panel); mDoneButton = (Button)findViewById(R.id.done_button); mLaunchButton = (Button)findViewById(R.id.launch_button); mOkPanel.setVisibility(View.INVISIBLE); String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); int originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, VerificationParams.NO_UID); ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST); VerificationParams verificationParams = new VerificationParams(null, originatingURI, referrer, originatingUid, manifestDigest); PackageInstallObserver observer = new PackageInstallObserver(); if ("package".equals(mPackageURI.getScheme())) { try { pm.installExistingPackage(mAppInfo.packageName); observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_SUCCEEDED); onPackageInstalled(PackageInstaller.STATUS_SUCCESS); } catch (PackageManager.NameNotFoundException e) { observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_FAILED_INVALID_APK); onPackageInstalled(PackageInstaller.STATUS_FAILURE_INVALID); } } else { pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, installerPackageName, verificationParams, null); final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); params.originatingUri = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, UID_UNKNOWN); params.setInstallFlagsForcePermissionPrompt(); mInstallHandler.post(new Runnable() { @Override public void run() { doPackageStage(pm, params); } }); } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mBroadcastReceiver); mInstallThread.getLooper().quitSafely(); } public void onClick(View v) { Loading src/com/android/packageinstaller/PackageInstallerActivity.java +8 −2 Original line number Diff line number Diff line Loading @@ -438,7 +438,13 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mInstallFlowAnalytics.setSystemApp( (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)); // If we have a session id, we're invoked to verify the permissions for the given // package. Otherwise, we start the install process. if (mSessionId != -1) { startInstallConfirm(); } else { startInstall(); } } void setPmResult(int pmResult) { Loading Loading
res/values/strings.xml +18 −32 Original line number Diff line number Diff line Loading @@ -48,41 +48,27 @@ to this built-in application? Your existing data will not be lost. It does not require any special access.</string> <string name="install_failed">App not installed.</string> <!-- Reason displayed when installation fails because the installation package itself is invalid in some way (e.g., corrupt) [CHAR LIMIT=100] --> <string name="install_failed_invalid_apk">The package appears to be corrupt.</string> <!-- Reason displayed when installation fails because the package an existing package is installed with a conflicting package author signature [CHAR LIMIT=100] --> <string name="install_failed_inconsistent_certificates">An existing package by the same name with a conflicting signature is already installed.</string> <!-- Reason displayed when installation fails because the package specifies a minimum compatible OS version that is newer than our current OS version. [CHAR LIMIT=100] --> <string name="install_failed_older_sdk">The package only works on newer versions of Android.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current tablet doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="tablet">This app isn\'t <!-- Reason displayed when installation fails because the package was blocked from being installed (e.g., device policy, verification, ...) [CHAR LIMIT=100] --> <string name="install_failed_blocked">The package was blocked from being installed.</string> <!-- Reason displayed when installation fails because the package conflicts with an existing application (e.g., incompatible certificates) [CHAR LIMIT=100] --> <string name="install_failed_conflict">The package conflicts with an existing package by the same name.</string> <!-- Reason displayed when installation fails because the package is incompatible with the current tablet (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="tablet">This app isn\'t compatible with your tablet.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current TV doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="tv">This app isn\'t <!-- Reason displayed when installation fails because the package is incompatible with the current TV (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="tv">This app isn\'t compatible with your TV.</string> <!-- Reason displayed when installation fails because the package specifies it is compatible only with a CPU that the current phone doesn't have. [CHAR LIMIT=100] --> <string name="install_failed_cpu_abi_incompatible" product="default">This app isn\'t <!-- Reason displayed when installation fails because the package is incompatible with the current phone (e.g., missing native code for the current ABI, newer SDK, ...) [CHAR LIMIT=100] --> <string name="install_failed_incompatible" product="default">This app isn\'t compatible with your phone.</string> <!-- Reason displayed when installation fails because the package was deleted during the installation process. [CHAR LIMIT=100] --> <string name="install_failed_file_not_found">The package specified was deleted before installation could be completed.</string> <!-- Reason displayed when installation fails because the package could not be verified because the package verifier rejected it. [CHAR LIMIT=100] --> <string name="install_failed_verify_failed">The package did not pass verification and cannot be installed.</string> <!-- Reason displayed when installation fails because the package could not be verified before the internal system timer expired. [CHAR LIMIT=100] --> <string name="install_failed_verify_timeout">A timeout occurred while trying to verify this package. Try to install it again later.</string> <!-- Reason displayed when installation fails because the installation package itself is invalid in some way (e.g., corrupt) [CHAR LIMIT=100] --> <string name="install_failed_invalid_apk">The package appears to be corrupt.</string> <!-- Message presented when an application could not be installed on the tablet for some reason. [CHAR LIMIT=100] --> <string name="install_failed_msg" product="tablet"><xliff:g id="app_name">%1$s</xliff:g> couldn\'t be installed on your tablet.</string> <!-- Message presented when an application could not be installed on the TV for some reason. [CHAR LIMIT=100] --> Loading
src/com/android/packageinstaller/InstallAppProgress.java +137 −47 Original line number Diff line number Diff line Loading @@ -16,16 +16,21 @@ */ package com.android.packageinstaller; import static android.content.pm.PackageInstaller.SessionParams.UID_UNKNOWN; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageInstallObserver; import android.content.pm.ManifestDigest; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; Loading @@ -34,6 +39,7 @@ import android.graphics.drawable.LevelListDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.util.Log; import android.view.View; Loading @@ -41,7 +47,13 @@ import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import libcore.io.IoUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; /** Loading @@ -54,11 +66,14 @@ import java.util.List; */ public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener { private final String TAG="InstallAppProgress"; private boolean localLOGV = false; static final String EXTRA_MANIFEST_DIGEST = "com.android.packageinstaller.extras.manifest_digest"; static final String EXTRA_INSTALL_FLOW_ANALYTICS = "com.android.packageinstaller.extras.install_flow_analytics"; private static final String BROADCAST_ACTION = "com.android.packageinstaller.ACTION_INSTALL_COMMIT"; private static final String BROADCAST_SENDER_PERMISSION = "android.permission.INSTALL_PACKAGES"; private ApplicationInfo mAppInfo; private Uri mPackageURI; private InstallFlowAnalytics mInstallFlowAnalytics; Loading @@ -72,6 +87,8 @@ public class InstallAppProgress extends Activity implements View.OnClickListener private Intent mLaunchIntent; private static final int DLG_OUT_OF_SPACE = 1; private CharSequence mLabel; private HandlerThread mInstallThread; private Handler mInstallHandler; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { Loading @@ -81,7 +98,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { Intent result = new Intent(); result.putExtra(Intent.EXTRA_INSTALL_RESULT, msg.arg1); setResult(msg.arg1 == PackageManager.INSTALL_SUCCEEDED setResult(msg.arg1 == PackageInstaller.STATUS_SUCCESS ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER, result); finish(); Loading @@ -94,7 +111,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener int centerExplanationLabel = -1; LevelListDrawable centerTextDrawable = (LevelListDrawable) getDrawable(R.drawable.ic_result_status); if (msg.arg1 == PackageManager.INSTALL_SUCCEEDED) { if (msg.arg1 == PackageInstaller.STATUS_SUCCESS) { mLaunchButton.setVisibility(View.VISIBLE); centerTextDrawable.setLevel(0); centerTextLabel = R.string.install_done; Loading @@ -114,7 +131,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener } else { mLaunchButton.setEnabled(false); } } else if (msg.arg1 == PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE){ } else if (msg.arg1 == PackageInstaller.STATUS_FAILURE_STORAGE){ showDialogInner(DLG_OUT_OF_SPACE); return; } else { Loading Loading @@ -147,17 +164,30 @@ public class InstallAppProgress extends Activity implements View.OnClickListener } }; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int statusCode = intent.getIntExtra( PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); if (statusCode == PackageInstaller.STATUS_PENDING_USER_ACTION) { context.startActivity((Intent)intent.getParcelableExtra(Intent.EXTRA_INTENT)); } else { onPackageInstalled(statusCode); } } }; private int getExplanationFromErrorCode(int errCode) { Log.d(TAG, "Installation error code: " + errCode); switch (errCode) { case PackageManager.INSTALL_FAILED_INVALID_APK: case PackageInstaller.STATUS_FAILURE_BLOCKED: return R.string.install_failed_blocked; case PackageInstaller.STATUS_FAILURE_CONFLICT: return R.string.install_failed_conflict; case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: return R.string.install_failed_incompatible; case PackageInstaller.STATUS_FAILURE_INVALID: return R.string.install_failed_invalid_apk; case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: return R.string.install_failed_inconsistent_certificates; case PackageManager.INSTALL_FAILED_OLDER_SDK: return R.string.install_failed_older_sdk; case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: return R.string.install_failed_cpu_abi_incompatible; default: return -1; } Loading @@ -179,9 +209,19 @@ public class InstallAppProgress extends Activity implements View.OnClickListener throw new IllegalArgumentException("unexpected scheme " + scheme); } mInstallThread = new HandlerThread("InstallThread"); mInstallThread.start(); mInstallHandler = new Handler(mInstallThread.getLooper()); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BROADCAST_ACTION); registerReceiver( mBroadcastReceiver, intentFilter, BROADCAST_SENDER_PERMISSION, null /*scheduler*/); initView(); } @SuppressWarnings("deprecation") @Override public Dialog onCreateDialog(int id, Bundle bundle) { switch (id) { Loading Loading @@ -210,36 +250,85 @@ public class InstallAppProgress extends Activity implements View.OnClickListener return null; } @SuppressWarnings("deprecation") private void showDialogInner(int id) { removeDialog(id); showDialog(id); } class PackageInstallObserver extends IPackageInstallObserver.Stub { public void packageInstalled(String packageName, int returnCode) { void onPackageInstalled(int statusCode) { Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); msg.arg1 = returnCode; msg.arg1 = statusCode; mHandler.sendMessage(msg); } } public void initView() { setContentView(R.layout.op_progress); int installFlags = 0; int getInstallFlags(String packageName) { PackageManager pm = getPackageManager(); try { PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); if (pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; return PackageManager.INSTALL_REPLACE_EXISTING; } } catch (NameNotFoundException e) { } if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { Log.w(TAG, "Replacing package:" + mAppInfo.packageName); return 0; } private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) { final PackageInstaller packageInstaller = pm.getPackageInstaller(); PackageInstaller.Session session = null; try { final String packageLocation = mPackageURI.getPath(); final File file = new File(packageLocation); final int sessionId = packageInstaller.createSession(params); final byte[] buffer = new byte[65536]; session = packageInstaller.openSession(sessionId); final InputStream in = new FileInputStream(file); final long sizeBytes = file.length(); final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes); try { int c; while ((c = in.read(buffer)) != -1) { out.write(buffer, 0, c); if (sizeBytes > 0) { final float fraction = ((float) c / (float) sizeBytes); session.addProgress(fraction); } } session.fsync(out); } finally { IoUtils.closeQuietly(in); IoUtils.closeQuietly(out); } // Create a PendingIntent and use it to generate the IntentSender Intent broadcastIntent = new Intent(BROADCAST_ACTION); PendingIntent pendingIntent = PendingIntent.getBroadcast( InstallAppProgress.this /*context*/, sessionId, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); } catch (IOException e) { onPackageInstalled(PackageInstaller.STATUS_FAILURE); } finally { IoUtils.closeQuietly(session); } } void initView() { setContentView(R.layout.op_progress); final PackageUtil.AppSnippet as; final PackageManager pm = getPackageManager(); final int installFlags = getInstallFlags(mAppInfo.packageName); if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { Log.w(TAG, "Replacing package:" + mAppInfo.packageName); } if ("package".equals(mPackageURI.getScheme())) { as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo), pm.getApplicationIcon(mAppInfo)); Loading @@ -255,40 +344,41 @@ public class InstallAppProgress extends Activity implements View.OnClickListener mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); mProgressBar.setIndeterminate(true); // Hide button till progress is being displayed mOkPanel = (View)findViewById(R.id.buttons_panel); mOkPanel = findViewById(R.id.buttons_panel); mDoneButton = (Button)findViewById(R.id.done_button); mLaunchButton = (Button)findViewById(R.id.launch_button); mOkPanel.setVisibility(View.INVISIBLE); String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); int originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, VerificationParams.NO_UID); ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST); VerificationParams verificationParams = new VerificationParams(null, originatingURI, referrer, originatingUid, manifestDigest); PackageInstallObserver observer = new PackageInstallObserver(); if ("package".equals(mPackageURI.getScheme())) { try { pm.installExistingPackage(mAppInfo.packageName); observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_SUCCEEDED); onPackageInstalled(PackageInstaller.STATUS_SUCCESS); } catch (PackageManager.NameNotFoundException e) { observer.packageInstalled(mAppInfo.packageName, PackageManager.INSTALL_FAILED_INVALID_APK); onPackageInstalled(PackageInstaller.STATUS_FAILURE_INVALID); } } else { pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, installerPackageName, verificationParams, null); final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); params.originatingUri = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, UID_UNKNOWN); params.setInstallFlagsForcePermissionPrompt(); mInstallHandler.post(new Runnable() { @Override public void run() { doPackageStage(pm, params); } }); } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mBroadcastReceiver); mInstallThread.getLooper().quitSafely(); } public void onClick(View v) { Loading
src/com/android/packageinstaller/PackageInstallerActivity.java +8 −2 Original line number Diff line number Diff line Loading @@ -438,7 +438,13 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mInstallFlowAnalytics.setSystemApp( (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)); // If we have a session id, we're invoked to verify the permissions for the given // package. Otherwise, we start the install process. if (mSessionId != -1) { startInstallConfirm(); } else { startInstall(); } } void setPmResult(int pmResult) { Loading