Downloading songs in the background is now in effect!

This commit is contained in:
kdeng00
2020-01-11 17:39:21 -05:00
parent c893a38192
commit 92b6a79a78
7 changed files with 77 additions and 87 deletions
+2 -1
View File
@@ -30,7 +30,7 @@
</configuration> </configuration>
</facet> </facet>
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JVM 1.6" allPlatforms="JVM [1.6]" useProjectSettings="false"> <configuration version="3" platform="JVM 1.8" allPlatforms="JVM [1.8]" useProjectSettings="false">
<compilerSettings /> <compilerSettings />
<compilerArguments> <compilerArguments>
<option name="destination" value="$MODULE_DIR$/build/tmp/kotlin-classes/debug" /> <option name="destination" value="$MODULE_DIR$/build/tmp/kotlin-classes/debug" />
@@ -38,6 +38,7 @@
<option name="noStdlib" value="true" /> <option name="noStdlib" value="true" />
<option name="noReflect" value="true" /> <option name="noReflect" value="true" />
<option name="moduleName" value="app_debug" /> <option name="moduleName" value="app_debug" />
<option name="jvmTarget" value="1.8" />
<option name="languageVersion" value="1.3" /> <option name="languageVersion" value="1.3" />
<option name="apiVersion" value="1.3" /> <option name="apiVersion" value="1.3" />
<option name="pluginOptions"> <option name="pluginOptions">
+3
View File
@@ -38,6 +38,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
externalNativeBuild { externalNativeBuild {
cmake { cmake {
path "src/main/cpp/CMakeLists.txt" path "src/main/cpp/CMakeLists.txt"
@@ -5,7 +5,6 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.IBinder import android.os.IBinder
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@@ -16,6 +16,7 @@ class LoginActivity : BaseServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
window.statusBarColor = resources.getColor(R.color.track_seek)
setContentView(R.layout.activity_login) setContentView(R.layout.activity_login)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
@@ -11,25 +11,19 @@ import kotlinx.android.synthetic.main.fragment_track_details.*
import kotlinx.android.synthetic.main.fragment_track_elapsing.* import kotlinx.android.synthetic.main.fragment_track_elapsing.*
import kotlinx.android.synthetic.main.fragment_track_flow.* import kotlinx.android.synthetic.main.fragment_track_flow.*
import android.Manifest
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.PopupMenu import android.widget.PopupMenu
import android.widget.Toast import android.widget.Toast
/** import androidx.lifecycle.Observer
import androidx.work.Data import androidx.work.Data
import androidx.work.NetworkType import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager import androidx.work.WorkManager
*/
import org.jetbrains.anko.image import org.jetbrains.anko.image
import org.jetbrains.anko.imageBitmap import org.jetbrains.anko.imageBitmap
@@ -39,18 +33,14 @@ import com.example.mear.repositories.*
import com.example.mear.repositories.RepeatRepository.RepeatTypes import com.example.mear.repositories.RepeatRepository.RepeatTypes
import com.example.mear.repositories.ShuffleRepository.ShuffleTypes import com.example.mear.repositories.ShuffleRepository.ShuffleTypes
import com.example.mear.util.ConvertByteArray import com.example.mear.util.ConvertByteArray
// import com.example.mear.workers.IcarusSyncManager import com.example.mear.workers.IcarusSyncManager
class MainActivity : BaseServiceActivity() { class MainActivity : BaseServiceActivity() {
private val ctx: Context? = this
private var coverArtHandler: Handler? = Handler()
private var musicHandler: Handler? = Handler() private var musicHandler: Handler? = Handler()
private var updateLibraryHandler: Handler? = Handler()
private var playCountUpdated: Boolean? = false private var playCountUpdated: Boolean? = false
private var serviceBinded: Boolean? = false private var serviceBinded: Boolean? = false
private var metadataInitialized: Boolean = false
private var repeatOn: Boolean? = false private var repeatOn: Boolean? = false
private var shuffleOn: Boolean? = false private var shuffleOn: Boolean? = false
@@ -58,18 +48,6 @@ class MainActivity : BaseServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
try { try {
/**
val workManager = WorkManager.getInstance()
val constraints = androidx.work.Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED).build()
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
.setConstraints(constraints).build()
workManager.enqueue(task)
*/
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
@@ -354,22 +332,6 @@ class MainActivity : BaseServiceActivity() {
return true return true
} }
// TODO: Might need this down the road for playing songs off an external
// storage
private fun permissionPrompt() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
}
else {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 0)
}
}
}
private fun showPopup(view: View) { private fun showPopup(view: View) {
try { try {
@@ -390,12 +352,9 @@ class MainActivity : BaseServiceActivity() {
startActivity(Intent(this, IcarusSongActivity::class.java)) startActivity(Intent(this, IcarusSongActivity::class.java))
} }
R.id.action_song_delete -> { R.id.action_song_delete -> {
// TODO: handle song deletion
val ss = true
val appPath = appDirectory() val appPath = appDirectory()
val trackRepo = TrackRepository() val trackRepo = TrackRepository()
// The method I am calling has not been implemented on the C++
// side
var currSong = musicService!!.getCurrentSong() var currSong = musicService!!.getCurrentSong()
Toast.makeText(this, "Deleting song", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Deleting song", Toast.LENGTH_SHORT).show()
val result = trackRepo.delete(currSong, appPath) val result = trackRepo.delete(currSong, appPath)
@@ -405,46 +364,49 @@ class MainActivity : BaseServiceActivity() {
} }
R.id.action_song_download -> { R.id.action_song_download -> {
val appPath = appDirectory() val appPath = appDirectory()
val apiRepo = APIRepository()
val tokenRepo = TokenRepository()
val trackRepo = TrackRepository()
var song = musicService!!.getCurrentSong() var song = musicService!!.getCurrentSong()
val token = tokenRepo.retrieveToken(appPath)
// val apiInfo = apiRepo.retrieveRecord(appPath)
// song = trackRepo.download(token, song, appPath)
// musicService!!.changeSongDownloadStatus(song)
// TODO: implement something to include the downloaded song into the songQueue
// essentially replacing the song that already exists, that way one can
// actually access the file without having to restart the app
Toast.makeText(this, "Downloading song", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Downloading song", Toast.LENGTH_SHORT).show()
// val dMgr = IcarusSyncManager
musicService!!.downloadSong(token, song, appPath)
//val workManager = WorkManager.getInstance()
/**
val constraints = androidx.work.Constraints.Builder() val constraints = androidx.work.Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED).build() .setRequiredNetworkType(NetworkType.CONNECTED).build()
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
.setConstraints(constraints)
val data = Data.Builder() val data = Data.Builder()
data.putString("accessToken", token.accessToken)
data.putString("appPath", appPath) data.putString("appPath", appPath)
data.putInt("songId", song.id) data.putInt("songId", song.id)
task.setInputData(data.build()) data.putString("songTitle", song.title)
*/ data.putString("songArtist", song.artist)
//workManager.enqueue(task) data.putString("songAlbum", song.album)
//WorkManager.getInstance().enqueue(task.build()) data.putString("songAlbumArtist", song.albumArtist)
data.putString("songGenre", song.genre)
data.putInt("songYear", song.year)
data.putInt("songDuration", song.duration)
data.putInt("songCoverArtId", song.coverArtId)
data.putBoolean("songDownloaded", false)
data.putInt("songDisc", song.disc)
data.putInt("songTrack", song.track)
val task = OneTimeWorkRequest.Builder(IcarusSyncManager::class.java)
.setInputData(data.build())
.setConstraints(constraints)
.build()
WorkManager.getInstance().enqueue(task)
WorkManager.getInstance(this).getWorkInfoByIdLiveData(task.id)
.observe(this, Observer { info ->
if (info != null && info.state.isFinished) {
song.path = info.outputData.getString("songPath")!!
song.filename = info.outputData.getString("songFilename")!!
song.downloaded = info.outputData.getBoolean("songDownloaded", true)!!
musicService!!.changeSongDownloadStatus(song)
}
})
} }
/** /**
R.id.action_song_play_count-> { R.id.action_song_play_count-> {
// TODO: not implemented // TODO: not implemented
val trk = musicService!!.getCurrentSong() val trk = musicService!!.getCurrentSong()
// val pc = PlayCountRepository(this).getPlayCount(trk.id)
// val playCount = pc.playCount
Toast.makeText(this, "Song played $playCount times", Toast.LENGTH_LONG).show() Toast.makeText(this, "Song played $playCount times", Toast.LENGTH_LONG).show()
} }
*/ */
@@ -87,7 +87,7 @@ class MusicService(var appPath: String = ""): Service() {
try { try {
trackPlayer!!.reset() trackPlayer!!.reset()
trackPlayer!!.setDataSource(this, uri, hddr) trackPlayer!!.setDataSource(this, uri, hddr)
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.start() trackPlayer!!.start()
} }
catch (ex: Exception) { catch (ex: Exception) {
@@ -102,14 +102,13 @@ class MusicService(var appPath: String = ""): Service() {
currentSong = song currentSong = song
currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id } currentSongIndex = songQueue.indexOfFirst { it.id == currentSong.id }
songQueue[currentSongIndex!!] = currentSong songQueue[currentSongIndex!!] = currentSong
/**
val curPosition = currentPositionOfTrack() val curPosition = currentPositionOfTrack()
trackPlayer!!.reset() trackPlayer!!.reset()
trackPlayer!!.setDataSource(currentSong.path) trackPlayer!!.setDataSource(currentSong.path)
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.seekTo(curPosition) trackPlayer!!.seekTo(curPosition)
trackPlayer!!.start() trackPlayer!!.start()
*/
} }
fun removeSongDownloadStatus(song: Song) { fun removeSongDownloadStatus(song: Song) {
@@ -179,7 +178,7 @@ class MusicService(var appPath: String = ""): Service() {
uri, hddr) uri, hddr)
} }
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.start() trackPlayer!!.start()
} }
} }
@@ -216,7 +215,7 @@ class MusicService(var appPath: String = ""): Service() {
APIRepository.retrieveSongStreamUri(apiInfo, currentSong), APIRepository.retrieveSongStreamUri(apiInfo, currentSong),
APIRepository.retrieveSongStreamHeader(token)) APIRepository.retrieveSongStreamHeader(token))
} }
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.start() trackPlayer!!.start()
} }
catch (ex: Exception) { catch (ex: Exception) {
@@ -266,7 +265,7 @@ class MusicService(var appPath: String = ""): Service() {
APIRepository.retrieveSongStreamHeader(token)) APIRepository.retrieveSongStreamHeader(token))
} }
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.setOnCompletionListener { trackPlayer!!.setOnCompletionListener {
playNextTrack() playNextTrack()
} }
@@ -302,7 +301,7 @@ class MusicService(var appPath: String = ""): Service() {
trackPlayer!!.reset() trackPlayer!!.reset()
trackPlayer!!.setDataSource(song.path) trackPlayer!!.setDataSource(song.path)
trackPlayer!!.prepareAsync() trackPlayer!!.prepare()
trackPlayer!!.start() trackPlayer!!.start()
} }
catch (ex: Exception) { catch (ex: Exception) {
@@ -1,21 +1,46 @@
package com.example.mear.workers package com.example.mear.workers
import android.content.Context import android.content.Context
import androidx.work.Data
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf
import com.example.mear.models.Song
import com.example.mear.repositories.TokenRepository
import com.example.mear.repositories.TrackRepository
class IcarusSyncManager(context: Context, workerParams: WorkerParameters) : class IcarusSyncManager(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) { Worker(context, workerParams) {
override fun doWork(): Result { override fun doWork(): Result {
//TODO perform your async operational task here val appPath: String = inputData.getString("appPath")!!
/** val songId = inputData.getInt("songId", 0)
* We have performed download task here on above example if (songId == 0) {
*/ return Result.failure()
val accessToken = inputData.getString("accessToken") }
val appPath = inputData.getString("appPath")
//val songId = inputData.getInt("songId")
return Result.success() val tokenRepo = TokenRepository()
val trackRepo = TrackRepository()
val tok = tokenRepo.retrieveToken(appPath)
val song = Song()
song.id = songId
song.title = inputData.getString("songTitle")!!
song.artist = inputData.getString("songArtist")!!
song.album = inputData.getString("songAlbum")!!
song.albumArtist = inputData.getString("songAlbumArtist")!!
song.genre = inputData.getString("songGenre")!!
song.year = inputData.getInt("songYear", 0)
song.duration = inputData.getInt("songDuration", 0)
song.coverArtId = inputData.getInt("songCoverArtId", 0)
song.disc = inputData.getInt("songDisc", 0)
song.track = inputData.getInt("songTrack", 0)
val downloadedSong = trackRepo.download(tok, song, appPath)
val output: Data = workDataOf("songPath" to downloadedSong.path,
"songFilename" to downloadedSong.filename,
"songDownloaded" to true)
return Result.success(output)
} }
} }