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