diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 619d2c577..6d8d4361a 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -25,6 +25,7 @@ import android.widget.*; import org.fdroid.fdroid.data.*; import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.installer.Installer.AndroidNotCompatibleException; +import org.fdroid.fdroid.installer.Installer.InstallerCallback; import org.xml.sax.XMLReader; import android.app.AlertDialog; @@ -310,7 +311,8 @@ public class AppDetails extends ListActivity { } mPm = getPackageManager(); - installer = Installer.getActivityInstaller(this, mPm, myInstallerCallback); + installer = Installer.getActivityInstaller(this, mPm, + myInstallerCallback); // Get the preferences we're going to use in this Activity... AppDetails old = (AppDetails) getLastNonConfigurationInstance(); @@ -929,82 +931,80 @@ public class AppDetails extends ListActivity { downloadHandler = new DownloadHandler(apk, repoaddress, Utils.getApkCacheDir(getBaseContext())); } - private void installApk(File file, String packageName) { setProgressBarIndeterminateVisibility(true); - + try { installer.installPackage(file); } catch (AndroidNotCompatibleException e) { Log.e(TAG, "Android not compatible with this Installer!", e); } - - notifyAppChanged(packageName); } private void removeApk(String packageName) { setProgressBarIndeterminateVisibility(true); - + try { installer.deletePackage(packageName); } catch (AndroidNotCompatibleException e) { Log.e(TAG, "Android not compatible with this Installer!", e); } - - notifyAppChanged(packageName); - } + } /** - * We could probably drop this, and let the PackageReceiver take care of notifications - * for us, but I don't think the package receiver notifications are very instantaneous. + * We could probably drop this, and let the PackageReceiver take care of + * notifications for us, but I don't think the package receiver + * notifications are very instantaneous. */ private void notifyAppChanged(String id) { getContentResolver().notifyChange(AppProvider.getContentUri(id), null); } - - private Installer.InstallerCallback myInstallerCallback = new Installer.InstallerCallback() { + + Installer.InstallerCallback myInstallerCallback = new Installer.InstallerCallback() { @Override - public void onSuccess(int operation, boolean unattended) { - resetRequired = true; - - if (operation == Installer.InstallerCallback.OPERATION_INSTALL) { - if (downloadHandler != null) { - downloadHandler = null; - } - - PackageManagerCompat.setInstaller(mPm, app.id); - } - - // if unattended, onResume is not execute automatically -// if (unattended) { + public void onSuccess(final int operation) { runOnUiThread(new Runnable() { @Override public void run() { + Log.d(TAG, "handling installer onSuccess"); + + notifyAppChanged(app.id); + + resetRequired = true; + + if (operation == Installer.InstallerCallback.OPERATION_INSTALL) { + if (downloadHandler != null) { + downloadHandler = null; + } + + PackageManagerCompat.setInstaller(mPm, app.id); + } + + // TODO: whole onResume? onResume(); setProgressBarIndeterminateVisibility(false); } }); -// } - } @Override - public void onError(int operation, boolean unattended, final String reason) { - runOnUiThread(new Runnable() { - @Override - public void run() { - setProgressBarIndeterminateVisibility(false); - - // TODO - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this); - alertBuilder.setTitle("Error"); - alertBuilder.setMessage(reason); - alertBuilder.setNeutralButton(android.R.string.ok, null); - alertBuilder.create().show(); - } - }); - + public void onError(int operation, final int errorCode) { + if (errorCode != InstallerCallback.ERROR_CODE_CANCELED) { + runOnUiThread(new Runnable() { + @Override + public void run() { + setProgressBarIndeterminateVisibility(false); + + // TODO + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(AppDetails.this); + alertBuilder.setTitle("Error"); + alertBuilder.setMessage("errorCode: " + errorCode); + alertBuilder.setNeutralButton(android.R.string.ok, null); + alertBuilder.create().show(); + } + }); + } } }; diff --git a/src/org/fdroid/fdroid/compat/PackageManagerCompat.java b/src/org/fdroid/fdroid/compat/PackageManagerCompat.java index 714c5b144..5aa752c1f 100644 --- a/src/org/fdroid/fdroid/compat/PackageManagerCompat.java +++ b/src/org/fdroid/fdroid/compat/PackageManagerCompat.java @@ -9,12 +9,12 @@ import android.util.Log; public class PackageManagerCompat extends Compatibility { @TargetApi(11) - public static void setInstaller(PackageManager mPm, String app_id) { + public static void setInstaller(PackageManager mPm, String packageName) { if (!hasApi(11)) return; try { - mPm.setInstallerPackageName(app_id, "org.fdroid.fdroid"); + mPm.setInstallerPackageName(packageName, "org.fdroid.fdroid"); Log.d("FDroid", "Installer package name for " + - app_id + " set successfully"); + packageName + " set successfully"); } catch (Exception e) { // Many problems can occur: // * App wasn't installed due to incompatibility @@ -22,8 +22,8 @@ public class PackageManagerCompat extends Compatibility { // * Another app interfered in the process // * Another app already set the target's installer package // * ... - Log.d("FDroid", "Could not set installer package name for " + - app_id + ": " + e.getMessage()); + Log.e("FDroid", "Could not set installer package name for " + + packageName, e); } } diff --git a/src/org/fdroid/fdroid/installer/DefaultInstaller.java b/src/org/fdroid/fdroid/installer/DefaultInstaller.java index 1de5e3417..e9ae33ca0 100644 --- a/src/org/fdroid/fdroid/installer/DefaultInstaller.java +++ b/src/org/fdroid/fdroid/installer/DefaultInstaller.java @@ -59,7 +59,7 @@ public class DefaultInstaller extends Installer { // intent.setAction(Settings.ACTION_APPLICATION_SETTINGS); // startActivity(intent); // } - + @Override public void installPackage(File apkFile) throws AndroidNotCompatibleException { super.installPackage(apkFile); @@ -104,11 +104,11 @@ public class DefaultInstaller extends Installer { */ switch (requestCode) { case REQUEST_CODE_INSTALL: - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL, false); + mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); return true; case REQUEST_CODE_DELETE: - mCallback.onSuccess(InstallerCallback.OPERATION_DELETE, false); + mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); return true; default: diff --git a/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java b/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java index 8fbb97e7a..218a3242b 100644 --- a/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java +++ b/src/org/fdroid/fdroid/installer/DefaultInstallerSdk14.java @@ -21,6 +21,8 @@ package org.fdroid.fdroid.installer; import java.io.File; +import org.fdroid.fdroid.installer.Installer.InstallerCallback; + import android.annotation.TargetApi; import android.app.Activity; import android.content.ActivityNotFoundException; @@ -97,38 +99,82 @@ public class DefaultInstallerSdk14 extends Installer { } @Override - public boolean handleOnActivityResult(int requestCode, int resultCode, Intent data) { + public boolean handleOnActivityResult(final int requestCode, final int resultCode, Intent data) { /** * resultCode is always 0 on Android < 4.0. See * com.android.packageinstaller.PackageInstallerActivity: setResult is * never executed! */ - switch (requestCode) { - case REQUEST_CODE_INSTALL: - if (resultCode == Activity.RESULT_OK) { - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL, false); - } else if (resultCode == Activity.RESULT_CANCELED) { - // TODO - mCallback.onError(InstallerCallback.OPERATION_INSTALL, false, "canceled"); - } else { - mCallback.onError(InstallerCallback.OPERATION_INSTALL, false, "todo"); + // wait until Android's internal PackageManger has + // received the new package state + Thread wait = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { } - return true; - case REQUEST_CODE_DELETE: - if (resultCode == Activity.RESULT_OK) { - mCallback.onSuccess(InstallerCallback.OPERATION_DELETE, false); - } else if (resultCode == Activity.RESULT_CANCELED) { - // TODO - mCallback.onError(InstallerCallback.OPERATION_DELETE, false, "canceled"); - } else { - mCallback.onError(InstallerCallback.OPERATION_DELETE, false, "todo"); - } + switch (requestCode) { + case REQUEST_CODE_INSTALL: + if (resultCode == Activity.RESULT_OK) { + mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); + } else if (resultCode == Activity.RESULT_CANCELED) { + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_CANCELED); + } else { + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); + } - return true; - default: - return false; - } + // return true; + case REQUEST_CODE_DELETE: + if (resultCode == Activity.RESULT_OK) { + mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); + } else if (resultCode == Activity.RESULT_CANCELED) { + mCallback.onError(InstallerCallback.OPERATION_DELETE, + InstallerCallback.ERROR_CODE_CANCELED); + } else { + mCallback.onError(InstallerCallback.OPERATION_DELETE, + InstallerCallback.ERROR_CODE_OTHER); + } + + // return true; + default: + // return false; + } + } + }); + wait.start(); + return true; + + // case REQUEST_CODE_INSTALL: + // if (resultCode == Activity.RESULT_OK) { + // mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); + // } else if (resultCode == Activity.RESULT_CANCELED) { + // mCallback.onError(InstallerCallback.OPERATION_INSTALL, + // InstallerCallback.ERROR_CODE_CANCELED); + // } else { + // mCallback.onError(InstallerCallback.OPERATION_INSTALL, + // InstallerCallback.ERROR_CODE_OTHER); + // } + // + // return true; + // case REQUEST_CODE_DELETE: + // if (resultCode == Activity.RESULT_OK) { + // mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); + // } else if (resultCode == Activity.RESULT_CANCELED) { + // mCallback.onError(InstallerCallback.OPERATION_DELETE, + // InstallerCallback.ERROR_CODE_CANCELED); + // } else { + // mCallback.onError(InstallerCallback.OPERATION_DELETE, + // InstallerCallback.ERROR_CODE_OTHER); + // } + // + // return true; + // default: + // return false; + // } } @Override diff --git a/src/org/fdroid/fdroid/installer/Installer.java b/src/org/fdroid/fdroid/installer/Installer.java index 425b4c579..f2e185376 100644 --- a/src/org/fdroid/fdroid/installer/Installer.java +++ b/src/org/fdroid/fdroid/installer/Installer.java @@ -77,10 +77,13 @@ abstract public class Installer { public static final int OPERATION_INSTALL = 1; public static final int OPERATION_DELETE = 2; + + public static final int ERROR_CODE_CANCELED = 1; + public static final int ERROR_CODE_OTHER = 2; - public void onSuccess(int operation, boolean unattended); + public void onSuccess(int operation); - public void onError(int operation, boolean unattended, String reason); + public void onError(int operation, int errorCode); } public Installer(Context context, PackageManager pm, InstallerCallback callback) diff --git a/src/org/fdroid/fdroid/installer/RootInstaller.java b/src/org/fdroid/fdroid/installer/RootInstaller.java index 3c62d71a1..04380428f 100644 --- a/src/org/fdroid/fdroid/installer/RootInstaller.java +++ b/src/org/fdroid/fdroid/installer/RootInstaller.java @@ -27,6 +27,7 @@ import eu.chainfire.libsuperuser.Shell; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.util.Log; /** * Installer using a root shell and "pm install", "pm uninstall" commands @@ -67,9 +68,9 @@ public class RootInstaller extends Installer { // exec failed // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - // TODO - mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, - "Error opening root shell with exitCode " + exitCode); + Log.e(TAG, "Error opening root shell with exitCode " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); } else { addInstallCommand(apkFile); } @@ -94,9 +95,9 @@ public class RootInstaller extends Installer { // exec failed // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - // TODO - mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, - "Error opening root shell with exitCode " + exitCode); + Log.e(TAG, "Error opening root shell with exitCode " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); } else { addInstallCommand(apkFiles); } @@ -121,9 +122,9 @@ public class RootInstaller extends Installer { // exec failed // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - // TODO - mCallback.onError(InstallerCallback.OPERATION_DELETE, true, - "Error opening root shell with exitCode " + exitCode); + Log.e(TAG, "Error opening root shell with exitCode " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_DELETE, + InstallerCallback.ERROR_CODE_OTHER); } else { addDeleteCommand(packageName); } @@ -153,9 +154,9 @@ public class RootInstaller extends Installer { rootSession.close(); if (exitCode < 0) { - // TODO - mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, - "Install failed with exit code " + exitCode); + Log.e(TAG, "Install failed with exit code " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); } else { // wait until Android's internal PackageManger // has received the new package state @@ -167,9 +168,7 @@ public class RootInstaller extends Installer { } catch (InterruptedException e) { } - mCallback.onSuccess( - InstallerCallback.OPERATION_INSTALL, - true); + mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); } }); wait.start(); @@ -187,9 +186,9 @@ public class RootInstaller extends Installer { rootSession.close(); if (exitCode < 0) { - // TODO - mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, - "Install failed with exit code " + exitCode); + Log.e(TAG, "Install failed with exit code " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); } else { // wait until Android's internal PackageManger has // received the new package state @@ -201,7 +200,7 @@ public class RootInstaller extends Installer { } catch (InterruptedException e) { } - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL, true); + mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); } }); wait.start(); @@ -218,9 +217,9 @@ public class RootInstaller extends Installer { rootSession.close(); if (exitCode < 0) { - // TODO - mCallback.onError(InstallerCallback.OPERATION_DELETE, true, - "Delete failed with exit code " + exitCode); + Log.e(TAG, "Delete failed with exit code " + exitCode); + mCallback.onError(InstallerCallback.OPERATION_DELETE, + InstallerCallback.ERROR_CODE_OTHER); } else { // wait until Android's internal PackageManger has // received the new package state @@ -232,7 +231,7 @@ public class RootInstaller extends Installer { } catch (InterruptedException e) { } - mCallback.onSuccess(InstallerCallback.OPERATION_DELETE, true); + mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); } }); wait.start(); diff --git a/src/org/fdroid/fdroid/installer/SystemPermissionInstaller.java b/src/org/fdroid/fdroid/installer/SystemPermissionInstaller.java index 754924c9a..a3fdb905e 100644 --- a/src/org/fdroid/fdroid/installer/SystemPermissionInstaller.java +++ b/src/org/fdroid/fdroid/installer/SystemPermissionInstaller.java @@ -106,13 +106,14 @@ public class SystemPermissionInstaller extends Installer { } catch (InterruptedException e) { } - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL, true); + mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); } }); wait.start(); } else { - Log.d(TAG, "Install failed: " + returnCode); - mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, "todo"); + Log.e(TAG, "Install failed with returnCode " + returnCode); + mCallback.onError(InstallerCallback.OPERATION_INSTALL, + InstallerCallback.ERROR_CODE_OTHER); } } } @@ -136,13 +137,14 @@ public class SystemPermissionInstaller extends Installer { } catch (InterruptedException e) { } - mCallback.onSuccess(InstallerCallback.OPERATION_DELETE, true); + mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); } }); wait.start(); } else { - Log.d(TAG, "Delete failed: " + returnCode); - mCallback.onError(InstallerCallback.OPERATION_DELETE, true, "todo"); + Log.e(TAG, "Delete failed with returnCode " + returnCode); + mCallback.onError(InstallerCallback.OPERATION_DELETE, + InstallerCallback.ERROR_CODE_OTHER); } } }