Skip to content

Commit d7d3228

Browse files
author
Leo Neat
committed
Moving DFS to separate file
1 parent ac86dc4 commit d7d3228

File tree

3 files changed

+190
-165
lines changed

3 files changed

+190
-165
lines changed

mediacontroller/src/main/java/com/example/android/mediacontroller/MediaAppControllerActivity.java

Lines changed: 17 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,7 @@ private class BrowseMediaItemsAdapter extends
11551155

11561156
private List<MediaBrowserCompat.MediaItem> mItems;
11571157
private final Stack<String> mNodes = new Stack<>();
1158+
private MediaBrowseTreeSnapshot mMediaBrowseTreeSnapshot;
11581159

11591160
MediaBrowserCompat.SubscriptionCallback callback =
11601161
new MediaBrowserCompat.SubscriptionCallback() {
@@ -1180,7 +1181,6 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
11801181
public void onBindViewHolder(@NonNull ViewHolder holder, int position){
11811182
Log.i(TAG, "On Bind view holder");
11821183
if (mNodes.size() == 0) {
1183-
Log.i(TAG, "Setting to no browser");
11841184
holder.name.setText(getString(R.string.media_no_browser));
11851185
holder.name.setVisibility(View.VISIBLE);
11861186
holder.description.setVisibility(View.GONE);
@@ -1268,7 +1268,6 @@ void updateItems(List items) {
12681268
* Assigns click handlers to the buttons if provided for moving to the top of the tree or
12691269
* for moving up one level in the tree.
12701270
*/
1271-
@RequiresApi(api = Build.VERSION_CODES.N)
12721271
void init(View topButtonView, View upButtonView, View saveButtonView) {
12731272
if (topButtonView != null) {
12741273
topButtonView.setOnClickListener(v -> {
@@ -1292,172 +1291,26 @@ void init(View topButtonView, View upButtonView, View saveButtonView) {
12921291
});
12931292
}
12941293
if (saveButtonView != null) {
1295-
1296-
// Go to root of browse tree
1297-
// TODO: Fix race condition with subscription callback
1298-
unsubscribe();
1299-
while (mNodes.size() > 1) {
1300-
mNodes.pop();
1301-
}
1302-
subscribe();
1303-
saveButtonView.setOnClickListener(
1304-
v -> {
1305-
1306-
if (mNodes.isEmpty()) {
1307-
Toast toast =
1308-
Toast.makeText(
1309-
getApplicationContext(),
1310-
"List Empty, nothing saved! ", Toast.LENGTH_LONG);
1311-
toast.setMargin(50, 50);
1312-
toast.show();
1313-
return;
1314-
}
1315-
1316-
// Create output file
1317-
File root = android.os.Environment.getExternalStorageDirectory();
1318-
String dirs_path = root.getAbsolutePath() + "/Temp/";
1319-
File dirs = new File(dirs_path);
1320-
dirs.mkdirs();
1321-
File file = new File(dirs.getAbsolutePath(),
1322-
"_BrowseTreeContent.txt");
1323-
if (file.exists()) {
1324-
file.delete();
1325-
}
1326-
try {
1327-
final FileOutputStream f = new FileOutputStream(file);
1328-
PrintWriter pw = new PrintWriter(f);
1329-
if(mItems == null){
1330-
Log.i(TAG, "Nodes: " + mNodes.toString());
1331-
subscribe();
1332-
Toast toast =
1333-
Toast.makeText(
1334-
getApplicationContext(),
1335-
"No media items found, could not save tree.",
1336-
Toast.LENGTH_LONG);
1337-
toast.setMargin(50, 50);
1338-
toast.show();
1339-
return;
1340-
}
1341-
pw.println("Root:");
1342-
Semaphore writeCompleted = new Semaphore(1);
1343-
ExecutorService executorService =
1344-
Executors.newFixedThreadPool(4);
1345-
executorService.execute(new Runnable() {
1346-
@Override
1347-
public void run() {
1348-
for (MediaBrowserCompat.MediaItem item : mItems) {
1349-
try {
1350-
writeCompleted.acquire();
1351-
} catch (InterruptedException e) {
1352-
e.printStackTrace();
1353-
}
1354-
writeMediaItemToFile(item, pw, 1,
1355-
executorService);
1356-
writeCompleted.release();
1357-
1358-
}
1359-
pw.flush();
1360-
pw.close();
1361-
try {
1362-
f.close();
1363-
} catch (IOException e) {
1364-
e.printStackTrace();
1365-
}
1366-
runOnUiThread(new Runnable() {
1367-
public void run() {
1368-
Toast toast =
1369-
Toast.makeText(
1370-
getApplicationContext(),
1371-
"MediaItems saved to " +
1372-
file.getAbsolutePath(),
1373-
Toast.LENGTH_LONG);
1374-
toast.setMargin(50, 50);
1375-
toast.show();
1376-
}
1377-
});
1378-
}
1379-
});
1380-
} catch (FileNotFoundException e) {
1381-
e.printStackTrace();
1382-
}
1383-
});
1384-
}
1385-
1386-
}
1387-
1388-
@RequiresApi(api = Build.VERSION_CODES.N)
1389-
private void writeMediaItemToFile(MediaItem mediaItem, PrintWriter printWriter, int depth,
1390-
ExecutorService executorService) {
1391-
if (mediaItem != null) {
1392-
MediaDescriptionCompat descriptionCompat = mediaItem.getDescription();
1393-
if (descriptionCompat != null) {
1394-
1395-
// Tab the media item to the respective depth
1396-
String tabStr = new String(new char[depth]).replace("\0",
1397-
"\t");
1398-
1399-
String titleStr = descriptionCompat.getTitle() != null
1400-
? descriptionCompat.getTitle().toString()
1401-
: "NAN";
1402-
String subTitleStr = descriptionCompat.getSubtitle() != null
1403-
? descriptionCompat.getSubtitle().toString()
1404-
: "NAN";
1405-
String mIDStr = descriptionCompat.getMediaId() != null
1406-
? descriptionCompat.getMediaId()
1407-
: "NAN";
1408-
String uriStr = descriptionCompat.getMediaUri() != null
1409-
? descriptionCompat.getMediaUri().toString()
1410-
: "NAN";
1411-
String desStr = descriptionCompat.getDescription() != null
1412-
? descriptionCompat.getDescription().toString()
1413-
: "NAN";
1414-
String infoStr = String.format(
1415-
"%sTitle:%s,Subtitle:%s,MediaId:%s,URI:%s,Description:%s",
1416-
tabStr, titleStr, subTitleStr, mIDStr, uriStr, desStr);
1417-
Log.i(TAG, "Logging media item: " + infoStr + " at depth: " + depth);
1418-
printWriter.println(infoStr);
1419-
}
1420-
// If a media item is not a leaf continue DFS on it
1421-
if (mediaItem.isBrowsable()) {
1422-
Log.i(TAG, "Media Item is browseable");
1423-
Semaphore loaded = new Semaphore(1);
1424-
try {
1425-
loaded.acquire();
1426-
} catch (InterruptedException e) {
1427-
e.printStackTrace();
1294+
saveButtonView.setOnClickListener(v -> {
1295+
if(mMediaBrowseTreeSnapshot != null) {
1296+
mMediaBrowseTreeSnapshot.takeBrowserSnapshot();
14281297
}
1429-
final List<MediaItem> mChildren = new ArrayList<MediaItem>();
1430-
executorService.execute(new Runnable() {
1431-
@Override
1432-
public void run() {
1433-
mBrowser.subscribe(mediaItem.getMediaId(),
1434-
new MediaBrowserCompat.SubscriptionCallback() {
1435-
@Override
1436-
public void onChildrenLoaded(@NonNull String parentId,
1437-
@NonNull List<MediaItem> children) {
1438-
// Notify the main thread that all of the children have loaded
1439-
mChildren.addAll(children);
1440-
loaded.release();
1441-
super.onChildrenLoaded(parentId, children);
1442-
}
1443-
});
1444-
}
1445-
});
1446-
1447-
// Wait for all of the media children to be loaded before continuing DFS
1448-
try {
1449-
loaded.acquire();
1450-
} catch (InterruptedException e) {
1451-
e.printStackTrace();
1298+
else if(mBrowser != null) {
1299+
mMediaBrowseTreeSnapshot = new MediaBrowseTreeSnapshot(mBrowser, getApplicationContext());
1300+
mMediaBrowseTreeSnapshot.takeBrowserSnapshot();
14521301
}
1453-
1454-
// Run DFS on all of the nodes children
1455-
for (MediaItem mediaItemChild : mChildren) {
1456-
writeMediaItemToFile(mediaItemChild, printWriter, depth + 1,
1457-
executorService);
1302+
else{
1303+
Log.e(TAG, "Media browser is null");
1304+
runOnUiThread(new Runnable() {
1305+
@Override
1306+
public void run() {
1307+
Toast.makeText(getApplicationContext(),"No media browser to snapshot", Toast.LENGTH_SHORT).show();
1308+
}
1309+
});
14581310
}
1459-
}
1311+
});
14601312
}
1313+
14611314
}
14621315

14631316
protected void subscribe() {

mediacontroller/src/main/java/com/example/android/mediacontroller/MediaAppListAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public void bindTo(RecyclerView.ViewHolder vh) {
124124
holder.appIconView.getContext().getString(R.string.app_icon_desc,
125125
appDetails.appName));
126126
holder.appNameView.setText(appDetails.appName);
127-
holder.appPackageView.setText(appDetails.packageName);
127+
//holder.appPackageView.setText(appDetails.packageName);
128128

129129
holder.controlButton.setOnClickListener(view ->
130130
appSelectedListener.onMediaAppClicked(appDetails, false));
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package com.example.android.mediacontroller
2+
3+
import android.content.Context
4+
import android.os.Environment
5+
import android.os.Handler
6+
import android.os.Looper
7+
import android.support.v4.media.MediaBrowserCompat
8+
import android.support.v4.media.MediaBrowserCompat.SubscriptionCallback
9+
import android.util.Log
10+
import android.widget.Toast
11+
import java.io.File
12+
import java.io.FileNotFoundException
13+
import java.io.FileOutputStream
14+
import java.io.IOException
15+
import java.io.PrintWriter
16+
import java.util.concurrent.ExecutorService
17+
import java.util.concurrent.Executors
18+
import java.util.concurrent.Semaphore
19+
20+
class MediaBrowseTreeSnapshot(private val mBrowser : MediaBrowserCompat, private val mContext: Context) {
21+
private val TAG = "MediaBrowseTreeSnapshot"
22+
23+
24+
fun takeBrowserSnapshot(){
25+
val loaded = Semaphore(1)
26+
val executorService = Executors.newFixedThreadPool(4)
27+
val mItems: MutableList<MediaBrowserCompat.MediaItem> = ArrayList()
28+
executorService.execute{
29+
try {
30+
loaded.acquire()
31+
} catch (e: InterruptedException) {
32+
e.printStackTrace()
33+
}
34+
mBrowser.subscribe(mBrowser.root, object : SubscriptionCallback() {
35+
override fun onChildrenLoaded(parentId: String,
36+
children: List<MediaBrowserCompat.MediaItem>) {
37+
// Notify the main thread that all of the children have loaded
38+
Log.i(TAG, "Children loaded for init")
39+
mItems.addAll(children)
40+
loaded.release()
41+
42+
super.onChildrenLoaded(parentId, children)
43+
}
44+
})
45+
// Wait for all of the media children to be loaded before starting snapshot
46+
try {
47+
loaded.acquire()
48+
} catch (e: InterruptedException) {
49+
e.printStackTrace()
50+
}
51+
52+
if(mItems.size > 0){
53+
takeBrowserSnapshotImpl(mItems, executorService)
54+
}
55+
else{
56+
notifyUser("No media items found, could not save tree.")
57+
}
58+
59+
}
60+
}
61+
62+
private fun takeBrowserSnapshotImpl(mItems: MutableList<MediaBrowserCompat.MediaItem>, executorService: ExecutorService){
63+
// Create output file
64+
65+
// Create output file
66+
val root = Environment.getExternalStorageDirectory()
67+
val dirsPath = root.absolutePath + "/Temp/"
68+
val dirs = File(dirsPath)
69+
dirs.mkdirs()
70+
val file = File(dirs.absolutePath,
71+
"_BrowseTreeContent.txt")
72+
if (file.exists()) {
73+
file.delete()
74+
}
75+
try {
76+
val f = FileOutputStream(file)
77+
val pw = PrintWriter(f)
78+
pw.println("Root:")
79+
val writeCompleted = Semaphore(1)
80+
executorService.execute {
81+
for (item in mItems) {
82+
try {
83+
writeCompleted.acquire()
84+
} catch (e: InterruptedException) {
85+
e.printStackTrace()
86+
}
87+
writeMediaItemToFile(item, pw, 1,
88+
executorService)
89+
writeCompleted.release()
90+
}
91+
pw.flush()
92+
pw.close()
93+
try {
94+
f.close()
95+
} catch (e: IOException) {
96+
e.printStackTrace()
97+
}
98+
notifyUser("MediaItems saved to " +
99+
file.absolutePath)
100+
}
101+
} catch (e: FileNotFoundException) {
102+
e.printStackTrace()
103+
}
104+
}
105+
106+
private fun writeMediaItemToFile(mediaItem: MediaBrowserCompat.MediaItem?, printWriter: PrintWriter, depth: Int,
107+
executorService: ExecutorService) {
108+
if (mediaItem != null) {
109+
val descriptionCompat = mediaItem.description
110+
111+
// Tab the media item to the respective depth
112+
val tabStr = String(CharArray(depth)).replace("\u0000",
113+
"\t")
114+
val titleStr = if (descriptionCompat.title != null) descriptionCompat.title.toString() else "NAN"
115+
val subTitleStr = if (descriptionCompat.subtitle != null) descriptionCompat.subtitle.toString() else "NAN"
116+
val mIDStr = if (descriptionCompat.mediaId != null) descriptionCompat.mediaId else "NAN"
117+
val uriStr = if (descriptionCompat.mediaUri != null) descriptionCompat.mediaUri.toString() else "NAN"
118+
val desStr = if (descriptionCompat.description != null) descriptionCompat.description.toString() else "NAN"
119+
val infoStr = String.format(
120+
"%sTitle:%s,Subtitle:%s,MediaId:%s,URI:%s,Description:%s",
121+
tabStr, titleStr, subTitleStr, mIDStr, uriStr, desStr)
122+
printWriter.println(infoStr)
123+
val mid = if (mediaItem.mediaId != null) mediaItem.mediaId!! else ""
124+
// If a media item is not a leaf continue DFS on it
125+
if (mediaItem.isBrowsable && mid != "") {
126+
val loaded = Semaphore(1)
127+
try {
128+
loaded.acquire()
129+
} catch (e: InterruptedException) {
130+
e.printStackTrace()
131+
}
132+
val mChildren: MutableList<MediaBrowserCompat.MediaItem> = ArrayList()
133+
executorService.execute {
134+
mBrowser.subscribe(mid,
135+
object : SubscriptionCallback() {
136+
override fun onChildrenLoaded(parentId: String,
137+
children: List<MediaBrowserCompat.MediaItem>) {
138+
// Notify the main thread that all of the children have loaded
139+
mChildren.addAll(children)
140+
loaded.release()
141+
super.onChildrenLoaded(parentId, children)
142+
}
143+
})
144+
}
145+
146+
// Wait for all of the media children to be loaded before continuing DFS
147+
try {
148+
loaded.acquire()
149+
} catch (e: InterruptedException) {
150+
e.printStackTrace()
151+
}
152+
153+
// Run DFS on all of the nodes children
154+
for (mediaItemChild in mChildren) {
155+
writeMediaItemToFile(mediaItemChild, printWriter, depth + 1,
156+
executorService)
157+
}
158+
}
159+
}
160+
}
161+
162+
private fun notifyUser(textToNotify: String) {
163+
Handler(Looper.getMainLooper()).post {
164+
val toast = Toast.makeText(
165+
mContext,
166+
textToNotify,
167+
Toast.LENGTH_LONG)
168+
toast.setMargin(50f, 50f)
169+
toast.show()
170+
}
171+
}
172+
}

0 commit comments

Comments
 (0)