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