Merge branch 'InstallManagerService-completion' into 'master'

InstallManagerService completion

This is a collection of fixes to finalize `InstallManagerService` now that !300 is merged.

See merge request !318
This commit is contained in:
Dominik 2016-06-01 22:23:50 +00:00
commit de238f3f5f
10 changed files with 128 additions and 131 deletions

View File

@ -85,14 +85,13 @@ import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.InstalledAppProvider;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.installer.InstallerFactory;
import org.fdroid.fdroid.installer.InstallerService;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
import java.io.File;
import java.util.Iterator;
import java.util.List;
@ -530,11 +529,8 @@ public class AppDetails extends AppCompatActivity {
@Override
public void onReceive(Context context, Intent intent) {
cleanUpFinishedDownload();
Uri localUri =
Uri.fromFile(new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH)));
localBroadcastManager.registerReceiver(installReceiver,
Installer.getInstallIntentFilter(localUri));
Installer.getInstallIntentFilter(intent.getData()));
}
};

View File

@ -45,34 +45,34 @@ public class DefaultInstaller extends Installer {
}
@Override
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
Utils.debugLog(TAG, "DefaultInstaller uri: " + uri + " file: " + new File(uri.getPath()));
Utils.debugLog(TAG, "DefaultInstaller uri: " + localApkUri + " file: " + new File(localApkUri.getPath()));
Uri sanitizedUri;
try {
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
} catch (Installer.InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
e.getMessage());
return;
}
Intent installIntent = new Intent(context, DefaultInstallerActivity.class);
installIntent.setAction(DefaultInstallerActivity.ACTION_INSTALL_PACKAGE);
installIntent.putExtra(DefaultInstallerActivity.EXTRA_ORIGINATING_URI, originatingUri);
installIntent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
installIntent.setData(sanitizedUri);
PendingIntent installPendingIntent = PendingIntent.getActivity(
context.getApplicationContext(),
uri.hashCode(),
localApkUri.hashCode(),
installIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
sendBroadcastInstall(uri, originatingUri,
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_USER_INTERACTION,
installPendingIntent);
}
@Override

View File

@ -38,18 +38,15 @@ import org.fdroid.fdroid.R;
public class DefaultInstallerActivity extends FragmentActivity {
public static final String TAG = "AndroidInstallerAct";
public static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.INSTALL_PACKAGE";
public static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.UNINSTALL_PACKAGE";
static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE";
static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_PACKAGE";
public static final String EXTRA_UNINSTALL_PACKAGE_NAME = "uninstallPackageName";
public static final String EXTRA_ORIGINATING_URI = "originatingUri";
static final String EXTRA_UNINSTALL_PACKAGE_NAME = "org.fdroid.fdroid.installer.DefaultInstaller.extra.UNINSTALL_PACKAGE_NAME";
private static final int REQUEST_CODE_INSTALL = 0;
private static final int REQUEST_CODE_UNINSTALL = 1;
private Uri installOriginatingUri;
private Uri installUri;
private Uri downloadUri;
private String uninstallPackageName;
// for the broadcasts
@ -64,10 +61,9 @@ public class DefaultInstallerActivity extends FragmentActivity {
Intent intent = getIntent();
String action = intent.getAction();
if (ACTION_INSTALL_PACKAGE.equals(action)) {
installUri = intent.getData();
installOriginatingUri = intent.getParcelableExtra(EXTRA_ORIGINATING_URI);
installPackage(installUri, installOriginatingUri);
Uri localApkUri = intent.getData();
downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
installPackage(localApkUri);
} else if (ACTION_UNINSTALL_PACKAGE.equals(action)) {
uninstallPackageName = intent.getStringExtra(EXTRA_UNINSTALL_PACKAGE_NAME);
@ -78,7 +74,7 @@ public class DefaultInstallerActivity extends FragmentActivity {
}
@SuppressLint("InlinedApi")
private void installPackage(Uri uri, Uri originatingUri) {
private void installPackage(Uri uri) {
if (uri == null) {
throw new RuntimeException("Set the data uri to point to an apk location!");
}
@ -121,12 +117,11 @@ public class DefaultInstallerActivity extends FragmentActivity {
startActivityForResult(intent, REQUEST_CODE_INSTALL);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "ActivityNotFoundException", e);
installer.sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
"This Android rom does not support ACTION_INSTALL_PACKAGE!");
finish();
}
installer.sendBroadcastInstall(installUri, installOriginatingUri,
Installer.ACTION_INSTALL_STARTED);
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
}
protected void uninstallPackage(String packageName) {
@ -172,31 +167,29 @@ public class DefaultInstallerActivity extends FragmentActivity {
* never executed on Androids < 4.0
*/
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
installer.sendBroadcastInstall(installUri, installOriginatingUri,
Installer.ACTION_INSTALL_COMPLETE);
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
break;
}
// Fallback on N for https://gitlab.com/fdroid/fdroidclient/issues/631
if ("N".equals(Build.VERSION.CODENAME)) {
installer.sendBroadcastInstall(installUri, installOriginatingUri,
Installer.ACTION_INSTALL_COMPLETE);
installer.sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
break;
}
switch (resultCode) {
case Activity.RESULT_OK:
installer.sendBroadcastInstall(installUri, installOriginatingUri,
installer.sendBroadcastInstall(downloadUri,
Installer.ACTION_INSTALL_COMPLETE);
break;
case Activity.RESULT_CANCELED:
installer.sendBroadcastInstall(installUri, installOriginatingUri,
installer.sendBroadcastInstall(downloadUri,
Installer.ACTION_INSTALL_INTERRUPTED);
break;
case Activity.RESULT_FIRST_USER:
default:
// AOSP returns Activity.RESULT_FIRST_USER on error
installer.sendBroadcastInstall(installUri, installOriginatingUri,
installer.sendBroadcastInstall(downloadUri,
Installer.ACTION_INSTALL_INTERRUPTED,
getString(R.string.install_error_unknown));
break;

View File

@ -46,14 +46,13 @@ public class ExtensionInstaller extends Installer {
}
@Override
protected void installPackage(Uri uri, Uri originatingUri, String packageName) {
protected void installPackage(Uri localApkUri, Uri downloadUri, String packageName) {
Uri sanitizedUri;
try {
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
} catch (InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
e.getMessage());
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED, e.getMessage());
return;
}
@ -61,7 +60,7 @@ public class ExtensionInstaller extends Installer {
// NOTE: Disabled for debug builds to be able to use official extension from repo
ApkSignatureVerifier signatureVerifier = new ApkSignatureVerifier(context);
if (!BuildConfig.DEBUG && !signatureVerifier.hasFDroidSignature(new File(sanitizedUri.getPath()))) {
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
"APK signature of extension not correct!");
}
Intent installIntent = new Intent(context, InstallExtensionDialogActivity.class);
@ -70,15 +69,15 @@ public class ExtensionInstaller extends Installer {
PendingIntent installPendingIntent = PendingIntent.getActivity(
context.getApplicationContext(),
uri.hashCode(),
localApkUri.hashCode(),
installIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
sendBroadcastInstall(uri, originatingUri,
sendBroadcastInstall(downloadUri,
Installer.ACTION_INSTALL_USER_INTERACTION, installPendingIntent);
// don't use broadcasts for the rest of this special installer
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_COMPLETE);
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_COMPLETE);
}
@Override

View File

@ -55,8 +55,10 @@ import java.util.Set;
* <li>for a {@link Uri} ID, use {@code Uri}, {@link Intent#getData()}
* <li>for a {@code String} ID, use {@code urlString}, {@link Uri#toString()}, or
* {@link Intent#getDataString()}
* <li>for an {@code int} ID, use {@link String#hashCode()}
* <li>for an {@code int} ID, use {@link String#hashCode()} or {@link Uri#hashCode()}
* </ul></p>
* The implementations of {@link Uri#toString()} and {@link Intent#getDataString()} both
* include caching of the generated {@code String}, so it should be plenty fast.
*/
public class InstallManagerService extends Service {
public static final String TAG = "InstallManagerService";
@ -154,7 +156,7 @@ public class InstallManagerService extends Service {
Apk apk = new Apk(intent.getParcelableExtra(EXTRA_APK));
addToActive(urlString, app, apk);
NotificationCompat.Builder builder = createNotificationBuilder(intent.getDataString(), apk);
NotificationCompat.Builder builder = createNotificationBuilder(urlString, apk);
notificationManager.notify(urlString.hashCode(), builder.build());
registerDownloaderReceivers(urlString, builder);
@ -224,18 +226,18 @@ public class InstallManagerService extends Service {
@Override
public void onReceive(Context context, Intent intent) {
// elsewhere called urlString
Uri originatingUri = intent.getData();
Uri downloadUri = intent.getData();
String urlString = downloadUri.toString();
File localFile = new File(intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH));
Uri localUri = Uri.fromFile(localFile);
Uri localApkUri = Uri.fromFile(localFile);
Utils.debugLog(TAG, "download completed of " + originatingUri
+ " to " + localUri);
Utils.debugLog(TAG, "download completed of " + urlString + " to " + localApkUri);
unregisterDownloaderReceivers(intent.getDataString());
unregisterDownloaderReceivers(urlString);
registerInstallerReceivers(downloadUri);
registerInstallerReceivers(localUri);
Apk apk = ACTIVE_APKS.get(originatingUri.toString());
InstallerService.install(context, localUri, originatingUri, apk.packageName);
Apk apk = ACTIVE_APKS.get(urlString);
InstallerService.install(context, localApkUri, downloadUri, apk.packageName);
}
};
BroadcastReceiver interruptedReceiver = new BroadcastReceiver() {
@ -262,19 +264,18 @@ public class InstallManagerService extends Service {
}
private void registerInstallerReceivers(Uri uri) {
private void registerInstallerReceivers(Uri downloadUri) {
BroadcastReceiver installReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
String downloadUrl = intent.getDataString();
switch (intent.getAction()) {
case Installer.ACTION_INSTALL_STARTED:
// nothing to do
break;
case Installer.ACTION_INSTALL_COMPLETE:
Apk apkComplete = removeFromActive(originatingUri.toString());
Apk apkComplete = removeFromActive(downloadUrl);
PackageManagerCompat.setInstaller(getPackageManager(), apkComplete.packageName);
@ -286,31 +287,31 @@ public class InstallManagerService extends Service {
// show notification if app details is not visible
if (!TextUtils.isEmpty(errorMessage)) {
App app = getAppFromActive(originatingUri.toString());
String title = String.format(
getString(R.string.install_error_notify_title),
app.name);
App app = getAppFromActive(downloadUrl);
// show notification if app details is not visible
if (AppDetails.isAppVisible(app.packageName)) {
cancelNotification(originatingUri.toString());
cancelNotification(downloadUrl);
} else {
notifyError(originatingUri.toString(), title, errorMessage);
String title = String.format(
getString(R.string.install_error_notify_title),
app.name);
notifyError(downloadUrl, title, errorMessage);
}
}
removeFromActive(downloadUrl);
localBroadcastManager.unregisterReceiver(this);
break;
case Installer.ACTION_INSTALL_USER_INTERACTION:
PendingIntent installPendingIntent =
intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
Apk apkUserInteraction = getApkFromActive(originatingUri.toString());
Apk apkUserInteraction = getApkFromActive(downloadUrl);
// show notification if app details is not visible
if (AppDetails.isAppVisible(apkUserInteraction.packageName)) {
cancelNotification(originatingUri.toString());
cancelNotification(downloadUrl);
} else {
notifyDownloadComplete(apkUserInteraction, originatingUri.toString(), installPendingIntent);
notifyDownloadComplete(apkUserInteraction, downloadUrl, installPendingIntent);
}
break;
@ -321,7 +322,7 @@ public class InstallManagerService extends Service {
};
localBroadcastManager.registerReceiver(installReceiver,
Installer.getInstallIntentFilter(uri));
Installer.getInstallIntentFilter(downloadUri));
}
private NotificationCompat.Builder createNotificationBuilder(String urlString, Apk apk) {

View File

@ -46,7 +46,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.Map;
/**
*
* Handles the actual install process. Subclasses implement the details.
*/
public abstract class Installer {
final Context context;
@ -64,10 +64,14 @@ public abstract class Installer {
public static final String ACTION_UNINSTALL_USER_INTERACTION = "org.fdroid.fdroid.installer.Installer.action.UNINSTALL_USER_INTERACTION";
/**
* Same as http://developer.android.com/reference/android/content/Intent.html#EXTRA_ORIGINATING_URI
* In InstallManagerService often called urlString
* The URI where the APK was originally downloaded from. This is also used
* as the unique ID representing this in the whole install process in
* {@link InstallManagerService}, there is is generally known as the
* "download URL" since it is the URL used to download the APK.
*
* @see Intent#EXTRA_ORIGINATING_URI
*/
public static final String EXTRA_ORIGINATING_URI = "org.fdroid.fdroid.installer.Installer.extra.ORIGINATING_URI";
static final String EXTRA_DOWNLOAD_URI = "org.fdroid.fdroid.installer.Installer.extra.DOWNLOAD_URI";
public static final String EXTRA_PACKAGE_NAME = "org.fdroid.fdroid.installer.Installer.extra.PACKAGE_NAME";
public static final String EXTRA_USER_INTERACTION_PI = "org.fdroid.fdroid.installer.Installer.extra.USER_INTERACTION_PI";
public static final String EXTRA_ERROR_MESSAGE = "org.fdroid.fdroid.net.installer.Installer.extra.ERROR_MESSAGE";
@ -91,7 +95,7 @@ public abstract class Installer {
localBroadcastManager = LocalBroadcastManager.getInstance(context);
}
public static Uri prepareApkFile(Context context, Uri uri, String packageName)
static Uri prepareApkFile(Context context, Uri uri, String packageName)
throws InstallFailedException {
File apkFile = new File(uri.getPath());
@ -229,7 +233,7 @@ public abstract class Installer {
/**
* Checks the APK file against the provided hash, returning whether it is a match.
*/
public static boolean verifyApkFile(File apkFile, String hash, String hashType)
static boolean verifyApkFile(File apkFile, String hash, String hashType)
throws NoSuchAlgorithmException {
if (!apkFile.exists()) {
return false;
@ -238,24 +242,23 @@ public abstract class Installer {
return hasher.match(hash);
}
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
void sendBroadcastInstall(Uri downloadUri, String action,
PendingIntent pendingIntent) {
sendBroadcastInstall(uri, originatingUri, action, pendingIntent, null);
sendBroadcastInstall(downloadUri, action, pendingIntent, null);
}
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action) {
sendBroadcastInstall(uri, originatingUri, action, null, null);
void sendBroadcastInstall(Uri downloadUri, String action) {
sendBroadcastInstall(downloadUri, action, null, null);
}
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action, String errorMessage) {
sendBroadcastInstall(uri, originatingUri, action, null, errorMessage);
void sendBroadcastInstall(Uri downloadUri, String action, String errorMessage) {
sendBroadcastInstall(downloadUri, action, null, errorMessage);
}
public void sendBroadcastInstall(Uri uri, Uri originatingUri, String action,
void sendBroadcastInstall(Uri downloadUri, String action,
PendingIntent pendingIntent, String errorMessage) {
Intent intent = new Intent(action);
intent.setData(uri);
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
intent.setData(downloadUri);
intent.putExtra(Installer.EXTRA_USER_INTERACTION_PI, pendingIntent);
if (!TextUtils.isEmpty(errorMessage)) {
intent.putExtra(Installer.EXTRA_ERROR_MESSAGE, errorMessage);
@ -263,20 +266,20 @@ public abstract class Installer {
localBroadcastManager.sendBroadcast(intent);
}
public void sendBroadcastUninstall(String packageName, String action, String errorMessage) {
void sendBroadcastUninstall(String packageName, String action, String errorMessage) {
sendBroadcastUninstall(packageName, action, null, errorMessage);
}
public void sendBroadcastUninstall(String packageName, String action) {
void sendBroadcastUninstall(String packageName, String action) {
sendBroadcastUninstall(packageName, action, null, null);
}
public void sendBroadcastUninstall(String packageName, String action,
void sendBroadcastUninstall(String packageName, String action,
PendingIntent pendingIntent) {
sendBroadcastUninstall(packageName, action, pendingIntent, null);
}
public void sendBroadcastUninstall(String packageName, String action,
void sendBroadcastUninstall(String packageName, String action,
PendingIntent pendingIntent, String errorMessage) {
Uri uri = Uri.fromParts("package", packageName, null);
@ -290,6 +293,10 @@ public abstract class Installer {
localBroadcastManager.sendBroadcast(intent);
}
/**
* Gets an {@link IntentFilter} for matching events from the install
* process based on the original download URL as a {@link Uri}.
*/
public static IntentFilter getInstallIntentFilter(Uri uri) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Installer.ACTION_INSTALL_STARTED);
@ -297,6 +304,7 @@ public abstract class Installer {
intentFilter.addAction(Installer.ACTION_INSTALL_INTERRUPTED);
intentFilter.addAction(Installer.ACTION_INSTALL_USER_INTERACTION);
intentFilter.addDataScheme(uri.getScheme());
intentFilter.addDataAuthority(uri.getHost(), String.valueOf(uri.getPort()));
intentFilter.addDataPath(uri.getPath(), PatternMatcher.PATTERN_LITERAL);
return intentFilter;
}
@ -312,10 +320,20 @@ public abstract class Installer {
return intentFilter;
}
protected abstract void installPackage(Uri uri, Uri originatingUri, String packageName);
/**
* @param localApkUri points to the local copy of the APK to be installed
* @param downloadUri serves as the unique ID for all actions related to the
* installation of that specific APK
* @param packageName package name of the app that should be installed
*/
protected abstract void installPackage(Uri localApkUri, Uri downloadUri, String packageName);
protected abstract void uninstallPackage(String packageName);
/**
* This {@link Installer} instance is capable of "unattended" install and
* uninstall activities, without the system enforcing a user prompt.
*/
protected abstract boolean isUnattended();
}

View File

@ -33,6 +33,10 @@ import android.net.Uri;
* i.e., runs sequentially
* - no cancel operation is needed. Cancelling an installation
* would be the same as starting uninstall afterwards
* <p/>
* The download URL is only used as the unique ID that represents this
* particular apk throughout the whole install process in
* {@link InstallManagerService}.
*/
public class InstallerService extends IntentService {
@ -50,9 +54,8 @@ public class InstallerService extends IntentService {
if (ACTION_INSTALL.equals(intent.getAction())) {
Uri uri = intent.getData();
Uri originatingUri = intent.getParcelableExtra(Installer.EXTRA_ORIGINATING_URI);
installer.installPackage(uri, originatingUri, packageName);
Uri downloadUri = intent.getParcelableExtra(Installer.EXTRA_DOWNLOAD_URI);
installer.installPackage(uri, downloadUri, packageName);
} else if (ACTION_UNINSTALL.equals(intent.getAction())) {
installer.uninstallPackage(packageName);
}
@ -62,15 +65,15 @@ public class InstallerService extends IntentService {
* Install an apk from {@link Uri}
*
* @param context this app's {@link Context}
* @param uri {@link Uri} pointing to (downloaded) local apk file
* @param originatingUri {@link Uri} where the apk has been downloaded from
* @param localApkUri {@link Uri} pointing to (downloaded) local apk file
* @param downloadUri {@link Uri} where the apk has been downloaded from
* @param packageName package name of the app that should be installed
*/
public static void install(Context context, Uri uri, Uri originatingUri, String packageName) {
public static void install(Context context, Uri localApkUri, Uri downloadUri, String packageName) {
Intent intent = new Intent(context, InstallerService.class);
intent.setAction(ACTION_INSTALL);
intent.setData(uri);
intent.putExtra(Installer.EXTRA_ORIGINATING_URI, originatingUri);
intent.setData(localApkUri);
intent.putExtra(Installer.EXTRA_DOWNLOAD_URI, downloadUri);
intent.putExtra(Installer.EXTRA_PACKAGE_NAME, packageName);
context.startService(intent);
}

View File

@ -297,15 +297,15 @@ public class PrivilegedInstaller extends Installer {
}
@Override
protected void installPackage(final Uri uri, final Uri originatingUri, String packageName) {
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_STARTED);
protected void installPackage(final Uri localApkUri, final Uri downloadUri, String packageName) {
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_STARTED);
final Uri sanitizedUri;
try {
sanitizedUri = Installer.prepareApkFile(context, uri, packageName);
sanitizedUri = Installer.prepareApkFile(context, localApkUri, packageName);
} catch (Installer.InstallFailedException e) {
Log.e(TAG, "prepareApkFile failed", e);
sendBroadcastInstall(uri, originatingUri, Installer.ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, Installer.ACTION_INSTALL_INTERRUPTED,
e.getMessage());
return;
}
@ -318,9 +318,9 @@ public class PrivilegedInstaller extends Installer {
@Override
public void handleResult(String packageName, int returnCode) throws RemoteException {
if (returnCode == INSTALL_SUCCEEDED) {
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_COMPLETE);
sendBroadcastInstall(downloadUri, ACTION_INSTALL_COMPLETE);
} else {
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
"Error " + returnCode + ": "
+ INSTALL_RETURN_CODES.get(returnCode));
}
@ -330,7 +330,7 @@ public class PrivilegedInstaller extends Installer {
try {
boolean hasPermissions = privService.hasPrivilegedPermissions();
if (!hasPermissions) {
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
context.getString(R.string.system_install_denied_permissions));
return;
}
@ -339,7 +339,7 @@ public class PrivilegedInstaller extends Installer {
null, callback);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
sendBroadcastInstall(uri, originatingUri, ACTION_INSTALL_INTERRUPTED,
sendBroadcastInstall(downloadUri, ACTION_INSTALL_INTERRUPTED,
"connecting to privileged service failed");
}
}

View File

@ -34,6 +34,13 @@ import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.installer.Installer;
/**
* This class provides the confirmation prompt for when the user chooses to
* uninstall an app. This has to be implemented here for the privileged
* extension, it is only shown for {@link Installer} instances that can do
* installs and uninstalls without user prompts, which is detected via
* {@link Installer#isUnattended()}.
*/
public class UninstallDialogActivity extends FragmentActivity {
@Override

View File

@ -44,14 +44,10 @@ import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.NewRepoConfig;
import org.fdroid.fdroid.installer.InstallManagerService;
import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.installer.InstallerService;
import org.fdroid.fdroid.localrepo.LocalRepoManager;
import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.net.Downloader;
import org.fdroid.fdroid.net.DownloaderService;
import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
@ -773,26 +769,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
public void install(@NonNull final App app) {
final Apk apk = ApkProvider.Helper.find(this, app.packageName, app.suggestedVersionCode);
String urlString = apk.getUrl();
BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String path = intent.getStringExtra(Downloader.EXTRA_DOWNLOAD_PATH);
handleDownloadComplete(new File(path), app.packageName, intent.getDataString());
}
};
localBroadcastManager.registerReceiver(downloadCompleteReceiver,
DownloaderService.getIntentFilter(urlString, Downloader.ACTION_COMPLETE));
InstallManagerService.queue(this, app, apk);
}
private void handleDownloadComplete(File apkFile, String packageName, String urlString) {
Uri originatingUri = Uri.parse(urlString);
Uri localUri = Uri.fromFile(apkFile);
Uri downloadUri = Uri.parse(apk.getUrl());
localBroadcastManager.registerReceiver(installReceiver,
Installer.getInstallIntentFilter(Uri.fromFile(apkFile)));
InstallerService.install(this, localUri, originatingUri, packageName);
Installer.getInstallIntentFilter(downloadUri));
InstallManagerService.queue(this, app, apk);
}
private final BroadcastReceiver installReceiver = new BroadcastReceiver() {