-
Notifications
You must be signed in to change notification settings - Fork 140
[Infra] Adding a button to snapshot the current Media Browse Tree #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
ff4d395
c979015
ac86dc4
d7d3228
891ed0f
d5e4693
2c6fac8
0e80bcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| package com.example.android.mediacontroller | ||
|
|
||
| import android.content.Context | ||
| import android.os.Environment | ||
| import android.os.Handler | ||
| import android.os.Looper | ||
| import android.support.v4.media.MediaBrowserCompat | ||
| import android.support.v4.media.MediaBrowserCompat.SubscriptionCallback | ||
| import android.util.Log | ||
| import android.widget.Toast | ||
| import java.io.File | ||
| import java.io.FileOutputStream | ||
| import java.io.IOException | ||
| import java.io.PrintWriter | ||
| import java.util.concurrent.ExecutorService | ||
| import java.util.concurrent.Executors | ||
| import java.util.concurrent.Semaphore | ||
|
|
||
| class MediaBrowseTreeSnapshot(private val mBrowser: MediaBrowserCompat, private val mContext: Context) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kotlin doesn't use 'm' prefixes in parameters or member variables. nit: Ideally
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| private val TAG = "MediaBrowseTreeSnapshot" | ||
|
|
||
| fun takeBrowserSnapshot() { | ||
| val loaded = Semaphore(1) | ||
| val executorService = Executors.newFixedThreadPool(4) | ||
| val mItems: MutableList<MediaBrowserCompat.MediaItem> = ArrayList() | ||
| executorService.execute { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is in Kotlin, you should use suspend functions, not executors, to do the background work.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| try { | ||
| loaded.acquire() | ||
| } catch (e: InterruptedException) { | ||
| e.printStackTrace() | ||
| } | ||
| mBrowser.subscribe(mBrowser.root, object : SubscriptionCallback() { | ||
| override fun onChildrenLoaded(parentId: String, | ||
| children: List<MediaBrowserCompat.MediaItem>) { | ||
| // Notify the main thread that all of the children have loaded | ||
| Log.i(TAG, "Children loaded for init") | ||
| mItems.addAll(children) | ||
| loaded.release() | ||
|
|
||
| super.onChildrenLoaded(parentId, children) | ||
| } | ||
| }) | ||
|
|
||
| // Wait for all of the media children to be loaded before starting snapshot | ||
| try { | ||
| loaded.acquire() | ||
| } catch (e: InterruptedException) { | ||
| e.printStackTrace() | ||
| } | ||
|
|
||
| if (mItems.size > 0) { | ||
| initDFSOnBrowseTree(mItems, executorService) | ||
| } else { | ||
| notifyUser("No media items found, could not save tree.") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun initDFSOnBrowseTree(mItems: MutableList<MediaBrowserCompat.MediaItem>, executorService: ExecutorService) { | ||
| val root = Environment.getExternalStorageDirectory() | ||
| val dirsPath = root.absolutePath + "/Temp/" | ||
| val dirs = File(dirsPath) | ||
| dirs.mkdirs() | ||
| val file = File(dirs.absolutePath, | ||
| "_BrowseTreeContent.txt") | ||
| if (file.exists()) { | ||
| file.delete() | ||
| } | ||
| try { | ||
| val f = FileOutputStream(file) | ||
| val pw = PrintWriter(f) | ||
| runDFSOnBrowseTree(mItems, executorService, pw) | ||
| pw.flush() | ||
| pw.close() | ||
| f.close() | ||
| } catch (e: IOException) { | ||
| e.printStackTrace() | ||
| } | ||
| notifyUser("MediaItems saved to " + | ||
| file.absolutePath) | ||
| } | ||
|
|
||
| private fun runDFSOnBrowseTree(mItems: MutableList<MediaBrowserCompat.MediaItem>, executorService: ExecutorService, printWriter: PrintWriter) { | ||
| printWriter.println("Root:") | ||
| val writeCompleted = Semaphore(1) | ||
| executorService.execute { | ||
| for (item in mItems) { | ||
| try { | ||
| writeCompleted.acquire() | ||
| } catch (e: InterruptedException) { | ||
| e.printStackTrace() | ||
| } | ||
| visitMediaItemNode(item, printWriter, 1, | ||
| executorService) | ||
| writeCompleted.release() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun visitMediaItemNode(mediaItem: MediaBrowserCompat.MediaItem?, printWriter: PrintWriter, depth: Int, | ||
| executorService: ExecutorService) { | ||
| if (mediaItem != null) { | ||
| printMediaItemDescription(printWriter, mediaItem, depth) | ||
| val mid = if (mediaItem.mediaId != null) mediaItem.mediaId!! else "" | ||
|
|
||
| // If a media item is not a leaf continue DFS on it | ||
| if (mediaItem.isBrowsable && mid != "") { | ||
| val loaded = Semaphore(1) | ||
| try { | ||
| loaded.acquire() | ||
| } catch (e: InterruptedException) { | ||
| e.printStackTrace() | ||
| } | ||
| val mChildren: MutableList<MediaBrowserCompat.MediaItem> = ArrayList() | ||
| executorService.execute { | ||
| mBrowser.subscribe(mid, | ||
| object : SubscriptionCallback() { | ||
| override fun onChildrenLoaded(parentId: String, | ||
| children: List<MediaBrowserCompat.MediaItem>) { | ||
| // Notify the main thread that all of the children have loaded | ||
| mChildren.addAll(children) | ||
| loaded.release() | ||
| super.onChildrenLoaded(parentId, children) | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| // Wait for all of the media children to be loaded before continuing DFS | ||
| try { | ||
| loaded.acquire() | ||
| } catch (e: InterruptedException) { | ||
| e.printStackTrace() | ||
| } | ||
|
|
||
| // Run visit on all of the nodes children | ||
| for (mediaItemChild in mChildren) { | ||
| visitMediaItemNode(mediaItemChild, printWriter, depth + 1, | ||
| executorService) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun printMediaItemDescription(printWriter: PrintWriter, mediaItem: MediaBrowserCompat.MediaItem, depth: Int) { | ||
| val descriptionCompat = mediaItem.description | ||
| // Tab the media item to the respective depth | ||
| val tabStr = String(CharArray(depth)).replace("\u0000", | ||
| "\t") | ||
| val titleStr = if (descriptionCompat.title != null) descriptionCompat.title.toString() else "NAN" | ||
| val subTitleStr = if (descriptionCompat.subtitle != null) descriptionCompat.subtitle.toString() else "NAN" | ||
| val mIDStr = if (descriptionCompat.mediaId != null) descriptionCompat.mediaId else "NAN" | ||
| val uriStr = if (descriptionCompat.mediaUri != null) descriptionCompat.mediaUri.toString() else "NAN" | ||
| val desStr = if (descriptionCompat.description != null) descriptionCompat.description.toString() else "NAN" | ||
| val infoStr = String.format( | ||
| "%sTitle:%s,Subtitle:%s,MediaId:%s,URI:%s,Description:%s", | ||
| tabStr, titleStr, subTitleStr, mIDStr, uriStr, desStr) | ||
| printWriter.println(infoStr) | ||
| } | ||
|
|
||
| private fun notifyUser(textToNotify: String) { | ||
| Handler(Looper.getMainLooper()).post { | ||
| val toast = Toast.makeText( | ||
| mContext, | ||
| textToNotify, | ||
| Toast.LENGTH_LONG) | ||
| toast.setMargin(50f, 50f) | ||
| toast.show() | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.