use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.
the class AppDetailsActivity method uninstallApk.
/**
* Uninstall the app from the current screen. Since there are many ways
* to uninstall an app, including from Google Play, {@code adb uninstall},
* or Settings -> Apps, this method cannot ever be sure that the app isn't
* already being uninstalled. So it needs to check that we can actually
* get info on the installed app, otherwise, just call it interrupted and
* quit.
*
* @see <a href="https://gitlab.com/fdroid/fdroidclient/issues/1435">issue #1435</a>
*/
@Override
public void uninstallApk() {
Apk apk = app.installedApk;
if (apk == null) {
apk = app.getMediaApkifInstalled(getApplicationContext());
if (apk == null) {
// When the app isn't a media file - the above workaround refers to this.
apk = app.getInstalledApk(this);
if (apk == null) {
Log.d(TAG, "Couldn't find installed apk for " + app.packageName);
Toast.makeText(this, R.string.uninstall_error_unknown, Toast.LENGTH_SHORT).show();
uninstallReceiver.onReceive(this, new Intent(Installer.ACTION_UNINSTALL_INTERRUPTED));
return;
}
}
app.installedApk = apk;
}
Installer installer = InstallerFactory.create(this, apk);
Intent intent = installer.getUninstallScreen();
if (intent != null) {
// uninstall screen required
Utils.debugLog(TAG, "screen screen required");
startActivityForResult(intent, REQUEST_UNINSTALL_DIALOG);
return;
}
startUninstall();
}
use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.
the class AppDetailsActivity method onActivityResult.
/*
private void shareApkBluetooth() {
// If Bluetooth has not been enabled/turned on, then
// enabling device discoverability will automatically enable Bluetooth
Intent discoverBt = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverBt.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 121);
startActivityForResult(discoverBt, REQUEST_ENABLE_BLUETOOTH);
// if this is successful, the Bluetooth transfer is started
}
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_ENABLE_BLUETOOTH:
fdroidApp.sendViaBluetooth(this, resultCode, app.packageName);
break;
case REQUEST_PERMISSION_DIALOG:
if (resultCode == AppCompatActivity.RESULT_OK) {
Uri uri = data.getData();
Apk apk = ApkProvider.Helper.findByUri(this, uri, Schema.ApkTable.Cols.ALL);
InstallManagerService.queue(this, app, apk);
}
break;
case REQUEST_UNINSTALL_DIALOG:
if (resultCode == AppCompatActivity.RESULT_OK) {
startUninstall();
}
break;
}
}
use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.
the class InstallManagerService method registerInstallReceiver.
/**
* Register a {@link BroadcastReceiver} for tracking install progress for a
* give {@link Uri}. There can be multiple of these registered at a time.
*/
private void registerInstallReceiver(String canonicalUrl) {
BroadcastReceiver installReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!running) {
localBroadcastManager.unregisterReceiver(this);
return;
}
String canonicalUrl = intent.getDataString();
Apk apk;
switch(intent.getAction()) {
case Installer.ACTION_INSTALL_STARTED:
appUpdateStatusManager.updateApk(canonicalUrl, AppUpdateStatusManager.Status.Installing, null);
break;
case Installer.ACTION_INSTALL_COMPLETE:
appUpdateStatusManager.updateApk(canonicalUrl, AppUpdateStatusManager.Status.Installed, null);
Apk apkComplete = appUpdateStatusManager.getApk(canonicalUrl);
if (apkComplete != null && apkComplete.isApk()) {
try {
PackageManagerCompat.setInstaller(context, getPackageManager(), apkComplete.packageName);
} catch (SecurityException e) {
// Will happen if we fell back to DefaultInstaller for some reason.
}
}
localBroadcastManager.unregisterReceiver(this);
break;
case Installer.ACTION_INSTALL_INTERRUPTED:
apk = intent.getParcelableExtra(Installer.EXTRA_APK);
String errorMessage = intent.getStringExtra(Installer.EXTRA_ERROR_MESSAGE);
if (!TextUtils.isEmpty(errorMessage)) {
appUpdateStatusManager.setApkError(apk, errorMessage);
} else {
appUpdateStatusManager.removeApk(canonicalUrl);
}
localBroadcastManager.unregisterReceiver(this);
break;
case Installer.ACTION_INSTALL_USER_INTERACTION:
apk = intent.getParcelableExtra(Installer.EXTRA_APK);
PendingIntent installPendingIntent = intent.getParcelableExtra(Installer.EXTRA_USER_INTERACTION_PI);
appUpdateStatusManager.addApk(apk, AppUpdateStatusManager.Status.ReadyToInstall, installPendingIntent);
break;
default:
throw new RuntimeException("intent action not handled!");
}
}
};
localBroadcastManager.registerReceiver(installReceiver, Installer.getInstallIntentFilter(canonicalUrl));
}
use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.
the class InstallManagerService method onStartCommand.
/**
* This goes through a series of checks to make sure that the incoming
* {@link Intent} is still valid. The default {@link Intent#getAction() action}
* in the logic is {@link #ACTION_INSTALL} since it is the most complicate
* case. Since the {@code Intent} will be redelivered by Android if the
* app was killed, this needs to check that it still makes sense to handle.
* <p>
* For example, if F-Droid is killed while installing, it might not receive
* the message that the install completed successfully. The checks need to be
* as specific as possible so as not to block things like installing updates
* with the same {@link PackageInfo#versionCode}, which happens sometimes,
* and is allowed by Android.
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Utils.debugLog(TAG, "onStartCommand " + intent);
String canonicalUrl = intent.getDataString();
if (TextUtils.isEmpty(canonicalUrl)) {
Utils.debugLog(TAG, "empty canonicalUrl, nothing to do");
return START_NOT_STICKY;
}
String action = intent.getAction();
if (ACTION_CANCEL.equals(action)) {
DownloaderService.cancel(this, canonicalUrl);
Apk apk = appUpdateStatusManager.getApk(canonicalUrl);
if (apk != null) {
Utils.debugLog(TAG, "also canceling OBB downloads");
DownloaderService.cancel(this, apk.getPatchObbUrl());
DownloaderService.cancel(this, apk.getMainObbUrl());
}
return START_NOT_STICKY;
} else if (ACTION_INSTALL.equals(action)) {
if (!isPendingInstall(canonicalUrl)) {
Log.i(TAG, "Ignoring INSTALL that is not Pending Install: " + intent);
return START_NOT_STICKY;
}
} else {
Log.i(TAG, "Ignoring unknown intent action: " + intent);
return START_NOT_STICKY;
}
if (!intent.hasExtra(EXTRA_APP) || !intent.hasExtra(EXTRA_APK)) {
Utils.debugLog(TAG, canonicalUrl + " did not include both an App and Apk instance, ignoring");
return START_NOT_STICKY;
}
if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY && !DownloaderService.isQueuedOrActive(canonicalUrl)) {
Utils.debugLog(TAG, canonicalUrl + " finished downloading while InstallManagerService was killed.");
appUpdateStatusManager.removeApk(canonicalUrl);
return START_NOT_STICKY;
}
App app = intent.getParcelableExtra(EXTRA_APP);
Apk apk = intent.getParcelableExtra(EXTRA_APK);
if (app == null || apk == null) {
Utils.debugLog(TAG, "Intent had null EXTRA_APP and/or EXTRA_APK: " + intent);
return START_NOT_STICKY;
}
PackageInfo packageInfo = Utils.getPackageInfo(this, apk.packageName);
if ((flags & START_FLAG_REDELIVERY) == START_FLAG_REDELIVERY && packageInfo != null && packageInfo.versionCode == apk.versionCode && TextUtils.equals(packageInfo.versionName, apk.versionName)) {
Log.i(TAG, "INSTALL Intent no longer valid since its installed, ignoring: " + intent);
return START_NOT_STICKY;
}
FDroidApp.resetMirrorVars();
DownloaderService.setTimeout(FDroidApp.getTimeout());
appUpdateStatusManager.addApk(apk, AppUpdateStatusManager.Status.Downloading, null);
registerPackageDownloaderReceivers(canonicalUrl);
getMainObb(canonicalUrl, apk);
getPatchObb(canonicalUrl, apk);
File apkFilePath = ApkCache.getApkDownloadPath(this, apk.getCanonicalUrl());
long apkFileSize = apkFilePath.length();
if (!apkFilePath.exists() || apkFileSize < apk.size) {
Utils.debugLog(TAG, "download " + canonicalUrl + " " + apkFilePath);
DownloaderService.queueUsingRandomMirror(this, apk.repoId, canonicalUrl);
} else if (ApkCache.apkIsCached(apkFilePath, apk)) {
Utils.debugLog(TAG, "skip download, we have it, straight to install " + canonicalUrl + " " + apkFilePath);
sendBroadcast(intent.getData(), Downloader.ACTION_STARTED, apkFilePath);
sendBroadcast(intent.getData(), Downloader.ACTION_COMPLETE, apkFilePath);
} else {
Utils.debugLog(TAG, "delete and download again " + canonicalUrl + " " + apkFilePath);
apkFilePath.delete();
DownloaderService.queueUsingRandomMirror(this, apk.repoId, canonicalUrl);
}
// if killed before completion, retry Intent
return START_REDELIVER_INTENT;
}
use of org.fdroid.fdroid.data.Apk in project fdroidclient by f-droid.
the class AppDetailsRecyclerViewAdapter method updateItems.
public void updateItems(@NonNull App app) {
this.app = app;
// Get versions
versions = new ArrayList<>();
compatibleVersionsDifferentSig = new ArrayList<>();
final List<Apk> apks = ApkProvider.Helper.findByPackageName(context, this.app.packageName);
ensureInstalledApkExists(apks);
boolean showIncompatibleVersions = Preferences.get().showIncompatibleVersions();
for (final Apk apk : apks) {
boolean allowByCompatibility = apk.compatible || showIncompatibleVersions;
boolean allowBySig = this.app.installedSig == null || showIncompatibleVersions || TextUtils.equals(this.app.installedSig, apk.sig);
if (allowByCompatibility) {
compatibleVersionsDifferentSig.add(apk);
if (allowBySig) {
versions.add(apk);
if (!versionsExpandTracker.containsKey(apk.apkName)) {
versionsExpandTracker.put(apk.apkName, false);
}
}
}
}
if (items == null) {
items = new ArrayList<>();
} else {
items.clear();
}
addItem(VIEWTYPE_HEADER);
if (app.getAllScreenshots(context).length > 0) {
addItem(VIEWTYPE_SCREENSHOTS);
}
addItem(VIEWTYPE_DONATE);
addItem(VIEWTYPE_LINKS);
addItem(VIEWTYPE_PERMISSIONS);
if (versions.isEmpty()) {
addItem(VIEWTYPE_NO_VERSIONS);
} else {
addItem(VIEWTYPE_VERSIONS);
if (showVersions) {
setShowVersions(true);
}
}
notifyDataSetChanged();
}
Aggregations