前面我们实现了文件夹的操作,解下来就是从文件夹里面的音乐引入到音乐列表。由于音乐文件搜索在最后一个界面, 那我们就先实现最后一个welcom界面。
public class ReadyToScanFragment extends Fragment {
private Context mContext;
private TextView welcomeHeader;
private TextView welcomeText1;
private TextView swipeLeftToContinue;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContext = getActivity().getApplication();
View rootView = (View)inflater.inflate(R.layout.fragment_welcome_screen_6,container, false);
return rootView;
}
}
将这个类的对象添加到WelcomePagerAdapter,这样我们就可以显示这个界面了。
在WecomActivity中进入这个界面时候,会启用搜索文件的异步任务。
在这之前是一个动画效果,我们先忽略这个效果直接实现文件搜索。通过一个Service实现,并将其设置为前台任务及其后台进程。
/**
* Created by kankan on 2016/5/29.
*/
public class BuildMusicLibraryService extends Service implements AsyncBuildLibraryTask.OnBuildLibraryProgressUpdate {
private Context mContext;
private NotificationCompat.Builder mBuilder;
private Notification mNotification;
private NotificationManager mNotifyManager;
public static int mNotificationId = 92713;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mContext = this.getApplicationContext();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/* */
mBuilder = new NotificationCompat.Builder(mContext);
mBuilder.setSmallIcon(android.support.design.R.id.split_action_bar);
mBuilder.setContentTitle(getResources().getString(R.string.building_music_library));
mBuilder.setTicker(getResources().getString(R.string.building_music_library));
mBuilder.setContentText("123");
mBuilder.setProgress(0, 0, true);
mNotifyManager =(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotification = mBuilder.build();
mNotification.flags |= Notification.FLAG_INSISTENT|Notification.FLAG_NO_CLEAR;
startForeground(mNotificationId, mNotification);
AsyncBuildLibraryTask task = new AsyncBuildLibraryTask(mContext, this);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return START_STICKY;
}
@Override
public void onStartBuildingLibrary() {
}
@Override
public void onProgressUpdate(AsyncBuildLibraryTask task, String mCurrentTask, int overallProgress, int maxProgress, boolean mediaStoreTransferDone) {
}
@Override
public void onFinishBuildingLibrary(AsyncBuildLibraryTask task) {
}
}
这个服务,第一是把自己变成前台任务,第二启动一个异步任务,用来将音乐文件的信息存入数据库。
我们看一下这个任务。
/**
* Created by kankan on 2016/5/29.
*/
public class AsyncBuildLibraryTask extends AsyncTask<Void, Void, String>{
private String TAG =this.getClass().getSimpleName();
private Context mContext;
private Common mApp;
private BuildMusicLibraryService mService;
private String mCurrentTask = "";
private int mOverallProgress = 0;
private Date date = new Date();
private String mMediaStoreSelection = null;
private HashMap<String, String> mGenresHashMap = new HashMap<String, String>();
private HashMap<String, Integer> mGenresSongCountHashMap = new HashMap<String, Integer>();
private HashMap<String, Integer> mAlbumsCountMap = new HashMap<String, Integer>();
private HashMap<String, Integer> mSongsCountMap = new HashMap<String, Integer>();
private HashMap<String, Uri> mMediaStoreAlbumArtMap = new HashMap<String, Uri>();
private HashMap<String, String> mFolderArtHashMap = new HashMap<String, String>();
public AsyncBuildLibraryTask(Context mContext, BuildMusicLibraryService mService) {
this.mContext = mContext;
this.mApp = (Common) mContext;
this.mService = mService;
// TODO: 2016/5/29
}
/**
* Provides callback methods that expose this
* AsyncTask's progress.
*
* @author Saravan Pantham
*/
public interface OnBuildLibraryProgressUpdate {
/**
* Called when this AsyncTask begins executing
* its doInBackground() method.
*/
public void onStartBuildingLibrary();
/**
* Called whenever mOverall Progress has been updated.
*/
public void onProgressUpdate(AsyncBuildLibraryTask task, String mCurrentTask,
int overallProgress, int maxProgress,
boolean mediaStoreTransferDone);
/**
* Called when this AsyncTask finishes executing
* its onPostExecute() method.
*/
public void onFinishBuildingLibrary(AsyncBuildLibraryTask task);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(Void... params) {
mCurrentTask = mContext.getResources().getString(R.string.building_music_library);
Cursor mediaStoreCursor = getSongsFromMediaStore();
if(mediaStoreCursor != null){
saveMediaStoreDataToDB(mediaStoreCursor);
}
return null;
}
void saveMediaStoreDataToDB(Cursor mediaStoreCursor ){
try{
mApp.getDBAccessHelper().getWritableDatabase().beginTransaction();
//clear out the table
mApp.getDBAccessHelper()
.getWritableDatabase()
.delete(DBAccessHelper.MUSIC_LIBRARY_TABLE, null, null);
//Tracks the progress of this method.
int subProgress = 0;
if(mediaStoreCursor.getCount() !=0){
subProgress = 250000/(mediaStoreCursor.getCount());
}else {
subProgress = 250000/1;
}
buildGenresLibrary();
buildArtistsLibrary();;
buildAlbumsLibrary();;
buildMediaStoreAlbumArtHash();
final int titleColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
final int artistColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
final int albumColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
final int albumIdColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID);
final int durationColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
final int trackColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.TRACK);
final int yearColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.YEAR);
final int dateAddedColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATE_ADDED);
final int dateModifiedColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATE_MODIFIED);
final int filePathColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media.DATA);
final int idColIndex = mediaStoreCursor.getColumnIndex(MediaStore.Audio.Media._ID);
int albumArtistColIndex = mediaStoreCursor.getColumnIndex(MediaStoreAccessHelper.ALBUM_ARTIST);
if(albumArtistColIndex == -1){
albumArtistColIndex = artistColIndex;
}
Log.i(TAG, "media store cursor "+ mediaStoreCursor.getCount());
for(int i = 0 ;i < mediaStoreCursor.getCount(); i++) {
mediaStoreCursor.moveToPosition(i);
mOverallProgress += subProgress;
publishProgress();
Log.i(TAG, "progress " +i);
String songTitle = mediaStoreCursor.getColumnName(titleColIndex);
String songArtist = mediaStoreCursor.getString(artistColIndex);
String songAlbum = mediaStoreCursor.getString(albumColIndex);
String songAlbumId = mediaStoreCursor.getString(albumIdColIndex);
String songAlbumArtist = mediaStoreCursor.getString(albumArtistColIndex);
String songFilePath = mediaStoreCursor.getString(filePathColIndex);
String songGenre = getSongGenre(songFilePath);
String songDuration = mediaStoreCursor.getString(durationColIndex);
String songTrackNumber = mediaStoreCursor.getString(trackColIndex);
String songYear = mediaStoreCursor.getString(yearColIndex);
String songDateAdded = mediaStoreCursor.getString(dateAddedColIndex);
String songDateModified = mediaStoreCursor.getString(dateModifiedColIndex);
String songId = mediaStoreCursor.getString(idColIndex);
String numberOfAlbums = "" + mAlbumsCountMap.get(songArtist);
String numberOfTracks = "" + mSongsCountMap.get(songAlbum + songArtist);
String numberOfSongsInGenre = "" + getGenreSongsCount(songGenre);
String songSource = DBAccessHelper.LOCAL;
String songSavedPosition = "-1";
String songAlbumArtPath = "";
if (mMediaStoreAlbumArtMap.get(songAlbum) != null) {
songAlbumArtPath = mMediaStoreAlbumArtMap.get(songAlbumId).toString();
}
if (numberOfAlbums.equals("1"))
numberOfAlbums += " " + mContext.getResources().getString(R.string.album_small);
else
numberOfAlbums += " " + mContext.getResources().getString(R.string.albums_small);
if (numberOfTracks.equals("1"))
numberOfTracks += " " + mContext.getResources().getString(R.string.song_small);
else
numberOfTracks += " " + mContext.getResources().getString(R.string.songs_small);
if (numberOfSongsInGenre.equals("1"))
numberOfSongsInGenre += " " + mContext.getResources().getString(R.string.song_small);
else
numberOfSongsInGenre += " " + mContext.getResources().getString(R.string.songs_small);
//Check if any of the other tags were empty/null and set them to "Unknown xxx" values.
if (songArtist == null || songArtist.isEmpty()) {
songArtist = mContext.getResources().getString(R.string.unknown_artist);
}
if (songAlbumArtist == null || songAlbumArtist.isEmpty()) {
if (songArtist != null && !songArtist.isEmpty()) {
songAlbumArtist = songArtist;
} else {
songAlbumArtist = mContext.getResources().getString(R.string.unknown_album_artist);
}
}
if (songAlbum == null || songAlbum.isEmpty()) {
songAlbum = mContext.getResources().getString(R.string.unknown_album);
;
}
if (songGenre == null || songGenre.isEmpty()) {
songGenre = mContext.getResources().getString(R.string.unknown_genre);
}
//Filter out track numbers and remove any bogus values.
if (songTrackNumber != null) {
if (songTrackNumber.contains("/")) {
int index = songTrackNumber.lastIndexOf("/");
songTrackNumber = songTrackNumber.substring(0, index);
}
try {
if (Integer.parseInt(songTrackNumber) <= 0) {
songTrackNumber = "";
}
} catch (Exception e) {
e.printStackTrace();
songTrackNumber = "";
}
}
long durationLong = 0;
try {
durationLong = Long.parseLong(songDuration);
} catch (Exception e) {
e.printStackTrace();
}
ContentValues values = new ContentValues();
values.put(DBAccessHelper.SONG_TITLE, songTitle);
values.put(DBAccessHelper.SONG_ARTIST, songArtist);
values.put(DBAccessHelper.SONG_ALBUM, songAlbum);
values.put(DBAccessHelper.SONG_ALBUM_ARTIST, songAlbumArtist);
values.put(DBAccessHelper.SONG_DURATION, convertMillisToMinsSecs(durationLong));
values.put(DBAccessHelper.SONG_FILE_PATH, songFilePath);
values.put(DBAccessHelper.SONG_TRACK_NUMBER, songTrackNumber);
values.put(DBAccessHelper.SONG_GENRE, songGenre);
values.put(DBAccessHelper.SONG_YEAR, songYear);
values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
values.put(DBAccessHelper.SONG_LAST_MODIFIED, songDateModified);
values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
values.put(DBAccessHelper.BLACKLIST_STATUS, false);
values.put(DBAccessHelper.ADDED_TIMESTAMP, date.getTime());
values.put(DBAccessHelper.RATING, 0);
values.put(DBAccessHelper.LAST_PLAYED_TIMESTAMP, songDateModified);
values.put(DBAccessHelper.SONG_SOURCE, songSource);
values.put(DBAccessHelper.SONG_ID, songId);
values.put(DBAccessHelper.SAVED_POSITION, songSavedPosition);
values.put(DBAccessHelper.ALBUMS_COUNT, numberOfAlbums);
values.put(DBAccessHelper.SONGS_COUNT, numberOfTracks);
values.put(DBAccessHelper.GENRE_SONG_COUNT, numberOfSongsInGenre);
//Add all the entries to the database to build the songs library.
mApp.getDBAccessHelper().getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_TABLE,
null,
values);
}
} catch (Exception e){
e.printStackTrace();
}finally {
mApp.getDBAccessHelper().getWritableDatabase().setTransactionSuccessful();
mApp.getDBAccessHelper().getWritableDatabase().endTransaction();
}
}
private String getSongGenre(String filePath){
if(mGenresHashMap != null){
return mGenresHashMap.get(filePath);
}else {
return mContext.getResources().getString(R.string.unknown_genre);
}
}
private int getGenreSongsCount(String genre){
if(mGenresSongCountHashMap != null){
if(genre !=null){
return mGenresSongCountHashMap.get(genre);
}else {
return 0;
}
}else{
if(mGenresSongCountHashMap.get(mContext.getResources().getString(R.string.unknown_genre))!= null)
return mGenresSongCountHashMap.get(mContext.getResources().getString(R.string.unknown_genre));
else
return 0;
}
}
private void buildGenresLibrary(){
//Get a cursor of all genres in MediaStore
// Cursor generesCursor = mContext.getContentResolver()
Cursor genersCursor = mContext.getContentResolver().query(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Genres._ID, MediaStore.Audio.Genres.NAME},
null,
null,
null);
//Iterate thru all generes in MediaStore
for(genersCursor.moveToFirst(); !genersCursor.isAfterLast(); genersCursor.moveToNext()){
String genreId = genersCursor.getString(0);
String genreName = genersCursor.getString(1);
Log.i(TAG, "genresId "+genreId+"genreName "+ genreName);
if (genreName==null || genreName.isEmpty() ||
genreName.equals(" ") || genreName.equals(" ") ||
genreName.equals(" "))
genreName = mContext.getResources().getString(R.string.unknown_genre);
Cursor cursor = mContext.getContentResolver().query(makeGenreUri(genreId),
new String[]{MediaStore.Audio.Media.DATA},
mMediaStoreSelection,
null,
null);
if(cursor != null){
for(int i= 0; i< cursor.getCount() ; i++){
cursor.moveToPosition(i);
mGenresHashMap.put(cursor.getString(0), genreName);
mGenresSongCountHashMap.put(genreName, cursor.getCount());
}
cursor.close();
}
}
if(genersCursor != null){
genersCursor.close();
}
}
private Uri makeGenreUri(String genreId){
String CONTENTDIR = MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY;
return Uri.parse(new StringBuilder().append(MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI.toString())
.append("/")
.append(genreId)
.append("/")
.append(CONTENTDIR)
.toString());
}
/**
* ""
*
**/
private Cursor getSongsFromMediaStore(){
Cursor musicFolderCursor = mApp.getDBAccessHelper().getAllMusicFolderPaths();
Cursor mediaStoreCursor = null;
String sortOrder = null;
String projection[]={
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.TRACK,
MediaStore.Audio.Media.YEAR,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DATE_ADDED,
MediaStore.Audio.Media.DATE_MODIFIED,
MediaStore.Audio.Media._ID,
MediaStoreAccessHelper.ALBUM_ARTIST
};
if(musicFolderCursor == null || musicFolderCursor.getCount() <1){
// TODO: 2016/5/29
}else{
mMediaStoreSelection = buildMusicFoldersSelection(musicFolderCursor);
mediaStoreCursor = MediaStoreAccessHelper.getAllSongsWithSelection(mContext,
mMediaStoreSelection,
projection,
sortOrder);
musicFolderCursor.close();
}
return mediaStoreCursor;
}
/***
*
*/
private String buildMusicFoldersSelection(Cursor musicFoldersCursor){
String mediaStoreSelection = MediaStore.Audio.Media.IS_MUSIC+ "!=0 AND (";
int folderPathColIndex = musicFoldersCursor.getColumnIndex(DBAccessHelper.FOLDER_PATH);
int includeColIndex = musicFoldersCursor.getColumnIndex(DBAccessHelper.INCLUDE);
for(int i =0; i<musicFoldersCursor.getCount(); i++){
musicFoldersCursor.moveToPosition(i);
boolean include = musicFoldersCursor.getInt(includeColIndex) > 0;
String likeClause;
if(include)
likeClause = " LIKE";
else
likeClause = " NOT LIKE";
if(i != 0 && !include)
mediaStoreSelection +=" AND ";
else if (i!=0 && include )
mediaStoreSelection += " OR ";
mediaStoreSelection += MediaStore.Audio.Media.DATA + likeClause
+ "'%" + musicFoldersCursor.getString(folderPathColIndex)
+"/%'";
}
mediaStoreSelection +=")";
Log.i(TAG, "mediaStoreSelection is :" + mediaStoreSelection);
return mediaStoreSelection;
}
/**
* Builds a HashMap of all songs and their genres.
*/
private void buildArtistsLibrary(){
Cursor artistsCursor = mContext.getContentResolver().query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS},
null, null, null);
if(artistsCursor == null){
return;
}
for(int i= 0; i< artistsCursor.getCount(); i++){
artistsCursor.moveToPosition(i);
mAlbumsCountMap.put(artistsCursor.getString(0), artistsCursor
.getInt(1));
}
artistsCursor.close();
}
private void buildAlbumsLibrary(){
Cursor albumsCursor = mContext. getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.NUMBER_OF_SONGS},
null, null, null);
if(albumsCursor == null){
return;
}
for(int i=0; i < albumsCursor.getCount(); i++){
albumsCursor.moveToPosition(i);
mSongsCountMap.put(albumsCursor.getString(0)+albumsCursor.getString(1), albumsCursor.getInt(2));
}
albumsCursor.close();
}
private void buildMediaStoreAlbumArtHash(){
Cursor albumsCursor = mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Media.ALBUM_ID},
MediaStore.Audio.Media.IS_ALARM+"=1",
null, null);
final Uri ART_CONTENT_URI = Uri.parse("content://media/external/audio/albumart");
if(albumsCursor == null){
return;
}
for (int i = 0; i< albumsCursor.getCount(); i++){
albumsCursor.moveToPosition(i);
Uri albumArtUri = ContentUris.withAppendedId(ART_CONTENT_URI, albumsCursor.getLong(0));
mMediaStoreAlbumArtMap.put(albumsCursor.getString(0), albumArtUri);
}
albumsCursor.close();
}
/**
* Convert millisseconds to hh:mm:ss format.
*
* @param milliseconds The input time in milliseconds to format.
* @return The formatted time string.
*/
private String convertMillisToMinsSecs(long milliseconds) {
int secondsValue = (int) (milliseconds / 1000) % 60;
int minutesValue = (int) ((milliseconds / (1000*60)) % 60);
int hoursValue = (int) ((milliseconds / (1000*60*60)) % 24);
String seconds = "";
String minutes = "";
String hours = "";
if (secondsValue < 10) {
seconds = "0" + secondsValue;
} else {
seconds = "" + secondsValue;
}
minutes = "" + minutesValue;
hours = "" + hoursValue;
String output = "";
if (hoursValue!=0) {
minutes = "0" + minutesValue;
hours = "" + hoursValue;
output = hours + ":" + minutes + ":" + seconds;
} else {
minutes = "" + minutesValue;
hours = "" + hoursValue;
output = minutes + ":" + seconds;
}
return output;
}
}
这个类很大,但做的事情却不多,就是将文件夹中的音乐文件从AudioStore里面读取信息,这里面有ContentProvider来提供。