1+ package com .example .musicplayerapp ;
12
2- // MainActivity.java
3- package com .example .rootfilepicker ;
4-
5- import android .Manifest ;
6- import android .app .Activity ;
3+ import android .app .Notification ;
4+ import android .app .NotificationChannel ;
5+ import android .app .NotificationManager ;
76import android .content .Intent ;
8- import android .content .pm .PackageManager ;
9- import android .net .Uri ;
7+ import android .os .Build ;
108import android .os .Bundle ;
11- import android .os .Environment ;
129import android .view .View ;
13- import android .widget .* ;
14- import androidx . annotation . NonNull ;
10+ import android .widget .Button ;
11+ import android . widget . Toast ;
1512import androidx .appcompat .app .AppCompatActivity ;
16- import androidx .core .app .ActivityCompat ;
17- import androidx .core .content .ContextCompat ;
18- import java .io .File ;
19- import java .io .FileWriter ;
20- import java .io .IOException ;
21- import java .util .*;
22- import java .io .BufferedReader ;
23- import java .io .InputStreamReader ;
13+ import android .media .MediaPlayer ;
14+ import android .net .Uri ;
2415
2516public class MainActivity extends AppCompatActivity {
2617
27- private void testRootAccess () {
28- try {
29- Process process = Runtime .getRuntime ().exec (new String []{"su" , "-c" , "id" });
30- BufferedReader reader = new BufferedReader (new InputStreamReader (process .getInputStream ()));
31- String output = reader .readLine ();
32- Toast .makeText (this , "su output: " + output , Toast .LENGTH_LONG ).show ();
33- } catch (Exception e ) {
34- Toast .makeText (this , "su failed: " + e .getMessage (), Toast .LENGTH_LONG ).show ();
35- }
36- }
37-
38- private List <String > fileFilter = new ArrayList <>();
39- private String typeUri = "path" ;
40- private static final int PERMISSION_REQUEST_CODE = 1 ;
41- private ListView listView ;
42- private File currentDirectory ;
43- private TextView tvCurrentPath ;
44- private FileListAdapter adapter ;
45- private final List <FileItem > fileItems = new ArrayList <>();
46- private final List <FileItem > selectedItems = new ArrayList <>();
47-
48-
18+ private MediaPlayer mediaPlayer ;
19+ private static final String CHANNEL_ID = "music_channel" ;
20+ private Button playButton , pauseButton , stopButton ;
4921
5022 @ Override
5123 protected void onCreate (Bundle savedInstanceState ) {
52- Intent intent = getIntent ();
53- if (intent != null && intent .hasExtra ("type_uri" )) {
54-
55- String extRaw = intent .getStringExtra ("extension" );
56- if (extRaw != null ) {
57- for (String ext : extRaw .split ("," )) {
58- fileFilter .add (ext .trim ().toLowerCase ());
59- }
60- }
61- typeUri = intent .getStringExtra ("type_uri" );
62-
63- }
6424 super .onCreate (savedInstanceState );
65- testRootAccess ();
66- // Lưu khi app thoát
67- Runtime .getRuntime ().addShutdownHook (new Thread (this ::saveSelectedPaths ));
68-
69-
70-
7125 setContentView (R .layout .activity_main );
7226
73- listView = findViewById (R .id .listview );
74- tvCurrentPath = findViewById (R .id .tv_current_path );
75- Button btnSave = findViewById (R .id .btn_save_list );
27+ // Khởi tạo các button
28+ playButton = findViewById (R .id .playButton );
29+ pauseButton = findViewById (R .id .pauseButton );
30+ stopButton = findViewById (R .id .stopButton );
7631
77- adapter = new FileListAdapter (this , fileItems , selectedItems );
78- listView .setAdapter (adapter );
32+ // Tạo Notification Channel (cho API 26+)
33+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
34+ NotificationChannel channel = new NotificationChannel (CHANNEL_ID , "Music Service" , NotificationManager .IMPORTANCE_LOW );
35+ NotificationManager manager = getSystemService (NotificationManager .class );
36+ manager .createNotificationChannel (channel );
37+ }
7938
80- SearchView searchView = findViewById (R .id .searchView );
81- searchView .setOnQueryTextListener (new SearchView .OnQueryTextListener () {
82- @ Override
83- public boolean onQueryTextSubmit (String query ) {
84- adapter .getFilter ().filter (query );
85- return true ;
86- }
39+ // Khởi tạo MediaPlayer
40+ mediaPlayer = MediaPlayer .create (this , Uri .parse ("android.resource://" + getPackageName () + "/" + R .raw .sample_music ));
8741
42+ // Chức năng Play
43+ playButton .setOnClickListener (new View .OnClickListener () {
8844 @ Override
89- public boolean onQueryTextChange (String newText ) {
90- adapter .getFilter ().filter (newText );
91- return true ;
92- }
93- });
94-
95-
96- listView .setOnItemClickListener ((adapterView , view , i , l ) -> {
97- FileItem item = fileItems .get (i );
98- File file = item .getFile ();
99- if (file .isDirectory ()) {
100- loadDirectory (file );
101- } else {
102- if (selectedItems .contains (item )) {
103- selectedItems .remove (item );
104- } else {
105- selectedItems .add (item );
45+ public void onClick (View v ) {
46+ if (!mediaPlayer .isPlaying ()) {
47+ mediaPlayer .start ();
48+ showNotification ("Playing Music" , "Sample Music" );
10649 }
107- adapter .notifyDataSetChanged ();
10850 }
10951 });
11052
111- listView . setOnItemLongClickListener (( adapterView , view , i , l ) -> {
112- FileItem item = fileItems . get ( i );
113- if ( item . getFile (). isDirectory ()) {
114- if ( selectedItems . contains ( item ) ) {
115- selectedItems . remove ( item );
116- } else {
117- selectedItems . add ( item );
53+ // Chức năng Pause
54+ pauseButton . setOnClickListener ( new View . OnClickListener () {
55+ @ Override
56+ public void onClick ( View v ) {
57+ if ( mediaPlayer . isPlaying ()) {
58+ mediaPlayer . pause ();
59+ showNotification ( "Music Paused" , "Sample Music" );
11860 }
119- adapter .notifyDataSetChanged ();
120- return true ;
12161 }
122- return false ;
12362 });
12463
125- btnSave .setOnClickListener (v -> {
126- saveSelectedPaths ();
127- finish (); // Thoát app sau khi lưu
128- });
129-
130- if (checkPermission ()) {
131- initFilePicker ();
132- } else {
133- requestPermission ();
134- }
135- }
136-
137- private void initFilePicker () {
138- currentDirectory = Environment .getExternalStorageDirectory ();
139- loadDirectory (currentDirectory );
140- }
141-
142- private void loadDirectory (File dir ) {
143- currentDirectory = dir ;
144- tvCurrentPath .setText (dir .getAbsolutePath ());
145- File [] files = dir .listFiles ();
146- fileItems .clear ();
147- if (files != null ) {
148- Arrays .sort (files , (f1 , f2 ) -> {
149- if (f1 .isDirectory () && !f2 .isDirectory ()) return -1 ;
150- if (!f1 .isDirectory () && f2 .isDirectory ()) return 1 ;
151- return f1 .getName ().compareToIgnoreCase (f2 .getName ());
152- });
153- for (File f : files ) {
154- if (!fileFilter .isEmpty () && f .isFile ()) {
155- boolean matched = false ;
156- for (String ext : fileFilter ) {
157- if (f .getName ().toLowerCase ().endsWith (ext )) {
158- matched = true ;
159- break ;
160- }
64+ // Chức năng Stop
65+ stopButton .setOnClickListener (new View .OnClickListener () {
66+ @ Override
67+ public void onClick (View v ) {
68+ if (mediaPlayer .isPlaying ()) {
69+ mediaPlayer .stop ();
70+ mediaPlayer = MediaPlayer .create (MainActivity .this , Uri .parse ("android.resource://" + getPackageName () + "/" + R .raw .sample_music ));
71+ showNotification ("Music Stopped" , "Sample Music" );
16172 }
162- if (!matched ) continue ;
163- }
164- fileItems .add (new FileItem (f ));
165- }
166- }
167- adapter .notifyDataSetChanged ();
168- }
169-
170- private void saveSelectedPaths () {
171- File outFile = new File (Environment .getExternalStorageDirectory (), "list.txt" );
172- try (FileWriter writer = new FileWriter (outFile )) {
173- for (FileItem item : selectedItems ) {
174- if ("uri" .equals (typeUri )) {
175- Uri uri = androidx .core .content .FileProvider .getUriForFile (
176- this ,
177- getApplicationContext ().getPackageName () + ".provider" ,
178- item .getFile ()
179- );
180- writer .write (uri .toString () + "\n " );
181- } else {
182- writer .write (item .getFile ().getAbsolutePath () + "\n " );
18373 }
184- }
185- Toast .makeText (this , "Đã lưu tại: " + outFile .getAbsolutePath (), Toast .LENGTH_LONG ).show ();
186- } catch (IOException e ) {
187- Toast .makeText (this , "Lỗi lưu file" , Toast .LENGTH_SHORT ).show ();
188- }
74+ });
18975 }
19076
191- private boolean checkPermission () {
192- return ContextCompat .checkSelfPermission (this , Manifest .permission .READ_EXTERNAL_STORAGE ) == PackageManager .PERMISSION_GRANTED ;
193- }
77+ private void showNotification (String title , String content ) {
78+ Notification notification = new Notification .Builder (this , CHANNEL_ID )
79+ .setContentTitle (title )
80+ .setContentText (content )
81+ .setSmallIcon (android .R .drawable .ic_media_play )
82+ .build ();
19483
195- private void requestPermission () {
196- ActivityCompat . requestPermissions ( this , new String []{ Manifest . permission . READ_EXTERNAL_STORAGE }, PERMISSION_REQUEST_CODE );
84+ NotificationManager manager = ( NotificationManager ) getSystemService ( NOTIFICATION_SERVICE );
85+ manager . notify ( 1 , notification );
19786 }
19887
19988 @ Override
200- public void onBackPressed () {
201- if (currentDirectory != null && !currentDirectory .getAbsolutePath ().equals ("/" )) {
202- loadDirectory (currentDirectory .getParentFile ());
203- } else {
204- saveSelectedPaths ();
205- super .onBackPressed ();
206- }
207- }
208-
209- @ Override
210- public void onRequestPermissionsResult (int requestCode , @ NonNull String [] permissions , @ NonNull int [] grantResults ) {
211- if (requestCode == PERMISSION_REQUEST_CODE ) {
212- if (grantResults .length > 0 && grantResults [0 ] == PackageManager .PERMISSION_GRANTED ) {
213- initFilePicker ();
214- } else {
215- Toast .makeText (this , "Permission denied" , Toast .LENGTH_SHORT ).show ();
216- }
89+ protected void onDestroy () {
90+ super .onDestroy ();
91+ if (mediaPlayer != null ) {
92+ mediaPlayer .release ();
21793 }
21894 }
219- }
95+ }
0 commit comments