diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
index d552647d2..30e77857b 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java
@@ -708,11 +708,20 @@ public class AppProvider extends FDroidProvider {
}
private AppQuerySelection queryInstalledWithKnownVulns() {
- // Include the hash in this check because otherwise any app with any vulnerable version will
- // get returned.
- String selection = " antiFeature." + Schema.AntiFeatureTable.Cols.NAME + " = 'KnownVuln' AND " +
- getApkTableName() + "." + ApkTable.Cols.HASH + " = installed." + InstalledAppTable.Cols.HASH;
- return new AppQuerySelection(selection).requireNaturalInstalledTable().requireNatrualJoinAntiFeatures();
+ String apk = getApkTableName();
+
+ // Include the hash in this check because otherwise apps with any vulnerable version will
+ // get returned, rather than just the installed version.
+ String compareHash = apk + "." + ApkTable.Cols.HASH + " = installed." + InstalledAppTable.Cols.HASH;
+ String knownVuln = " antiFeature." + Schema.AntiFeatureTable.Cols.NAME + " = 'KnownVuln' ";
+ String notIgnored = " COALESCE(prefs." + AppPrefsTable.Cols.IGNORE_VULNERABILITIES + ", 0) = 0 ";
+
+ String selection = knownVuln + " AND " + compareHash + " AND " + notIgnored;
+
+ return new AppQuerySelection(selection)
+ .requireNaturalInstalledTable()
+ .requireNatrualJoinAntiFeatures()
+ .requireLeftJoinPrefs();
}
static AppQuerySelection queryPackageNames(String packageNames, String packageNameField) {
diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java
index 8476e04ad..b9a0b1168 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java
@@ -93,6 +93,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
@Nullable
private final Button actionButton;
+ @Nullable
+ private final Button secondaryButton;
+
private final DisplayImageOptions displayImageOptions;
@Nullable
@@ -137,11 +140,16 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_button);
actionButton = (Button) itemView.findViewById(R.id.action_button);
+ secondaryButton = (Button) itemView.findViewById(R.id.secondary_button);
if (actionButton != null) {
actionButton.setOnClickListener(onActionClicked);
}
+ if (secondaryButton != null) {
+ secondaryButton.setOnClickListener(onSecondaryButtonClicked);
+ }
+
if (cancelButton != null) {
cancelButton.setOnClickListener(onCancelDownload);
}
@@ -213,6 +221,15 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
}
}
+ if (secondaryButton != null) {
+ if (viewState.shouldShowSecondaryButton()) {
+ secondaryButton.setVisibility(View.VISIBLE);
+ secondaryButton.setText(viewState.getSecondaryButtonText());
+ } else {
+ secondaryButton.setVisibility(View.GONE);
+ }
+ }
+
if (progressBar != null) {
if (viewState.showProgress()) {
progressBar.setVisibility(View.VISIBLE);
@@ -392,6 +409,18 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
}
};
+ @SuppressWarnings("FieldCanBeLocal")
+ private final View.OnClickListener onSecondaryButtonClicked = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (currentApp == null) {
+ return;
+ }
+
+ onSecondaryButtonPressed(currentApp);
+ }
+ };
+
protected void onActionButtonPressed(@NonNull App app) {
// When the button says "Run", then launch the app.
if (currentStatus != null && currentStatus.status == AppUpdateStatusManager.Status.Installed) {
@@ -441,6 +470,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
}
}
+ /** To be overridden by subclasses if desired */
+ protected void onSecondaryButtonPressed(@NonNull App app) { }
+
@SuppressWarnings("FieldCanBeLocal")
private final View.OnClickListener onCancelDownload = new View.OnClickListener() {
@Override
diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java
index 2a1e31fe8..2fef4de81 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java
@@ -14,6 +14,7 @@ public class AppListItemState {
private final App app;
private CharSequence mainText = null;
private CharSequence actionButtonText = null;
+ private CharSequence secondaryButtonText = null;
private CharSequence statusText = null;
private CharSequence secondaryStatusText = null;
private int progressCurrent = -1;
@@ -34,6 +35,11 @@ public class AppListItemState {
return this;
}
+ public AppListItemState showSecondaryButton(CharSequence label) {
+ secondaryButtonText = label;
+ return this;
+ }
+
public AppListItemState setStatusText(CharSequence text) {
this.statusText = text;
return this;
@@ -74,6 +80,14 @@ public class AppListItemState {
return actionButtonText;
}
+ public boolean shouldShowSecondaryButton() {
+ return secondaryButtonText != null;
+ }
+
+ public CharSequence getSecondaryButtonText() {
+ return secondaryButtonText;
+ }
+
public boolean showProgress() {
return progressCurrent >= 0;
}
diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java
index a466ae98e..69f744aca 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java
@@ -14,6 +14,8 @@ import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App;
+import org.fdroid.fdroid.data.AppPrefs;
+import org.fdroid.fdroid.data.AppPrefsProvider;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.installer.Installer;
import org.fdroid.fdroid.installer.InstallerService;
@@ -39,16 +41,17 @@ public class KnownVulnAppListItemController extends AppListItemController {
// TODO: Take into account signature when multi-sig stuff is merged.
if (app.installedVersionCode < app.suggestedVersionCode) {
- mainText = activity.getString(R.string.updates__app_with_known_vulnerability__upgrade, app.name);
+ mainText = activity.getString(R.string.updates__app_with_known_vulnerability__prompt_upgrade, app.name);
actionButtonText = activity.getString(R.string.menu_upgrade);
} else {
- mainText = activity.getString(R.string.updates__app_with_known_vulnerability__uninstall, app.name);
+ mainText = activity.getString(R.string.updates__app_with_known_vulnerability__prompt_uninstall, app.name);
actionButtonText = activity.getString(R.string.menu_uninstall);
}
return new AppListItemState(app)
.setMainText(mainText)
- .showActionButton(actionButtonText);
+ .showActionButton(actionButtonText)
+ .showSecondaryButton(activity.getString(R.string.updates__app_with_known_vulnerability__ignore));
}
@Override
@@ -69,18 +72,32 @@ public class KnownVulnAppListItemController extends AppListItemController {
}
}
+ @Override
+ protected void onSecondaryButtonPressed(@NonNull App app) {
+ AppPrefs prefs = app.getPrefs(activity);
+ prefs.ignoreVulnerabilities = true;
+ AppPrefsProvider.Helper.update(activity, app, prefs);
+ refreshUpdatesList();
+ }
+
private void unregisterUninstallReceiver() {
LocalBroadcastManager.getInstance(activity).unregisterReceiver(installReceiver);
}
+ /**
+ * Trigger the LoaderManager in UpdatesAdapter to automatically requery for the list of
+ * apps with known vulnerabilities (i.e. this app should no longer be in that list).
+ */
+ private void refreshUpdatesList() {
+ activity.getContentResolver().notifyChange(AppProvider.getInstalledWithKnownVulnsUri(), null);
+ }
+
private final BroadcastReceiver installReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Installer.ACTION_UNINSTALL_COMPLETE:
- // This will cause the LoaderManager in UpdatesAdapter to automatically requery for the list of
- // apps with known vulnerabilities (i.e. this app should no longer be in that list).
- activity.getContentResolver().notifyChange(AppProvider.getInstalledWithKnownVulnsUri(), null);
+ refreshUpdatesList();
unregisterUninstallReceiver();
break;
diff --git a/app/src/main/res/layout/known_vuln_app_list_item.xml b/app/src/main/res/layout/known_vuln_app_list_item.xml
index 6420162fd..80a4ff265 100644
--- a/app/src/main/res/layout/known_vuln_app_list_item.xml
+++ b/app/src/main/res/layout/known_vuln_app_list_item.xml
@@ -63,4 +63,16 @@
app:layout_constraintTop_toBottomOf="@+id/app_name"
tools:text="Uninstall"/>
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3ad55ce16..7503ea30f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -97,8 +97,9 @@ This often occurs with apps installed via Google Play or other sources, if they
Download
Download all updates
- We found a vulnerability with %1$s. We recommend uninstalling this app immediately.
- We found a vulnerability with %1$s. We recommend upgrading to the newest version immediately.
+ We found a vulnerability with %1$s. We recommend uninstalling this app immediately.
+ We found a vulnerability with %1$s. We recommend upgrading to the newest version immediately.
+ Ignore
Hide apps
Show apps
diff --git a/app/src/main/res/values/styles_detail.xml b/app/src/main/res/values/styles_detail.xml
index 885879496..e6d2825da 100644
--- a/app/src/main/res/values/styles_detail.xml
+++ b/app/src/main/res/values/styles_detail.xml
@@ -24,6 +24,10 @@
- @drawable/button_secondary_background_selector
+
+