diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index db398f3b..2566d5da 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -66,13 +66,9 @@
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
-
-
-
+
+
+
diff --git a/app/src/main/java/com/dkanada/gramophone/helper/menu/SongMenuHelper.java b/app/src/main/java/com/dkanada/gramophone/helper/menu/SongMenuHelper.java
index 62f2b420..f3f5ad36 100644
--- a/app/src/main/java/com/dkanada/gramophone/helper/menu/SongMenuHelper.java
+++ b/app/src/main/java/com/dkanada/gramophone/helper/menu/SongMenuHelper.java
@@ -3,6 +3,8 @@ package com.dkanada.gramophone.helper.menu;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;
import androidx.appcompat.app.AppCompatActivity;
+
+import android.content.Intent;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupMenu;
@@ -15,6 +17,7 @@ import com.dkanada.gramophone.helper.MusicPlayerRemote;
import com.dkanada.gramophone.model.Album;
import com.dkanada.gramophone.model.Artist;
import com.dkanada.gramophone.model.Song;
+import com.dkanada.gramophone.service.DownloadService;
import com.dkanada.gramophone.util.NavigationUtil;
public class SongMenuHelper {
@@ -37,6 +40,9 @@ public class SongMenuHelper {
case R.id.action_details:
SongDetailDialog.create(song).show(activity.getSupportFragmentManager(), SongDetailDialog.TAG);
return true;
+ case R.id.action_download:
+ NavigationUtil.startDownload(activity, song);
+ return true;
case R.id.action_go_to_album:
NavigationUtil.startAlbum(activity, new Album(song));
return true;
diff --git a/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java b/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java
new file mode 100644
index 00000000..a45e9c0b
--- /dev/null
+++ b/app/src/main/java/com/dkanada/gramophone/service/DownloadService.java
@@ -0,0 +1,88 @@
+package com.dkanada.gramophone.service;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+
+import com.dkanada.gramophone.App;
+import com.dkanada.gramophone.BuildConfig;
+import com.dkanada.gramophone.model.Song;
+import com.dkanada.gramophone.util.MusicUtil;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class DownloadService extends Service {
+ public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
+ public static final String EXTRA_SONG = PACKAGE_NAME + ".extra.song";
+
+ private Executor executor;
+ private Handler handler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ looper = Looper.getMainLooper();
+ }
+
+ executor = Executors.newFixedThreadPool(4);
+ handler = new Handler(looper);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) return super.onStartCommand(null, flags, startId);
+ Song song = intent.getParcelableExtra(EXTRA_SONG);
+
+ executor.execute(() -> {
+ try {
+ URL url = new URL(MusicUtil.getDownloadUri(song));
+ URLConnection connection = url.openConnection();
+
+ File root = new File(App.getInstance().getCacheDir(), "music");
+ String path = song.artistName + "/" + song.albumName + "/";
+ String name = song.discNumber + "." + song.trackNumber + " - " + song.title + "." + song.container;
+ File audio = new File(root, path + name);
+
+ audio.getParentFile().mkdirs();
+ audio.createNewFile();
+
+ InputStream input = connection.getInputStream();
+ OutputStream output = new FileOutputStream(audio);
+
+ connection.connect();
+
+ byte[] data = new byte[4096];
+ int count;
+
+ while ((count = input.read(data)) != -1) {
+ output.write(data, 0, count);
+ }
+
+ input.close();
+ output.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java b/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java
index 7f073656..41aefdd1 100644
--- a/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java
+++ b/app/src/main/java/com/dkanada/gramophone/util/MusicUtil.java
@@ -69,6 +69,19 @@ public class MusicUtil {
return builder.toString();
}
+ public static String getDownloadUri(Song song) {
+ StringBuilder builder = new StringBuilder(256);
+
+ builder.append(App.getApiClient().getApiUrl());
+ builder.append("/Items/");
+ builder.append(song.id);
+ builder.append("/Download");
+
+ builder.append("?ApiKey=").append(App.getApiClient().getAccessToken());
+
+ return builder.toString();
+ }
+
@NonNull
public static Intent createShareSongFileIntent(@NonNull final Song song, Context context) {
try {
diff --git a/app/src/main/java/com/dkanada/gramophone/util/NavigationUtil.java b/app/src/main/java/com/dkanada/gramophone/util/NavigationUtil.java
index 0ff918f4..1ce01fa1 100644
--- a/app/src/main/java/com/dkanada/gramophone/util/NavigationUtil.java
+++ b/app/src/main/java/com/dkanada/gramophone/util/NavigationUtil.java
@@ -22,6 +22,8 @@ import com.dkanada.gramophone.activities.details.AlbumDetailActivity;
import com.dkanada.gramophone.activities.details.ArtistDetailActivity;
import com.dkanada.gramophone.activities.details.GenreDetailActivity;
import com.dkanada.gramophone.activities.details.PlaylistDetailActivity;
+import com.dkanada.gramophone.model.Song;
+import com.dkanada.gramophone.service.DownloadService;
public class NavigationUtil {
public static void openUrl(@NonNull final Context context, String url) {
@@ -99,4 +101,11 @@ public class NavigationUtil {
activity.startActivity(intent);
}
}
+
+ public static void startDownload(@NonNull Activity activity, Song song) {
+ Intent intent = new Intent(activity, DownloadService.class);
+
+ intent.putExtra(DownloadService.EXTRA_SONG, song);
+ activity.startService(intent);
+ }
}
diff --git a/app/src/main/res/menu/menu_item_song.xml b/app/src/main/res/menu/menu_item_song.xml
index 8d7a97b0..f93195c5 100644
--- a/app/src/main/res/menu/menu_item_song.xml
+++ b/app/src/main/res/menu/menu_item_song.xml
@@ -29,4 +29,8 @@
android:id="@+id/action_details"
android:title="@string/action_details"
app:showAsAction="never" />
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bfe2b1ec..7e291e5b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,6 +18,7 @@
Add to favorites
Remove from favorites
Search
+ Download
Play next
Play
Play/Pause