<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:id="@+id/tab_layout"
app:tabIndicatorFullWidth="true"
app:tabIndicatorGravity="center"
app:tabTextColor="@color/colorAccent"
app:tabIndicatorHeight="40dp"
app:tabIndicatorColor="#009688"
app:tabIndicator="@drawable/tab_indicator"/>
2. ViewPager
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:id="@+id/tab_layout"
app:tabIndicatorFullWidth="true"
app:tabIndicatorGravity="center"
app:tabTextColor="@color/colorAccent"
app:tabIndicatorHeight="40dp"
app:tabIndicatorColor="#009688"
app:tabIndicator="@drawable/tab_indicator"/>
public static class ViewPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments;
private ArrayList<String> titles;
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<>();
this.titles = new ArrayList<>();
}
void addFragments(Fragment fragment, String title){
fragments.add(fragment);
titles.add(title);
}
@NonNull
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient android:centerColor="@color/colorPrimaryDark" android:angle="0"/>
</shape>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
permission();
}
private void permission() {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_CODE);
}
else
{
musicFiles = getAllAudio(this);
initViewPager();
}
}
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE)
{
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
//Do whatever you want permission related;
musicFiles = getAllAudio(this);
initViewPager();
}
else
{
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_CODE);
}
}
}
public ArrayList<MusicFiles> getAllAudio (Context context)
{
ArrayList<MusicFiles> tempAudioList = new ArrayList<>();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] projection =
{
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATA, //for path
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media._ID
};
Cursor cursor = context.getContentResolver().query(uri,projection,null,null, order);
if (cursor != null)
{
while (cursor.moveToNext())
{
String album = cursor.getString(0);
String title = cursor.getString(1);
String duration = cursor.getString(2);
String path = cursor.getString(3);
String artist = cursor.getString(4);
String id = cursor.getString(5);
MusicFiles musicFiles = new MusicFiles(path, title, artist, album, duration, id);
//take log.e for check
Log.e("Path:" + path, "Album" + album);
tempAudioList.add(musicFiles);
if (!duplicate.contains(album)) {
albums.add(musicFiles);
duplicate.add(album);
}
}
cursor.close();
}
return tempAudioList;
}
3. Import Glide dependency to build.gradle (Module: app)
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
-
ImageView's scaleType
5. Add FloatingActionButton in activity_player.xml
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/play_pause"
android:src="@drawable/ic_play"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:focusable="true"
android:clickable="true"/>
-
Commit the FUNC of itemview.click
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, PlayerActivity.class);
intent.putExtra("position",position);
mContext.startActivity(intent);
}
});
4. MusicAdapter.java to add intent.putExtra()
intent.putExtra("position",position);
position = getIntent().getIntExtra("position",-1);
private void getIntentMethod() {
position = getIntent().getIntExtra("position",-1);
String sender = getIntent().getStringExtra("sender");
if (sender != null && sender.equals("albumDetails"))
{
listSongs = albumFiles;
}
else
{
listSongs = mFiles;
}
if (listSongs != null)
{
playPauseBtn.setImageResource(R.drawable.ic_pause);
uri = Uri.parse(listSongs.get(position).getPath());
}
if (mediaPlayer != null)
{
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
else
{
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
}
seekBar.setMax(mediaPlayer.getDuration() / 1000);
metaData(uri);
}
-
runOnUiThread Thread collocate with Handler
private void metaData(Uri uri)
{
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri.toString());
int durationTotal = Integer.parseInt(listSongs.get(position).getDuration()) / 1000;
duration_total.setText(formattedTime(durationTotal));
byte[] art = retriever.getEmbeddedPicture();
if (art != null)
{
Glide.with(this)
.asBitmap()
.load(art)
.into(cover_art);
}
else
{
Glide.with(this)
.asBitmap()
.load(R.drawable.bewedoc)
.into(cover_art);
}
}
song_name.setText(listSongs.get(position).getTitle());
artist_name.setText(listSongs.get(position).getArtist());
//the animation of songs_changing
public void ImageAnimation(final Context context, final ImageView imageView, final Bitmap bitmap)
{
Animation animOut = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
final Animation animIn = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
animOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
Glide.with(context).load(bitmap).into(imageView);
animIn.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
imageView.startAnimation(animIn);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
imageView.startAnimation(animOut);
}
public class PlayerActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener{
@Override
public void onCompletion(MediaPlayer mp) {
nextBtnClicked();
if (mediaPlayer != null)
{
mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
mediaPlayer.start();
mediaPlayer.setOnCompletionListener(this);
}
}
static boolean shuffleBoolean = false, repeatBoolean = false;
shuffleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (shuffleBoolean)
{
shuffleBoolean = false;
shuffleBtn.setImageResource(R.drawable.ic_shuffle_off);
}
else
{
shuffleBoolean = true;
shuffleBtn.setImageResource(R.drawable.ic_shuffle_on);
}
}
});
if (shuffleBoolean && !repeatBoolean)
{
position = getRandom(listSongs.size() - 1);
}
else if (!shuffleBoolean && !repeatBoolean)
{
position = ((position - 1) < 0 ? (listSongs.size() - 1) : (position - 1));
}
private int getRandom(int i) {
Random random = new Random();
return random.nextInt(i + 1); //i => listsongs.size
}
<ImageView
android:layout_width="60dp"
android:layout_height="60dp"
android:id="@+id/menuMore"
android:src="@drawable/ic_baseline_more"
android:layout_alignParentEnd="true"
android:padding="10dp"/>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title="Delete"
android:id="@+id/delete"
app:showAsAction="never"/>
</menu>
holder.menuMore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
PopupMenu popupMenu = new PopupMenu(mContext, view);
popupMenu.getMenuInflater().inflate(R.menu.popup, popupMenu.getMenu());
popupMenu.show();
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId())
{
case R.id.delete:
Toast.makeText(mContext, "Delete Clicked!!!", Toast.LENGTH_SHORT).show();
deleteFile(position, view);
break;
}
return true;
}
});
}
});
private void deleteFile(int position, View v)
{
Uri contentUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
Long.parseLong(mFiles.get(position).getId())); // content://
File file = new File(mFiles.get(position).getPath());
boolean deleted = file.delete();//delete your file
if (deleted)
{
mContext.getContentResolver().delete(contentUri, null, null);
mFiles.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mFiles.size());
Snackbar.make(v, "File Deleted:", Snackbar.LENGTH_LONG).show();
}
else //maybe file in sd-card
{
Snackbar.make(v, "Can't be Deleted:", Snackbar.LENGTH_LONG).show();
}
}
public class MusicFiles {
private String path;
private String title;
private String artist;
private String album;
private String duration;
private String id;
public MusicFiles(String path, String title, String artist, String album, String duration, String id) {
this.path = path;
this.title = title;
this.artist = artist;
this.album = album;
this.duration = duration;
this.id = id;
}
while (cursor.moveToNext())
{
String album = cursor.getString(0);
String title = cursor.getString(1);
String duration = cursor.getString(2);
String path = cursor.getString(3);
String artist = cursor.getString(4);
String id = cursor.getString(5);
MusicFiles musicFiles = new MusicFiles(path, title, artist, album, duration, id);
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="170dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/album_items"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
android:layout_margin="10dp"
android:layout_height="200dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:id="@+id/relative_layout">
<ImageView
android:layout_width="match_parent"
android:layout_height="170dp"
android:id="@+id/album_image"
android:src="@mipmap/ic_launcher"/>
<TextView
android:layout_width="140dp"
android:layout_height="wrap_content"
android:id="@+id/album_name"
android:layout_alignParentBottom="true"
android:text="Album"
android:textColor="#ffffff"
android:singleLine="true"
android:gravity="center_horizontal"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:textStyle="bold"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
RecyclerView recyclerView;
AlbumAdapter albumAdapter;
recyclerView = view.findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
if (!(musicFiles.size() < 1))
{
albumAdapter = new AlbumAdapter(getContext(),musicFiles);
recyclerView.setAdapter(albumAdapter);
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
}
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclerView"
android:background="#1C1C1C"/>
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.MyHolder>
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, AlbumDetails.class);
intent.putExtra("albumName", albumFiles.get(position).getAlbum());
mContext.startActivity(intent);
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_album_details);
recyclerView = findViewById(R.id.recyclerView);
albumPhoto = findViewById(R.id.albumPhoto);
albumName = getIntent().getStringExtra("albumName");
int j = 0;
for (int i = 0 ; i < musicFiles.size() ; i ++)
{
if (albumName.equals(musicFiles.get(i).getAlbum()))
{
albumSongs.add(j, musicFiles.get(i));
j ++;
}
}
byte[] image = getAlbumArt(albumSongs.get(0).getPath());
if (image != null)
{
Glide.with(this)
.load(image)
.into(albumPhoto);
}
else
{
Glide.with(this)
.load(R.drawable.bewedoc)
.into(albumPhoto);
}
}
@Override
protected void onResume() {
super.onResume();
if (!(albumSongs.size() < 1))
{
albumDetailsAdapter = new AlbumDetailsAdapter(this, albumSongs);
recyclerView.setAdapter(albumDetailsAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
RecyclerView.VERTICAL, false));
}
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, PlayerActivity.class);
intent.putExtra("sender", "albumDetails");
intent.putExtra("position", position);
mContext.startActivity(intent);
}
});
String sender = getIntent().getStringExtra("sender");
if (sender != null && sender.equals("albumDetails"))
{
listSongs = albumFiles;
}
else
{
listSongs = mFiles;
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title="search"
android:id="@+id/search_option"
android:icon="@android:drawable/ic_menu_search"
app:showAsAction="ifRoom"
app:actionViewClass="androidx.appcompat.widget.SearchView" />
</menu>
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
return super.onCreateOptionsMenu(menu);
}
public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
MenuItem menuItem = menu.findItem(R.id.search_option);
SearchView searchView = (SearchView) menuItem.getActionView();
searchView.setOnQueryTextListener(this);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
String userInput = newText.toLowerCase();
ArrayList<MusicFiles> myFiles = new ArrayList<>();
for (MusicFiles song : musicFiles)
{
if (song.getTitle().toLowerCase().contains(userInput))
{
myFiles.add(song);
}
}
}
void updateList(ArrayList<MusicFiles> musicFilesArrayList)
{
mFiles = new ArrayList<>();
mFiles.addAll(musicFilesArrayList);
notifyDataSetChanged();
}
static MusicAdapter musicAdapter;
@Override
public boolean onQueryTextChange(String newText) {
String userInput = newText.toLowerCase();
ArrayList<MusicFiles> myFiles = new ArrayList<>();
for (MusicFiles song : musicFiles)
{
if (song.getTitle().toLowerCase().contains(userInput))
{
myFiles.add(song);
}
}
}
β πchangeπ
@Override
public boolean onQueryTextChange(String newText) {
String userInput = newText.toLowerCase();
ArrayList<MusicFiles> myFiles = new ArrayList<>();
for (MusicFiles song : musicFiles)
{
if (song.getTitle().toLowerCase().contains(userInput))
{
myFiles.add(song);
}
}
SongsFragment.musicAdapter.updateList(myFiles);
return true;
}
8. Change the GetIntentMethod() in PlayerAcitvity.java for the search_songslist can play only in its own list.
private void getIntentMethod() {
position = getIntent().getIntExtra("position",-1);
String sender = getIntent().getStringExtra("sender");
if (sender != null && sender.equals("albumDetails"))
{
listSongs = albumFiles;
}
else
{
listSongs = musicFiles; ===> Change to the "mFiles"
}
β πchangeπ
else
{
listSongs = mFiles;
}