Skip to content

Wriprin/IPOD

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

44 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

IPOD Development Doc

> Read Songs From Phone Part - 1

  • commit the viewpagers and the style of tabindicator.

1. Download the TabLayout. Tip1, Tip2

<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"/>
<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"/>

3. Viewpageradapter

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);
    }
}

4. New songsFragment.xml and albumFragment.xml

5. New tabindicator.xml to initialize its style

<?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>

> Read Songs From Phone Part - 2

  • Add the permission of usage, fetch all the songs where from the storage to app.

1. Add permission in MainActivity.java

@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();
    }
}

2. Add permission in AndroidMainfest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3. Add onRequestPermissionsResult() in MainActivity.java

@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);
        }
    }
}

4. New io.wriprin.android.ipod.MusicFiles.java to pack attributes of songs

  • notice about the short key, Alt + Insert to generate the constructor and the Getter, Setter;

5. Add ArrayList getAllAudio

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;
    }

6. Global Declaration the MusicFiles to use it when user choose allow permission

> Read Songs From Phone Part - 3

  • Display SongList

1. New layout resource files - music_items.xml to display the SongList

2. New io.wriprin.android.ipod.MusicAdapter.java collect the info

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'

4. songsFragment.java - recyclerview match Adapter

> Read Songs From Phone Part - 4

  • Commit the layout of PlayerActivity

1. Add the Vector Assest which under drawable and change to a suitable color.

2. New io.wriprin.android.ipod.PlayerActivity(EmptyActivity)

3. New (Drawable Resource File ) - main_bg.xml

  • RootElement is shape

4. New (Drawable Resource File ) - gradient.xml

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"/>

> Read Songs From Phone Part - 5 | PlayAudio

1. Add itemview.click in MusicAdapter.java

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);
    }
});

2. Add TimeLine's layout in activity_player.xml

3. Implement the Init FUNC of PlayerActivity.java

  • Declare and assign

4. MusicAdapter.java to add intent.putExtra()

intent.putExtra("position",position);

5. PlayerActivity.java get the position from MusicAdapter.java

position = getIntent().getIntExtra("position",-1);

6. Implement the method of playing

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);
}

7. Implement the timeline_Durationbar and FortmattedTime

> Read Songs From Phone Part - 6 | Button Config

  • Read the song_name and artist to the PlayerActivity, Commit the FUNC of playing and resuming the music

1. Add Metadata() in PlayerActivity.java

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);
        }
    }

2. Display song_name and artist_name

song_name.setText(listSongs.get(position).getTitle());      
artist_name.setText(listSongs.get(position).getArtist());

3. Add three thread for the three button (play, prev, next) in PlayerActivity.java

  • ctrl + o to implement method - onResume()

> Read Songs From Phone Part - 7 | Animation APP

  • implement the animation of song_fading out and in, autoplay the next_song when current_song is done.

1. Add the ImageAnimation()

//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);
}

2. Implement MediaPlayer.OnCompletionListener in PlayerActivity.java

public class PlayerActivity extends AppCompatActivity implements MediaPlayer.OnCompletionListener{

3. Implement the method for the FUNC of autoplay

@Override
public void onCompletion(MediaPlayer mp) {
    nextBtnClicked();
    if (mediaPlayer != null)
    {
        mediaPlayer = MediaPlayer.create(getApplicationContext(), uri);
        mediaPlayer.start();
        mediaPlayer.setOnCompletionListener(this);
    }
}

> Read Songs From Phone Part - 8 | Shuffle, Repeat And Delete A File

1. Implement in MainActivity.java

static boolean shuffleBoolean = false, repeatBoolean = false;

2. shuffleBtn.setOnClickListener()

Same as the repeatBtn

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);
        }
    }
});

3. Modify position in Prev or NextBtn

if (shuffleBoolean && !repeatBoolean)
{
    position = getRandom(listSongs.size() - 1);
}
else if (!shuffleBoolean && !repeatBoolean)
{
    position = ((position - 1) < 0 ? (listSongs.size() - 1) : (position - 1));
}

Random:

private int getRandom(int i) {
    Random random = new Random();
    return random.nextInt(i + 1);		//i => listsongs.size
}

4. Add a vectorAssest about ic_baseline_more.xml for delete action in music_items.xml

<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"/>

5. New Android Resource Directory

Directory name: menu
Resource type: menu

Then New Resource file in menu directory

popup.xml
<?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>

6. Implement the method in MusicAdapter.java

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();

        }
}

7. Add String "id" in MainActivity.java and MusicFiles.java for delete(method) to find the song.

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);

> Read Songs From Phone Part - 9 | Album Fragment Part

  • Commit the layout of Album and tied to the songs

1. New Resource File "album_item" and add cardview in Design search box

<?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>

2. Copy the inflater in SongsFragment.java to AlbumFragment.java

    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));
    }

3. Modify the fragment_album.xml

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"
        android:background="#1C1C1C"/>

4. New AlbumAdapter.java and implement it. (Copy something of MusicAdapter.java)

public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.MyHolder> 

> Read Songs From Phone Part - 10 | Album Fragment Details

  • commit the FUNC of Album JMP its fragment.

1. New AlbumDetails.java ==> (Activity)

2. Design activity_album_details.xml

3. Implement the FUNC of Album JMP its fragment (activity_album_details.xml)

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);
    }
});
  • Display songs' own albumPhoto.

@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);
    }

}
  • Show the songs which is belong to the specific Album.

1. New AlbumDetailsAdapter.java

copy AlbumAdapter.java to AlbumDetailsAdapter.java

2. Ctrl + O: Implement onResume()

@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));
    }
}

> Read Songs From Phone Part - 11 | Play Album Files

  • Play the songs in Ablum list.

1. When click the songs, JMP to the PlayerActivity.java

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);
    }
});

2. Get Intent in PlayerActivity.java

String sender = getIntent().getStringExtra("sender");
if (sender != null && sender.equals("albumDetails"))
{
    listSongs = albumFiles;
}
else
{
    listSongs = mFiles;
}

> Read Songs From Phone Part - 12 | Search Files Filter List

1. New Menu Resource File (file name: search)

<?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>

2. Instantiation of the Search in MainActivity.java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.search, menu);
    return super.onCreateOptionsMenu(menu);
}

3. Add implement of Query

public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {}

4. Implement the FUCN

@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);
        }
    }
}

5. Create a updateList() in MusicAdapter.java

void updateList(ArrayList<MusicFiles> musicFilesArrayList)
{
    mFiles = new ArrayList<>();
    mFiles.addAll(musicFilesArrayList);
    notifyDataSetChanged();
}

notifyDataSetChanged()

6. Change the MusicAdapter in SongsFragment.java to static

static MusicAdapter musicAdapter;

7. Use the method

    @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;
}

About

Music app

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages