18
18
import static androidx .media .MediaBrowserServiceCompat .BrowserRoot .EXTRA_SUGGESTED ;
19
19
import static java .util .Arrays .asList ;
20
20
21
+ import android .Manifest ;
21
22
import android .app .Activity ;
22
23
import android .app .PendingIntent ;
23
24
import android .content .Context ;
61
62
import androidx .appcompat .app .ActionBar ;
62
63
import androidx .appcompat .app .AppCompatActivity ;
63
64
import androidx .appcompat .widget .Toolbar ;
65
+ import androidx .core .app .ActivityCompat ;
64
66
import androidx .core .content .ContextCompat ;
65
67
import androidx .core .content .res .ResourcesCompat ;
66
68
import androidx .core .graphics .drawable .DrawableCompat ;
73
75
74
76
import com .google .android .material .tabs .TabLayout ;
75
77
78
+ import java .io .FileNotFoundException ;
79
+ import java .io .OutputStream ;
76
80
import java .util .ArrayList ;
77
81
import java .util .Collections ;
78
82
import java .util .Comparator ;
@@ -111,12 +115,16 @@ public class MediaAppControllerActivity extends AppCompatActivity {
111
115
// Key name for Intent extras.
112
116
private static final String APP_DETAILS_EXTRA =
113
117
"com.example.android.mediacontroller.APP_DETAILS_EXTRA" ;
118
+ private static final String DEFAULT_BROWSE_TREE_FILE_NAME = "_BrowseTreeContent.txt" ;
114
119
115
120
// Index values for spinner.
116
121
private static final int SEARCH_INDEX = 0 ;
117
122
private static final int MEDIA_ID_INDEX = 1 ;
118
123
private static final int URI_INDEX = 2 ;
119
124
125
+ // Used for user storage permission request
126
+ private static final int CREATE_DOCUMENT_REQUEST_FOR_SNAPSHOT = 1 ;
127
+
120
128
private MediaAppDetails mMediaAppDetails ;
121
129
private MediaControllerCompat mController ;
122
130
private MediaBrowserCompat mBrowser ;
@@ -143,6 +151,8 @@ public class MediaAppControllerActivity extends AppCompatActivity {
143
151
144
152
private ViewGroup mRatingViewGroup ;
145
153
154
+ private MediaBrowseTreeSnapshot mMediaBrowseTreeSnapshot ;
155
+
146
156
private final SparseArray <ImageButton > mActionButtonMap = new SparseArray <>();
147
157
148
158
/**
@@ -248,20 +258,20 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) {
248
258
browseTreeList .setHasFixedSize (true );
249
259
browseTreeList .setAdapter (mBrowseMediaItemsAdapter );
250
260
mBrowseMediaItemsAdapter .init (findViewById (R .id .media_browse_tree_top ),
251
- findViewById (R .id .media_browse_tree_up ));
261
+ findViewById (R .id .media_browse_tree_up ), findViewById ( R . id . media_browse_tree_save ) );
252
262
253
263
final RecyclerView browseTreeListExtraSuggested = findViewById (R .id .media_items_list_extra_suggested );
254
264
browseTreeListExtraSuggested .setLayoutManager (new LinearLayoutManager (this ));
255
265
browseTreeListExtraSuggested .setHasFixedSize (true );
256
266
browseTreeListExtraSuggested .setAdapter (mBrowseMediaItemsExtraSuggestedAdapter );
257
267
mBrowseMediaItemsExtraSuggestedAdapter .init (findViewById (R .id .media_browse_tree_top_extra_suggested ),
258
- findViewById (R .id .media_browse_tree_up_extra_suggested ));
268
+ findViewById (R .id .media_browse_tree_up_extra_suggested ), findViewById ( R . id . media_browse_tree_save ) );
259
269
260
270
final RecyclerView searchItemsList = findViewById (R .id .search_items_list );
261
271
searchItemsList .setLayoutManager (new LinearLayoutManager (this ));
262
272
searchItemsList .setHasFixedSize (true );
263
273
searchItemsList .setAdapter (mSearchMediaItemsAdapter );
264
- mSearchMediaItemsAdapter .init (null , null );
274
+ mSearchMediaItemsAdapter .init (null , null , null );
265
275
266
276
findViewById (R .id .search_button ).setOnClickListener (v -> {
267
277
CharSequence queryText = ((TextView ) findViewById (R .id .search_query )).getText ();
@@ -271,6 +281,28 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) {
271
281
});
272
282
}
273
283
284
+ @ Override
285
+ protected void onActivityResult (int requestCode , int resultCode , @ Nullable Intent data ) {
286
+ super .onActivityResult (requestCode , resultCode , data );
287
+ if (requestCode == CREATE_DOCUMENT_REQUEST_FOR_SNAPSHOT ) {
288
+ if (resultCode == RESULT_OK && mMediaBrowseTreeSnapshot != null ) {
289
+ Uri uri = data .getData ();
290
+ OutputStream outputStream = null ;
291
+ try {
292
+ outputStream = getContentResolver ().openOutputStream (uri );
293
+ } catch (FileNotFoundException e ) {
294
+ e .printStackTrace ();
295
+ }
296
+ mMediaBrowseTreeSnapshot .takeBrowserSnapshot (outputStream );
297
+ Toast .makeText (this , "Output file location: " + uri .getPath (), Toast .LENGTH_SHORT ).show ();
298
+ } else {
299
+ Toast .makeText (this , "File could not be saved." , Toast .LENGTH_SHORT ).show ();
300
+ }
301
+
302
+
303
+ }
304
+ }
305
+
274
306
@ Override
275
307
protected void onDestroy () {
276
308
if (mController != null ) {
@@ -1102,7 +1134,7 @@ private class BrowseMediaItemsAdapter extends
1102
1134
RecyclerView .Adapter <BrowseMediaItemsAdapter .ViewHolder > {
1103
1135
1104
1136
private List <MediaBrowserCompat .MediaItem > mItems ;
1105
- private Stack <String > mNodes = new Stack <>();
1137
+ private final Stack <String > mNodes = new Stack <>();
1106
1138
1107
1139
MediaBrowserCompat .SubscriptionCallback callback =
1108
1140
new MediaBrowserCompat .SubscriptionCallback () {
@@ -1206,7 +1238,7 @@ void updateItems(List items) {
1206
1238
* Assigns click handlers to the buttons if provided for moving to the top of the tree or
1207
1239
* for moving up one level in the tree.
1208
1240
*/
1209
- void init (View topButtonView , View upButtonView ) {
1241
+ void init (View topButtonView , View upButtonView , View saveButtonView ) {
1210
1242
if (topButtonView != null ) {
1211
1243
topButtonView .setOnClickListener (v -> {
1212
1244
if (mNodes .size () > 1 ) {
@@ -1228,6 +1260,38 @@ void init(View topButtonView, View upButtonView) {
1228
1260
}
1229
1261
});
1230
1262
}
1263
+ if (saveButtonView != null ) {
1264
+ saveButtonView .setOnClickListener (v -> {
1265
+ takeMediaBrowseTreeSnapshot ();
1266
+ });
1267
+ }
1268
+
1269
+ }
1270
+
1271
+ private void takeMediaBrowseTreeSnapshot (){
1272
+ if (mBrowser != null ) {
1273
+ if (mMediaBrowseTreeSnapshot == null ) {
1274
+ mMediaBrowseTreeSnapshot = new MediaBrowseTreeSnapshot (
1275
+ MediaAppControllerActivity .this , mBrowser );
1276
+ }
1277
+ Intent saveTextFileIntent = new Intent (Intent .ACTION_CREATE_DOCUMENT );
1278
+ saveTextFileIntent .addCategory (Intent .CATEGORY_OPENABLE );
1279
+ saveTextFileIntent .setType ("text/plain" );
1280
+ saveTextFileIntent .putExtra (
1281
+ Intent .EXTRA_TITLE , DEFAULT_BROWSE_TREE_FILE_NAME );
1282
+ MediaAppControllerActivity .this .startActivityForResult (saveTextFileIntent ,
1283
+ CREATE_DOCUMENT_REQUEST_FOR_SNAPSHOT );
1284
+
1285
+ }else {
1286
+ Log .e (TAG , "Media browser is null" );
1287
+ runOnUiThread (new Runnable () {
1288
+ @ Override
1289
+ public void run () {
1290
+ Toast .makeText (getApplicationContext (),"No media browser to snapshot" ,
1291
+ Toast .LENGTH_SHORT ).show ();
1292
+ }
1293
+ });
1294
+ }
1231
1295
}
1232
1296
1233
1297
protected void subscribe () {
@@ -1284,7 +1348,8 @@ private class SearchMediaItemsAdapter extends BrowseMediaItemsAdapter {
1284
1348
@ Override
1285
1349
protected void subscribe () {
1286
1350
if (treeDepth () == 1 ) {
1287
- mBrowser .search (getCurrentNode (), null , new MediaBrowserCompat .SearchCallback () {
1351
+ mBrowser .search (getCurrentNode (), null ,
1352
+ new MediaBrowserCompat .SearchCallback () {
1288
1353
@ Override
1289
1354
public void onSearchResult (@ NonNull String query , Bundle extras ,
1290
1355
@ NonNull List <MediaBrowserCompat .MediaItem > items ) {
0 commit comments