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 ;
33
34
import android .os .RemoteException ;
34
35
import android .support .v4 .media .MediaBrowserCompat ;
35
36
import android .support .v4 .media .MediaBrowserCompat .MediaItem ;
37
+ import android .support .v4 .media .MediaDescriptionCompat ;
36
38
import android .support .v4 .media .MediaMetadataCompat ;
37
39
import android .support .v4 .media .RatingCompat ;
38
40
import android .support .v4 .media .session .MediaControllerCompat ;
61
63
import androidx .appcompat .app .ActionBar ;
62
64
import androidx .appcompat .app .AppCompatActivity ;
63
65
import androidx .appcompat .widget .Toolbar ;
66
+ import androidx .core .app .ActivityCompat ;
64
67
import androidx .core .content .ContextCompat ;
65
68
import androidx .core .content .res .ResourcesCompat ;
66
69
import androidx .core .graphics .drawable .DrawableCompat ;
73
76
74
77
import com .google .android .material .tabs .TabLayout ;
75
78
79
+ import java .io .File ;
80
+ import java .io .FileNotFoundException ;
81
+ import java .io .FileOutputStream ;
82
+ import java .io .IOException ;
83
+ import java .io .PrintWriter ;
76
84
import java .util .ArrayList ;
77
85
import java .util .Collections ;
78
86
import java .util .Comparator ;
@@ -117,6 +125,9 @@ public class MediaAppControllerActivity extends AppCompatActivity {
117
125
private static final int MEDIA_ID_INDEX = 1 ;
118
126
private static final int URI_INDEX = 2 ;
119
127
128
+ // Used for user storage permission request
129
+ private static final int STORAGE_PERMISSION_REQUEST = 1 ;
130
+
120
131
private MediaAppDetails mMediaAppDetails ;
121
132
private MediaControllerCompat mController ;
122
133
private MediaBrowserCompat mBrowser ;
@@ -153,7 +164,7 @@ public class MediaAppControllerActivity extends AppCompatActivity {
153
164
* @return An Intent that can be used to start the Activity.
154
165
*/
155
166
public static Intent buildIntent (final Activity activity ,
156
- final MediaAppDetails appDetails ) {
167
+ final MediaAppDetails appDetails ) {
157
168
final Intent intent = new Intent (activity , MediaAppControllerActivity .class );
158
169
intent .putExtra (APP_DETAILS_EXTRA , appDetails );
159
170
return intent ;
@@ -167,6 +178,8 @@ protected void onCreate(Bundle savedInstanceState) {
167
178
setSupportActionBar (toolbar );
168
179
getSupportActionBar ().setDisplayHomeAsUpEnabled (true );
169
180
toolbar .setNavigationOnClickListener (v -> finish ());
181
+ String [] permissions = {Manifest .permission .WRITE_EXTERNAL_STORAGE };
182
+ ActivityCompat .requestPermissions (MediaAppControllerActivity .this , permissions , STORAGE_PERMISSION_REQUEST );
170
183
171
184
mViewPager = findViewById (R .id .view_pager );
172
185
mInputTypeView = findViewById (R .id .input_type );
@@ -248,20 +261,20 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) {
248
261
browseTreeList .setHasFixedSize (true );
249
262
browseTreeList .setAdapter (mBrowseMediaItemsAdapter );
250
263
mBrowseMediaItemsAdapter .init (findViewById (R .id .media_browse_tree_top ),
251
- findViewById (R .id .media_browse_tree_up ));
264
+ findViewById (R .id .media_browse_tree_up ), findViewById ( R . id . media_browse_tree_save ) );
252
265
253
266
final RecyclerView browseTreeListExtraSuggested = findViewById (R .id .media_items_list_extra_suggested );
254
267
browseTreeListExtraSuggested .setLayoutManager (new LinearLayoutManager (this ));
255
268
browseTreeListExtraSuggested .setHasFixedSize (true );
256
269
browseTreeListExtraSuggested .setAdapter (mBrowseMediaItemsExtraSuggestedAdapter );
257
270
mBrowseMediaItemsExtraSuggestedAdapter .init (findViewById (R .id .media_browse_tree_top_extra_suggested ),
258
- findViewById (R .id .media_browse_tree_up_extra_suggested ));
271
+ findViewById (R .id .media_browse_tree_up_extra_suggested ), findViewById ( R . id . media_browse_tree_save ) );
259
272
260
273
final RecyclerView searchItemsList = findViewById (R .id .search_items_list );
261
274
searchItemsList .setLayoutManager (new LinearLayoutManager (this ));
262
275
searchItemsList .setHasFixedSize (true );
263
276
searchItemsList .setAdapter (mSearchMediaItemsAdapter );
264
- mSearchMediaItemsAdapter .init (null , null );
277
+ mSearchMediaItemsAdapter .init (null , null , null );
265
278
266
279
findViewById (R .id .search_button ).setOnClickListener (v -> {
267
280
CharSequence queryText = ((TextView ) findViewById (R .id .search_query )).getText ();
@@ -271,6 +284,34 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) {
271
284
});
272
285
}
273
286
287
+
288
+
289
+ @ Override
290
+ public void onRequestPermissionsResult (int requestCode ,
291
+ @ NonNull String [] permissions ,
292
+ @ NonNull int [] grantResults )
293
+ {
294
+ super .onRequestPermissionsResult (requestCode ,
295
+ permissions ,
296
+ grantResults );
297
+
298
+ if (requestCode == STORAGE_PERMISSION_REQUEST ) {
299
+ if (grantResults .length > 0
300
+ && grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
301
+ Toast .makeText (getApplicationContext (),
302
+ "Storage Permission Granted, can save browse tree." ,
303
+ Toast .LENGTH_SHORT )
304
+ .show ();
305
+ }
306
+ else {
307
+ Toast .makeText (getApplicationContext (),
308
+ "Storage Permission Denied, can not save browse tree to file." ,
309
+ Toast .LENGTH_SHORT )
310
+ .show ();
311
+ }
312
+ }
313
+ }
314
+
274
315
@ Override
275
316
protected void onDestroy () {
276
317
if (mController != null ) {
@@ -786,7 +827,7 @@ private void showActions(@PlaybackStateCompat.Actions long actions) {
786
827
}
787
828
788
829
private boolean actionSupported (@ PlaybackStateCompat .Actions long actions ,
789
- @ PlaybackStateCompat .Actions long checkAction ) {
830
+ @ PlaybackStateCompat .Actions long checkAction ) {
790
831
return ((actions & checkAction ) != 0 );
791
832
}
792
833
@@ -813,8 +854,8 @@ private static class AudioFocusHelper
813
854
private final Spinner mFocusTypeSpinner ;
814
855
815
856
private AudioFocusHelper (@ NonNull Context context ,
816
- @ NonNull ToggleButton focusToggleButton ,
817
- @ NonNull Spinner focusTypeSpinner ) {
857
+ @ NonNull ToggleButton focusToggleButton ,
858
+ @ NonNull Spinner focusTypeSpinner ) {
818
859
819
860
mAudioManager = (AudioManager ) context .getSystemService (AUDIO_SERVICE );
820
861
mToggleButton = focusToggleButton ;
@@ -932,7 +973,7 @@ public int getItemCount() {
932
973
}
933
974
934
975
void setActions (MediaControllerCompat controller ,
935
- List <PlaybackStateCompat .CustomAction > actions ) {
976
+ List <PlaybackStateCompat .CustomAction > actions ) {
936
977
mControls = controller .getTransportControls ();
937
978
try {
938
979
mMediaAppResources = getPackageManager ()
@@ -994,9 +1035,9 @@ private static abstract class ModeHelper implements AdapterView.OnItemSelectedLi
994
1035
private final List <Integer > modes ;
995
1036
996
1037
ModeHelper (ViewGroup container ,
997
- @ IdRes int stateSpinnerView ,
998
- @ IdRes int iconImageView ,
999
- List <Integer > modes ) {
1038
+ @ IdRes int stateSpinnerView ,
1039
+ @ IdRes int iconImageView ,
1040
+ List <Integer > modes ) {
1000
1041
this .context = container .getContext ();
1001
1042
this .spinner = container .findViewById (stateSpinnerView );
1002
1043
this .icon = container .findViewById (iconImageView );
@@ -1108,7 +1149,7 @@ private class BrowseMediaItemsAdapter extends
1108
1149
new MediaBrowserCompat .SubscriptionCallback () {
1109
1150
@ Override
1110
1151
public void onChildrenLoaded (@ NonNull String parentId ,
1111
- @ NonNull List <MediaItem > children ) {
1152
+ @ NonNull List <MediaItem > children ) {
1112
1153
updateItemsEmptyIfNull (children );
1113
1154
}
1114
1155
};
@@ -1206,7 +1247,7 @@ void updateItems(List items) {
1206
1247
* Assigns click handlers to the buttons if provided for moving to the top of the tree or
1207
1248
* for moving up one level in the tree.
1208
1249
*/
1209
- void init (View topButtonView , View upButtonView ) {
1250
+ void init (View topButtonView , View upButtonView , View saveButtonView ) {
1210
1251
if (topButtonView != null ) {
1211
1252
topButtonView .setOnClickListener (v -> {
1212
1253
if (mNodes .size () > 1 ) {
@@ -1228,6 +1269,92 @@ void init(View topButtonView, View upButtonView) {
1228
1269
}
1229
1270
});
1230
1271
}
1272
+ if (saveButtonView != null ) {
1273
+ notifyDataSetChanged ();
1274
+ saveButtonView .setOnClickListener (
1275
+ v -> {
1276
+
1277
+ if (mNodes .isEmpty ()) {
1278
+ Toast toast =
1279
+ Toast .makeText (
1280
+ getApplicationContext (), "List Empty, nothing saved! " , Toast .LENGTH_LONG );
1281
+ toast .setMargin (50 , 50 );
1282
+ toast .show ();
1283
+ return ;
1284
+ }
1285
+ File root = android .os .Environment .getExternalStorageDirectory ();
1286
+ try {
1287
+ String dirs_path = root .getAbsolutePath () + "/Temp/" ;
1288
+ File dirs = new File (dirs_path );
1289
+ File file = new File (dirs .getAbsolutePath (), "_BrowseTreeContent.txt" );
1290
+ FileOutputStream f = new FileOutputStream (file );
1291
+ PrintWriter pw = new PrintWriter (f );
1292
+ // We print the file path at the beginning of the file so that we can use it
1293
+ // to pull the file from platform to local computer.
1294
+
1295
+ pw .println (file .toString ());
1296
+ if (mItems == null ){
1297
+ Toast toast =
1298
+ Toast .makeText (
1299
+ getApplicationContext (),
1300
+ "No media items found, could not save tree." ,
1301
+ Toast .LENGTH_LONG );
1302
+ toast .setMargin (50 , 50 );
1303
+ toast .show ();
1304
+ return ;
1305
+ }
1306
+
1307
+ for (MediaBrowserCompat .MediaItem item : mItems ) {
1308
+ if (item != null ) {
1309
+ Log .i (TAG , "Logging media item" );
1310
+ MediaDescriptionCompat descriptionCompat = item .getDescription ();
1311
+ if (descriptionCompat != null ) {
1312
+ String infoStr = "Title:" ;
1313
+ infoStr += descriptionCompat .getTitle () != null
1314
+ ? descriptionCompat .getTitle ().toString ()
1315
+ : "NAN" ;
1316
+
1317
+ infoStr += ",Subtitle:" ;
1318
+ infoStr += descriptionCompat .getSubtitle () != null
1319
+ ? descriptionCompat .getSubtitle ().toString ()
1320
+ : "NAN" ;
1321
+
1322
+ infoStr += ",MediaId:" ;
1323
+ infoStr += descriptionCompat .getMediaId () != null
1324
+ ? descriptionCompat .getMediaId ().toString ()
1325
+ : "NAN" ;
1326
+ infoStr += ",Uri:" ;
1327
+ infoStr += descriptionCompat .getMediaUri () != null
1328
+ ? descriptionCompat .getMediaUri ().toString ()
1329
+ : "NAN" ;
1330
+ infoStr += ",Description:" ;
1331
+ infoStr += descriptionCompat .getDescription () != null
1332
+ ? descriptionCompat .getDescription ().toString ()
1333
+ : "NAN" ;
1334
+
1335
+ pw .println (infoStr );
1336
+ }
1337
+ }
1338
+ }
1339
+
1340
+ pw .flush ();
1341
+ pw .close ();
1342
+ f .close ();
1343
+ Toast toast =
1344
+ Toast .makeText (
1345
+ getApplicationContext (),
1346
+ "MediaItems saved to " + file .getAbsolutePath (),
1347
+ Toast .LENGTH_LONG );
1348
+ toast .setMargin (50 , 50 );
1349
+ toast .show ();
1350
+ } catch (FileNotFoundException e ) {
1351
+ e .printStackTrace ();
1352
+ } catch (IOException e ) {
1353
+ e .printStackTrace ();
1354
+ }
1355
+ });
1356
+ }
1357
+
1231
1358
}
1232
1359
1233
1360
protected void subscribe () {
@@ -1287,7 +1414,7 @@ protected void subscribe() {
1287
1414
mBrowser .search (getCurrentNode (), null , new MediaBrowserCompat .SearchCallback () {
1288
1415
@ Override
1289
1416
public void onSearchResult (@ NonNull String query , Bundle extras ,
1290
- @ NonNull List <MediaBrowserCompat .MediaItem > items ) {
1417
+ @ NonNull List <MediaBrowserCompat .MediaItem > items ) {
1291
1418
if (query .equals (getCurrentNode ())) {
1292
1419
updateItemsEmptyIfNull (items );
1293
1420
}
@@ -1311,4 +1438,4 @@ protected void unsubscribe() {
1311
1438
super .unsubscribe ();
1312
1439
}
1313
1440
}
1314
- }
1441
+ }
0 commit comments