diff --git a/dependencies.gradle b/dependencies.gradle
index 440859be..cd17bf93 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -1,6 +1,6 @@
 ext.versions = [
         minSdk               : 14,
-        targetSdk            : 23,
+        targetSdk            : 28,
         compileSdk           : 28,
         gradle               : '6.5',
 
@@ -10,7 +10,7 @@ ext.versions = [
         detekt               : "1.0.0.RC6-4",
         jacoco               : "0.8.5",
 
-        androidSupport       : "22.2.1",
+        androidSupport       : "28.0.0",
         androidLegacySupport : "1.0.0",
         androidSupportDesign : "1.0.0",
         multidex             : "2.0.1",
diff --git a/ultrasonic/src/main/AndroidManifest.xml b/ultrasonic/src/main/AndroidManifest.xml
index bcf7f624..31523fe8 100644
--- a/ultrasonic/src/main/AndroidManifest.xml
+++ b/ultrasonic/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 
     <supports-screens
         android:anyDensity="true"
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
index 72377dff..e176d5fc 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/activity/SubsonicTabActivity.java
@@ -97,7 +97,11 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
 		applyTheme();
 		super.onCreate(bundle);
 
-		startService(new Intent(this, DownloadServiceImpl.class));
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+			startForegroundService(new Intent(this, DownloadServiceImpl.class));
+		} else {
+			startService(new Intent(this, DownloadServiceImpl.class));
+		}
 		setVolumeControlStream(AudioManager.STREAM_MUSIC);
 
 		if (bundle != null)
@@ -774,7 +778,11 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
 			}
 
 			Log.w(TAG, "DownloadService not running. Attempting to start it.");
-			startService(new Intent(this, DownloadServiceImpl.class));
+			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+				startForegroundService(new Intent(this, DownloadServiceImpl.class));
+			} else {
+				startService(new Intent(this, DownloadServiceImpl.class));
+			}
 			Util.sleepQuietly(50L);
 		}
 
@@ -1240,7 +1248,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
 			File file = null;
 			PrintWriter printWriter = null;
 
-			try
+			/*try
 			{
 				file = new File(Environment.getExternalStorageDirectory(), filename);
 				printWriter = new PrintWriter(file);
@@ -1262,7 +1270,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
 				{
 					defaultHandler.uncaughtException(thread, throwable);
 				}
-			}
+			}*/
 		}
 	}
 
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
index a98f3724..944c6481 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/receiver/MediaButtonIntentReceiver.java
@@ -21,6 +21,7 @@ package org.moire.ultrasonic.receiver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.util.Log;
@@ -57,7 +58,11 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver
 
 			Intent serviceIntent = new Intent(context, DownloadServiceImpl.class);
 			serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
-			context.startService(serviceIntent);
+			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+				context.startForegroundService(serviceIntent);
+			} else {
+				context.startService(serviceIntent);
+			}
 
 			try
 			{
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java
index 495d7678..5558ed92 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/DownloadServiceImpl.java
@@ -20,6 +20,8 @@ package org.moire.ultrasonic.service;
 
 import android.annotation.SuppressLint;
 import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.ComponentName;
@@ -101,6 +103,8 @@ public class DownloadServiceImpl extends Service implements DownloadService
 	public static final String CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS";
 	public static final String CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT";
 
+	private static final String NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic";
+	private static final String NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service";
     private static final int NOTIFICATION_ID = 3033;
 
 	private final IBinder binder = new SimpleServiceBinder<DownloadService>(this);
@@ -2096,7 +2100,15 @@ public class DownloadServiceImpl extends Service implements DownloadService
 
     @SuppressWarnings("IconColors")
     private Notification buildForegroundNotification() {
-        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+			NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_NONE);
+			channel.setLightColor(android.R.color.holo_blue_dark);
+			channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
+			NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+			manager.createNotificationChannel(channel);
+
+		}
+		NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
         builder.setSmallIcon(R.drawable.ic_stat_ultrasonic);
 
         builder.setAutoCancel(false);
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java
index 57c7af18..b02f3f6e 100644
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java
+++ b/ultrasonic/src/main/java/org/moire/ultrasonic/util/FileUtil.java
@@ -40,6 +40,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.regex.Pattern;