diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0ac368898..c788385e5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -435,6 +435,7 @@ diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt index a40bf35dc..6fe311fb0 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt @@ -1,6 +1,8 @@ package org.schabi.newpipe.local.feed.notifications import android.content.Context +import android.content.pm.ServiceInfo +import android.os.Build import android.util.Log import androidx.core.app.NotificationCompat import androidx.work.Constraints @@ -83,7 +85,9 @@ class NotificationWorker( .setPriority(NotificationCompat.PRIORITY_LOW) .setContentTitle(applicationContext.getString(R.string.feed_notification_loading)) .build() - setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification)) + // ServiceInfo constants are not used below Android Q, so 0 is set here + val serviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC else 0 + setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification, serviceType)) } companion object { diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java index cc3889973..0894d22be 100644 --- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java +++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java @@ -167,19 +167,17 @@ public final class NotificationUtil { && notificationBuilder.mActions.get(2).actionIntent != null); } - public void createNotificationAndStartForeground() { if (notificationBuilder == null) { notificationBuilder = createNotification(); } updateNotification(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build(), - ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK); - } else { - player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build()); - } + // ServiceInfo constants are not used below Android Q, so 0 is set here + final int serviceType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + ? ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK : 0; + ServiceCompat.startForeground(player.getService(), NOTIFICATION_ID, + notificationBuilder.build(), serviceType); } public void cancelNotificationAndStopForeground() { diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java index 55193599e..2785afab0 100644 --- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java @@ -9,9 +9,11 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; +import android.text.Html; import android.widget.Toast; import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -113,14 +115,47 @@ public final class PermissionHelper { @RequiresApi(api = Build.VERSION_CODES.M) public static boolean checkSystemAlertWindowPermission(final Context context) { if (!Settings.canDrawOverlays(context)) { - final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, - Uri.parse("package:" + context.getPackageName())); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(i); - } catch (final ActivityNotFoundException ignored) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + context.getPackageName())); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(i); + } catch (final ActivityNotFoundException ignored) { + } + return false; + // from Android R the ACTION_MANAGE_OVERLAY_PERMISSION will only point to the menu, + // so let’s add a dialog that points the user to the right setting. + } else { + final String appName = context.getApplicationInfo() + .loadLabel(context.getPackageManager()).toString(); + final String title = context.getString(R.string.permission_display_over_apps); + final String permissionName = + context.getString(R.string.permission_display_over_apps_permission_name); + final String appNameItalic = "" + appName + ""; + final String permissionNameItalic = "" + permissionName + ""; + final String message = + context.getString(R.string.permission_display_over_apps_message, + appNameItalic, + permissionNameItalic + ); + new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT)) + .setPositiveButton("OK", (dialog, which) -> { + // we don’t need the package name here, since it won’t do anything on >R + final Intent intent = + new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); + try { + context.startActivity(intent); + } catch (final ActivityNotFoundException ignored) { + } + }) + .setCancelable(true) + .show(); + return false; } - return false; + } else { return true; } diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManager.java b/app/src/main/java/us/shandian/giga/service/DownloadManager.java index 9b90fa14b..d02f77bc1 100644 --- a/app/src/main/java/us/shandian/giga/service/DownloadManager.java +++ b/app/src/main/java/us/shandian/giga/service/DownloadManager.java @@ -265,7 +265,7 @@ public class DownloadManager { } } - public void deleteMission(Mission mission) { + public void deleteMission(Mission mission, boolean alsoDeleteFile) { synchronized (this) { if (mission instanceof DownloadMission) { mMissionsPending.remove(mission); @@ -274,7 +274,9 @@ public class DownloadManager { mFinishedMissionStore.deleteMission(mission); } - mission.delete(); + if (alsoDeleteFile) { + mission.delete(); + } } } diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index 9722a9a1f..79dda9011 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -614,7 +614,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb while (i.hasNext()) { Mission mission = i.next(); if (mission != null) { - mDownloadManager.deleteMission(mission); + mDownloadManager.deleteMission(mission, true); mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri())); } i.remove(); @@ -667,7 +667,14 @@ public class MissionAdapter extends Adapter implements Handler.Callb shareFile(h.item.mission); return true; case R.id.delete: - mDeleter.append(h.item.mission); + // delete the entry and the file + mDeleter.append(h.item.mission, true); + applyChanges(); + checkMasterButtonsVisibility(); + return true; + case R.id.delete_entry: + // just delete the entry + mDeleter.append(h.item.mission, false); applyChanges(); checkMasterButtonsVisibility(); return true; @@ -676,7 +683,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb final StoredFileHelper storage = h.item.mission.storage; if (!storage.existsAsFile()) { Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show(); - mDeleter.append(h.item.mission); + mDeleter.append(h.item.mission, true); applyChanges(); return true; } diff --git a/app/src/main/java/us/shandian/giga/ui/common/Deleter.java b/app/src/main/java/us/shandian/giga/ui/common/Deleter.java index 1902076d6..0f285fd74 100644 --- a/app/src/main/java/us/shandian/giga/ui/common/Deleter.java +++ b/app/src/main/java/us/shandian/giga/ui/common/Deleter.java @@ -13,7 +13,9 @@ import com.google.android.material.snackbar.Snackbar; import org.schabi.newpipe.R; import java.util.ArrayList; +import java.util.Optional; +import kotlin.Pair; import us.shandian.giga.get.FinishedMission; import us.shandian.giga.get.Mission; import us.shandian.giga.service.DownloadManager; @@ -30,7 +32,8 @@ public class Deleter { private static final int DELAY_RESUME = 400;// ms private Snackbar snackbar; - private ArrayList items; + // list of missions to be deleted, and whether to also delete the corresponding file + private ArrayList> items; private boolean running = true; private final Context mContext; @@ -51,7 +54,7 @@ public class Deleter { items = new ArrayList<>(2); } - public void append(Mission item) { + public void append(Mission item, boolean alsoDeleteFile) { /* If a mission is removed from the list while the Snackbar for a previously * removed item is still showing, commit the action for the previous item * immediately. This prevents Snackbars from stacking up in reverse order. @@ -60,13 +63,13 @@ public class Deleter { commit(); mIterator.hide(item); - items.add(0, item); + items.add(0, new Pair<>(item, alsoDeleteFile)); show(); } private void forget() { - mIterator.unHide(items.remove(0)); + mIterator.unHide(items.remove(0).getFirst()); mAdapter.applyChanges(); show(); @@ -84,7 +87,19 @@ public class Deleter { private void next() { if (items.size() < 1) return; - String msg = mContext.getString(R.string.file_deleted).concat(":\n").concat(items.get(0).storage.getName()); + final Optional fileToBeDeleted = items.stream() + .filter(Pair::getSecond) + .map(p -> p.getFirst().storage.getName()) + .findFirst(); + + String msg; + if (fileToBeDeleted.isPresent()) { + msg = mContext.getString(R.string.file_deleted) + .concat(":\n") + .concat(fileToBeDeleted.get()); + } else { + msg = mContext.getString(R.string.entry_deleted); + } snackbar = Snackbar.make(mView, msg, Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.undo, s -> forget()); @@ -98,11 +113,13 @@ public class Deleter { if (items.size() < 1) return; while (items.size() > 0) { - Mission mission = items.remove(0); + Pair missionAndAlsoDeleteFile = items.remove(0); + Mission mission = missionAndAlsoDeleteFile.getFirst(); + boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond(); if (mission.deleted) continue; mIterator.unHide(mission); - mDownloadManager.deleteMission(mission); + mDownloadManager.deleteMission(mission, alsoDeleteFile); if (mission instanceof FinishedMission) { mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri())); @@ -137,7 +154,11 @@ public class Deleter { pause(); - for (Mission mission : items) mDownloadManager.deleteMission(mission); + for (Pair missionAndAlsoDeleteFile : items) { + Mission mission = missionAndAlsoDeleteFile.getFirst(); + boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond(); + mDownloadManager.deleteMission(mission, alsoDeleteFile); + } items = null; } } diff --git a/app/src/main/res/menu/mission.xml b/app/src/main/res/menu/mission.xml index 4273c1ed6..6566252e8 100644 --- a/app/src/main/res/menu/mission.xml +++ b/app/src/main/res/menu/mission.xml @@ -27,7 +27,11 @@ + android:title="@string/delete_file" /> + + Restore defaults Do you want to restore defaults? Give permission to display over other apps + In order to use the Popup Player, please select %1$s in the following Android settings menu and enable %2$s. + “Allow display over other apps” NewPipe encountered an error, tap to report An error occurred, see the notification @@ -333,6 +335,8 @@ Pause Create Delete + Delete file + Delete entry Checksum Dismiss Rename @@ -889,4 +893,5 @@ Trending podcasts Trending movies and shows Trending music + Entry deleted