/*
* Copyright (C) 2014 Saravan Pantham
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.aniruddhc.acemusic.player.AsyncTasks;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import org.json.JSONArray;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.PowerManager;
import com.aniruddhc.acemusic.player.R;
import com.aniruddhc.acemusic.player.DBHelpers.DBAccessHelper;
import com.aniruddhc.acemusic.player.Services.AudioPlaybackService;
import com.aniruddhc.acemusic.player.Utils.Common;
/**
* Checks if the Google Play Music app is installed on the user's device. If it
* is, grabs the user's song data from Google Play Music's content mApp.
*/
public class AsyncGetGooglePlayMusicMetadataTask extends AsyncTask<String, String, String> {
private Context mContext;
private Common mApp;
private HashMap<String, String> playlistIdsNameMap = new HashMap<String, String>();
private JSONArray playlistsJSONArray = new JSONArray();
private JSONArray playlistEntriesJSONArray = new JSONArray();
private ArrayList<String> genresList = new ArrayList<String>();
private int targetVolume = 0;
private int currentVolume;
private int stepDownValue = 1;
private AudioManager am;
private String currentTask = "";
private int currentProgressValue = 0;
private int numberOfSongs = 0;
private int numberOfPlaylists = 0;
private Date date = new Date();
private PowerManager pm;
private PowerManager.WakeLock wakeLock;
public AsyncGetGooglePlayMusicMetadataTask(Context context) {
mContext = context;
mApp = (Common) mContext;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
//Hide the actionbar.
mApp.setIsBuildingLibrary(true);
//Acquire a wakelock to prevent the CPU from sleeping while the process is running.
pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.aniruddhc.acemusic.player.AsyncTasks.AsyncGetGooglePlayMusicMetadata");
wakeLock.acquire();
//Set the initial setting of the progressbar as indeterminate.
currentTask = mContext.getResources().getString(R.string.contacting_google_play_music);
}
@Override
protected String doInBackground(String... params) {
//Check if any music is playing and fade it out.
am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
if (mApp.isServiceRunning()) {
if (mApp.getService().isPlayingMusic()) {
targetVolume = 0;
currentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
while(currentVolume > targetVolume) {
am.setStreamVolume(AudioManager.STREAM_MUSIC, (currentVolume - stepDownValue), 0);
currentVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
}
mContext.stopService(new Intent(mContext, AudioPlaybackService.class));
}
}
//Check if the Google Play Music app is installed.
PackageManager pm = mContext.getPackageManager();
boolean installed = false;
try {
pm.getPackageInfo("com.google.android.music", PackageManager.GET_ACTIVITIES);
installed = true;
} catch (NameNotFoundException e1) {
//The app isn't installed.
installed = false;
}
String result = "GENERIC_EXCEPTION";
if (installed==false) {
//Can't do anything here anymore. Quit.
mApp.getSharedPreferences().edit().putBoolean("GOOGLE_PLAY_MUSIC_ENABLED", false).commit();
return null;
} else {
//Grab music metadata from Google Play Music's public content mApp.
result = getMetadataFromGooglePlayMusicApp();
}
return result;
}
//Grab music metadata from Google Play Music's public content mApp.
public String getMetadataFromGooglePlayMusicApp() {
//Grab a handle on the mApp.
Uri googlePlayMusicContentProviderUri = Uri.parse("content://com.google.android.music.MusicContent/audio");
String[] projection = { "title", "artist", "album", "AlbumArtist",
"duration", "track", "year", "Genre", "TrackType AS track_type",
/*"_count",*/ "Rating", "AlbumArtLocation AS album_art", "SourceType AS source_type",
"SourceId", "ArtistArtLocation", /*, "artistId",*/ "StoreAlbumId" };
/* source_type values:
* 0: Local file (not used).
* 1: Unknown.
* 2: Personal, free GMusic library (used).
* 3: All Access (not used).
*/
String selection = "source_type=2 AND track_type=0";
//Catch any exceptions that may be thrown as a result of unknown columns in GMusic's content mApp.
Cursor cursor = null;
boolean projectionFailed = false;
try {
cursor = mContext.getContentResolver().query(googlePlayMusicContentProviderUri, projection, selection, null, null);
} catch (IllegalArgumentException e) {
e.printStackTrace();
//Problematic columns are commented out here.
String[] failSafeProjection = { "title", "artist", "album", "AlbumArtist",
"duration", "track", "year", "Genre", "TrackType AS track_type",
/*"_count",*/ "Rating", "AlbumArtLocation AS album_art", /* "SourceType AS source_type", */
"SourceId", /* "ArtistArtLocation", "artistId",*/ "StoreAlbumId" };
cursor = mContext.getContentResolver().query(googlePlayMusicContentProviderUri, failSafeProjection, "track_type=0", null, null);
projectionFailed = true;
}
//Clear out all the current Google Play Music songs in the database.
mApp.getDBAccessHelper().deleteAllGooglePlayMusicSongs();
//Insert the songs and their metadata into Jams' local database.
/* To improve database insertion performance, we'll use a single transaction
* for the entire operation. SQLite journals each database insertion and
* creates a new transaction by default. We'll override this functionality
* and create a single transaction for all the database record insertions.
* In theory, this should reduce NAND memory overhead times and result in
* a 2x to 5x performance increase.
*/
try {
//We'll initialize the DB transaction manually.
mApp.getDBAccessHelper().getWritableDatabase().beginTransaction();
//Avoid "Divide by zero" errors.
int scanningSongsIncrement;
if (cursor!=null) {
if (cursor.getCount()!=0) {
scanningSongsIncrement = 800000/cursor.getCount();
} else {
scanningSongsIncrement = 800000/1;
}
} else {
return "FAIL";
}
currentTask = mContext.getResources().getString(R.string.syncing_with_google_play_music);
for (int i=0; i < cursor.getCount(); i++) {
cursor.moveToPosition(i);
currentProgressValue = currentProgressValue + scanningSongsIncrement;
publishProgress();
//Get the song's metadata.
String songTitle = cursor.getString(cursor.getColumnIndex("title"));
String songArtist = cursor.getString(cursor.getColumnIndex("Artist"));
String songAlbum = cursor.getString(cursor.getColumnIndex("Album"));
String songAlbumArtist = cursor.getString(cursor.getColumnIndex("AlbumArtist"));
String songDuration = cursor.getString(cursor.getColumnIndex("Duration"));
String songTrackNumber =cursor.getString(cursor.getColumnIndex("Track"));
String songYear = cursor.getString(cursor.getColumnIndex("Year"));
String songGenre = cursor.getString(cursor.getColumnIndex("Genre"));
//String songPlayCount = cursor.getString(cursor.getColumnIndex("_count"));
String songRating = cursor.getString(cursor.getColumnIndex("Rating"));
String songSource = DBAccessHelper.GMUSIC;
String songAlbumArtPath = cursor.getString(cursor.getColumnIndex("album_art"));
String songID = cursor.getString(cursor.getColumnIndex("SourceId"));
//String artistID = cursor.getString(cursor.getColumnIndex("artistId"));
String storeAlbumID = cursor.getString(cursor.getColumnIndex("StoreAlbumId"));
String songArtistArtPath = "";
if (projectionFailed==false) {
songArtistArtPath = cursor.getString(cursor.getColumnIndex("ArtistArtLocation"));
} else {
//Fall back on album art.
songArtistArtPath = cursor.getString(cursor.getColumnIndex("album_art"));
}
//Prepare the genres ArrayList.
if (!genresList.contains(songGenre)) {
genresList.add(songGenre);
}
//Filter out track numbers and remove any bogus values.
if (songTrackNumber!=null) {
if (songTrackNumber.contains("/")) {
int index = songTrackNumber.lastIndexOf("/");
songTrackNumber = songTrackNumber.substring(0, index);
}
}
if (songYear.equals("0")) {
songYear = "";
}
//Check if any of the other tags were empty/null and set them to "Unknown xxx" values.
if (songArtist==null || songArtist.isEmpty() || songArtist.equals(" ")) {
songArtist = "Unknown Artist";
}
if (songAlbumArtist==null || songAlbumArtist.isEmpty() || songAlbumArtist.equals(" ")) {
songAlbumArtist = "Unknown Album Artist";
}
if (songAlbum==null || songAlbum.isEmpty() || songAlbum.equals(" ")) {
songAlbum = "Unknown Album";
}
if (songGenre==null || songGenre.isEmpty() || songGenre.equals(" ")) {
songGenre = "Unknown Genre";
}
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, songDuration);
values.put(DBAccessHelper.SONG_FILE_PATH, songID);
values.put(DBAccessHelper.SONG_TRACK_NUMBER, songTrackNumber);
values.put(DBAccessHelper.SONG_GENRE, songGenre);
//values.put(DBAccessHelper.SONG_PLAY_COUNT, songPlayCount);
values.put(DBAccessHelper.SONG_YEAR, songYear);
values.put(DBAccessHelper.SONG_LAST_MODIFIED, "");
values.put(DBAccessHelper.BLACKLIST_STATUS, "FALSE"); //Keep the song whitelisted by default.
values.put(DBAccessHelper.ADDED_TIMESTAMP, date.getTime());
values.put(DBAccessHelper.RATING, songRating);
values.put(DBAccessHelper.SONG_SOURCE, songSource);
values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
values.put(DBAccessHelper.SONG_ID, songID);
values.put(DBAccessHelper.ARTIST_ART_LOCATION, songArtistArtPath);
//values.put(DBAccessHelper.ARTIST_ID, artistID);
values.put(DBAccessHelper.ALBUM_ID, storeAlbumID);
/* We're gonna have to save the song ID into the SONG_FILE_PATH
* field. Google Play Music playlist songs don't have a file path, but we're using a
* JOIN in PlaylistsFlippedFragment that relies on this field, so we'll need to use the
* song ID as a placeholder instead.
*/
values.put(DBAccessHelper.SONG_FILE_PATH, songID);
//Add all the entries to the database to build the songs library.
mApp.getDBAccessHelper().getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_TABLE,
null,
values);
}
mApp.getDBAccessHelper().getWritableDatabase().setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//Close the transaction.
mApp.getDBAccessHelper().getWritableDatabase().endTransaction();
if (cursor!=null) {
cursor.close();
cursor = null;
}
}
/****************************************************************************
* BUILD PLAYLISTS LIBRARY
****************************************************************************/
//getPlaylistsWebClient();
//getPlaylistsMobileClient();
//Update the genres library.
updateGenreSongCount();
return "SUCCESS";
}
/**
* Downloads and stores song metadata from Google's servers.
*
* @deprecated Grabbing metadata directly from Google's servers can potentially
* cause them to shutdown the "sj" service for this app. The official GMusic app
* has a ContentProvider that can provide all the metadata for offline usage.
*/
public String downloadMetadataFromGoogle() {
/* //Retrieve a list of songs stored on Google Play Music and their metadata.
GMusicClientCalls gMusicClientCalls = GMusicClientCalls.getInstance(mContext);
try {
songsList = gMusicClientCalls.getAllSongs(mContext.getApplicationContext());
} catch (JSONException e) {
return "GENERIC_EXCEPTION";
}
//Clear out all the current Google Play Music songs in the database.
DBAccessHelper libraryDBHelper = new DBAccessHelper(mContext);
libraryDBHelper.deleteAllGooglePlayMusicSongs();
//Insert the songs and their metadata into Jams' local database.
/* To improve database insertion performance, we'll use a single transaction
* for the entire operation. SQLite journals each database insertion and
* creates a new transaction by default. We'll override this functionality
* and create a single transaction for all the database record insertions.
* In theory, this should reduce NAND memory overhead times and result in
* a 2x to 5x performance increase.
*\/
try {
//We'll initialize the DB transaction manually.
libraryDBHelper.getWritableDatabase().beginTransaction();
/* Now that we have a list of all the audio files that are either new or
* modified, we can just delete all the records of those files in the DB
* and re-add them.
*\/
//Avoid "Divide by zero" errors.
int scanningSongsIncrement;
if (songsList.size()!=0) {
scanningSongsIncrement = 800000/songsList.size();
} else {
scanningSongsIncrement = 800000/1;
}
currentTask = mContext.getResources().getString(R.string.downloading_songs_info_from_google_play_music);
for (int i=0; i < songsList.size(); i++) {
WebClientSongsSchema song = songsList.get(i);
currentProgressValue = currentProgressValue + scanningSongsIncrement;
publishProgress();
//Get the song's metadata.
String songTitle = song.getTitle();
String songArtist = song.getArtist();
String songAlbum = song.getAlbum();
String songAlbumArtist = song.getAlbumArtist();
String songDuration = "" + song.getDurationMillis();
String songTrackNumber = "" + song.getTrack();
String songYear = "" + song.getYear();
String songGenre = song.getGenre();
String songPlayCount = "" + song.getPlayCount();
String songRating = "" + song.getRating();
String songSource = DBAccessHelper.GMUSIC;
String songAlbumArtPath = song.getAlbumArtUrl();
String songDeleted = "" + song.isDeleted();
String songLastPlayed = "" + song.getLastPlayed();
String songId = "" + song.getId();
/* By default, Google will return an album art path that contains
* an image that is 130x130 in size. The "=sxxx" parameter determines
* the size of the returned image. We'll replace all instances of "=s130"
* with "=s512" to get artwork that is 512x512 in size. Also, the "http://"
* part appears truncated, so add that into the beginning of the url.
*\/
if (songAlbumArtPath!=null) {
if (!songAlbumArtPath.isEmpty()) {
songAlbumArtPath = songAlbumArtPath.replace("=s130", "=s512");
songAlbumArtPath = "http:" + songAlbumArtPath;
}
}
//Prepare the genres ArrayList.
if (!genresList.contains(songGenre)) {
genresList.add(songGenre);
}
//Filter out track numbers and remove any bogus values.
if (songTrackNumber!=null) {
if (songTrackNumber.contains("/")) {
int index = songTrackNumber.lastIndexOf("/");
songTrackNumber = songTrackNumber.substring(0, index);
}
}
if (songYear.equals("0")) {
songYear = "";
}
String songFilePath = "";
try {
URI uri = gMusicClientCalls.getSongStream(song.getId());
songFilePath = uri.toURL().toString();
} catch (JSONException e) {
continue;
} catch (URISyntaxException e) {
continue;
} catch (MalformedURLException e) {
continue;
} catch (Exception e) {
continue;
}
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, songDuration);
values.put(DBAccessHelper.SONG_FILE_PATH, songFilePath);
values.put(DBAccessHelper.SONG_FOLDER_PATH, "");
values.put(DBAccessHelper.SONG_TRACK_NUMBER, songTrackNumber);
values.put(DBAccessHelper.SONG_GENRE, songGenre);
values.put(DBAccessHelper.SONG_PLAY_COUNT, songPlayCount);
values.put(DBAccessHelper.SONG_YEAR, songYear);
values.put(DBAccessHelper.SONG_LAST_MODIFIED, "");
values.put(DBAccessHelper.BLACKLIST_STATUS, "FALSE"); //Keep the song whitelisted by default.
values.put(DBAccessHelper.ADDED_TIMESTAMP, date.getTime());
values.put(DBAccessHelper.RATING, songRating);
values.put(DBAccessHelper.LAST_PLAYED_TIMESTAMP, songLastPlayed);
values.put(DBAccessHelper.SONG_SOURCE, songSource);
values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, songAlbumArtPath);
values.put(DBAccessHelper.SONG_DELETED, songDeleted);
values.put(DBAccessHelper.SONG_ID, songId);
/* We're gonna have to save the song ID into the SONG_FILE_PATH
* field. Google Play Music playlist songs don't have a file path, but we're using a
* JOIN in PlaylistsFlippedFragment that relies on this field, so we'll need to use the
* song ID as a placeholder instead.
*\/
values.put(DBAccessHelper.SONG_FILE_PATH, songId);
//Add all the entries to the database to build the songs library.
libraryDBHelper.getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_TABLE,
null,
values);
}
libraryDBHelper.getWritableDatabase().setTransactionSuccessful();
} catch (SQLException e) {
// TODO Auto-generated method stub.
return "GENERIC_EXCEPTION";
} finally {
//Close the transaction.
libraryDBHelper.getWritableDatabase().endTransaction();
libraryDBHelper.close();
}
/**************************************************************************
* BUILD PLAYLISTS LIBRARY.
**************************************************************************\/
//Clear out all the current Google Play Music playlists in the database.
DBAccessHelper musicLibraryPlaylistsDBHelper = new DBAccessHelper(mContext);
musicLibraryPlaylistsDBHelper.deleteAllGooglePlayMusicPlaylists();
//Insert the songs and their metadata into Jams' local database.
/* To improve database insertion performance, we'll use a single transaction
* for the entire operation. SQLite journals each database insertion and
* creates a new transaction by default. We'll override this functionality
* and create a single transaction for all the database record insertions.
* In theory, this should reduce NAND memory overhead times and result in
* a 2x to 5x performance increase.
*\/
try {
//Open a connection to the database.
musicLibraryPlaylistsDBHelper.getWritableDatabase().beginTransaction();
try {
playlistsList = gMusicClientCalls.getAllPlaylists(mContext.getApplicationContext()).getPlaylists();
} catch (JSONException e) {
return "GENERIC_EXCEPTION";
}
//Avoid "Divide by zero" errors.
int scanningPlaylistsIncrement;
if (playlistsList.size()!=0) {
scanningPlaylistsIncrement = 100000/playlistsList.size();
} else {
scanningPlaylistsIncrement = 100000/1;
}
currentTask = mContext.getResources().getString(R.string.syncing_with_google_play_music);
for (int i=0; i < playlistsList.size(); i++) {
currentProgressValue = currentProgressValue + scanningPlaylistsIncrement;
publishProgress();
//Get the playlist's metadata.
String playlistName = playlistsList.get(i).getTitle();
String playlistID = playlistsList.get(i).getPlaylistId();
String playlistArtUrl = "";
ContentValues playlistValues = new ContentValues();
playlistValues.put(DBAccessHelper.PLAYLIST_NAME, playlistName);
playlistValues.put(DBAccessHelper.PLAYLIST_ID, playlistID);
playlistValues.put(DBAccessHelper.PLAYLIST_ART_URL, playlistArtUrl);
playlistValues.put(DBAccessHelper.PLAYLIST_SOURCE, DBAccessHelper.GMUSIC);
playlistValues.put(DBAccessHelper.PLAYLIST_BLACKLIST_STATUS, "FALSE");
//Add all the entries to the database to build the songs library.
musicLibraryPlaylistsDBHelper.getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_PLAYLISTS_NAME,
null,
playlistValues);
}
musicLibraryPlaylistsDBHelper.getWritableDatabase().setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//Seal off all connections to the database.
musicLibraryPlaylistsDBHelper.getWritableDatabase().endTransaction();
musicLibraryPlaylistsDBHelper.close();
}
//Build the genres library.
updateGenreSongCount();
return "SUCCESS"; */
return null;
}
/**
* Retrieves the user's playlists and their contents using the WebClient protocol.
*/
//@SuppressWarnings("static-access")
/*private void getPlaylistsWebClient() {
//Clear out all the current Google Play Music playlists in the database.\
mApp.getDBAccessHelper().deleteAllGooglePlayMusicPlaylists();
//Insert the songs and their metadata into Jams' local database.
To improve database insertion performance, we'll use a single transaction
* for the entire operation. SQLite journals each database insertion and
* creates a new transaction by default. We'll override this functionality
* and create a single transaction for all the database record insertions.
* In theory, this should reduce NAND memory overhead times and result in
* a 2x to 5x performance increase.
GMusicClientCalls gMusicClientCalls = GMusicClientCalls.getInstance(mContext);
try {
//Open a connection to the database.
mApp.getDBAccessHelper().getMusicLibraryPlaylistsDBHelper().getWritableDatabase().beginTransaction();
//Get a list of all playlists from Google's servers.
playlistsJSONArray = gMusicClientCalls.getUserPlaylistsMobileClient(mContext);
//Avoid "Divide by zero" errors.
int scanningPlaylistsIncrement;
if (playlistsJSONArray.length()!=0) {
scanningPlaylistsIncrement = 100000/playlistsJSONArray.length();
} else {
scanningPlaylistsIncrement = 100000/1;
}
currentTask = mContext.getResources().getString(R.string.syncing_with_google_play_music);
MobileClientPlaylistsSchema currentPlaylist = new MobileClientPlaylistsSchema();
WebClientSongsSchema currentPlaylistSong = new WebClientSongsSchema();
for (int i=0; i < playlistsJSONArray.length(); i++) {
currentPlaylist = currentPlaylist.fromJsonObject(playlistsJSONArray.getJSONObject(i));
currentProgressValue = currentProgressValue + scanningPlaylistsIncrement;
publishProgress();
//Get the playlist's metadata.
String playlistName = currentPlaylist.getName();
String playlistId = currentPlaylist.getPlaylistId();
String playlistArtUrl = "";
//Retrieve all the song's within the current playlist.
JSONArray songsArray = gMusicClientCalls.getPlaylistEntriesWebClient(mContext, playlistId);
//Loop through the current playlist's songs array and retrieve each song's metadata.
for (int j=0; j < songsArray.length(); j++) {
try {
currentPlaylistSong = currentPlaylistSong.fromJsonObject(songsArray.getJSONObject(j));
//Extract the current playlist song's metadata.
String songTrackId = currentPlaylistSong.getId();
String playlistEntryId = currentPlaylistSong.getPlaylistEntryId();
ContentValues playlistValues = new ContentValues();
playlistValues.put(DBAccessHelper.PLAYLIST_NAME, playlistName);
playlistValues.put(DBAccessHelper.PLAYLIST_ID, playlistId);
playlistValues.put(DBAccessHelper.PLAYLIST_ART_URL, playlistArtUrl);
playlistValues.put(DBAccessHelper.PLAYLIST_SOURCE, DBAccessHelper.GMUSIC);
playlistValues.put(DBAccessHelper.PLAYLIST_BLACKLIST_STATUS, "FALSE");
playlistValues.put(DBAccessHelper.PLAYLIST_SONG_FILE_PATH, songTrackId);
playlistValues.put(DBAccessHelper.PLAYLIST_SONG_ENTRY_ID, playlistEntryId);
playlistValues.put(DBAccessHelper.PLAYLIST_ORDER, j);
//Add all the entries to the database to build the songs library.
mApp.getDBAccessHelper().getMusicLibraryPlaylistsDBHelper().getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_PLAYLISTS_NAME,
null,
playlistValues);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
mApp.getDBAccessHelper().getMusicLibraryPlaylistsDBHelper().getWritableDatabase().setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//Seal off all connections to the database.
mApp.getDBAccessHelper().getMusicLibraryPlaylistsDBHelper().getWritableDatabase().endTransaction();
}
}*/
/*************************************************************************************
* Retrieves the user's playlists and their contents using the MobileClient protocol.
*
* @deprecated The entryIds that we're fetching from the MobileClient protocol seem
* to be broken. They don't work with reordering playlist songs. I'll fix this if/when
* I have time. Until then, I'm gonna use getPlaylistsWebClient().
*************************************************************************************/
@SuppressWarnings("static-access")
private void getPlaylistsMobileClient() {
/* //Clear out all the current Google Play Music playlists in the database.
DBAccessHelper musicLibraryPlaylistsDBHelper = new DBAccessHelper(mContext);
musicLibraryPlaylistsDBHelper.deleteAllGooglePlayMusicPlaylists();
//Insert the songs and their metadata into Jams' local database.
To improve database insertion performance, we'll use a single transaction
* for the entire operation. SQLite journals each database insertion and
* creates a new transaction by default. We'll override this functionality
* and create a single transaction for all the database record insertions.
* In theory, this should reduce NAND memory overhead times and result in
* a 2x to 5x performance increase.
try {
//Open a connection to the database.
musicLibraryPlaylistsDBHelper.getWritableDatabase().beginTransaction();
*//*****************************************************************************
* The following calls are based on the MobileClient endpoints. Unfortunately,
* we can't get the correct entryIds for each song with these calls, so we'll
* have to revert to using the WebClient calls.
*****************************************************************************//*
//Instantiate the GMusic API and retrieve an array of all playlists.
GMusicClientCalls gMusicClientCalls = GMusicClientCalls.getInstance(mContext);
try {
playlistsJSONArray = gMusicClientCalls.getUserPlaylistsMobileClient(mContext);
} catch (JSONException e) {
e.printStackTrace();
}
//Retrieve an array of all song entries within every playlist.
try {
playlistEntriesJSONArray = gMusicClientCalls.getPlaylistEntriesMobileClient(mContext);
} catch (JSONException e) {
e.printStackTrace();
}
Now that we have a JSONArray with all the unique playlists, it's time to
* index the playlistIds and their name within the array. This will
* allow us to efficiently figure out the name of the playlist without
* going through the entire original array over and over again.
MobileClientPlaylistsSchema currentPlaylist = new MobileClientPlaylistsSchema();
for (int k=0; k < playlistsJSONArray.length(); k++) {
currentPlaylist = currentPlaylist.fromJsonObject(playlistsJSONArray.getJSONObject(k));
if (!playlistIdsNameMap.containsKey(currentPlaylist.getPlaylistId())) {
playlistIdsNameMap.put(currentPlaylist.getPlaylistId(), currentPlaylist.getName());
}
}
//Avoid "Divide by zero" errors.
int scanningPlaylistsIncrement;
if (playlistEntriesJSONArray.length()!=0) {
scanningPlaylistsIncrement = 100000/playlistEntriesJSONArray.length();
} else {
scanningPlaylistsIncrement = 100000/1;
}
currentTask = mContext.getResources().getString(R.string.syncing_with_google_play_music);
MobileClientPlaylistEntriesSchema currentPlaylistEntry = new MobileClientPlaylistEntriesSchema();
for (int i=0; i < playlistEntriesJSONArray.length(); i++) {
currentProgressValue = currentProgressValue + scanningPlaylistsIncrement;
publishProgress();
//Get the playlist's metadata.
currentPlaylistEntry = currentPlaylistEntry.fromJsonObject(playlistEntriesJSONArray.getJSONObject(i));
String playlistName = playlistIdsNameMap.get(currentPlaylistEntry.getPlaylistId());
String playlistId = currentPlaylistEntry.getPlaylistId();
String id = currentPlaylistEntry.getId();
String clientId = currentPlaylistEntry.getClientId();
String trackId = currentPlaylistEntry.getTrackId();
GMusic's backend server uses horribly misleading JSON key names.
* Each playlist entry has an entryId. When reordering songs, this
* entryId is actually the clientId of the song. The songId matches
* trackId. The "id" key in the JSON response is seemingly not
* used for anything in particular.
ContentValues playlistValues = new ContentValues();
playlistValues.put(DBAccessHelper.PLAYLIST_NAME, playlistName);
playlistValues.put(DBAccessHelper.PLAYLIST_ID, playlistId);
playlistValues.put(DBAccessHelper.PLAYLIST_ART_URL, "");
playlistValues.put(DBAccessHelper.PLAYLIST_SOURCE, DBAccessHelper.GMUSIC);
playlistValues.put(DBAccessHelper.PLAYLIST_SONG_ID, id);
playlistValues.put(DBAccessHelper.PLAYLIST_BLACKLIST_STATUS, "FALSE");
playlistValues.put(DBAccessHelper.PLAYLIST_ORDER, i);
playlistValues.put(DBAccessHelper.PLAYLIST_SONG_ENTRY_ID, clientId);
Log.e("DEBUG", "--------------------PLAYLIST ENTRY--------------------");
Log.e("DEBUG", "playlistName: " + playlistName);
Log.e("DEBUG", "playlistId: " + playlistId);
Log.e("DEBUG", "id: " + id);
Log.e("DEBUG", "clientId (entryId): " + clientId);
Log.e("DEBUG", "trackId: " + trackId);
We're gonna have to save the playlist's song IDs into the PLAYLIST_SONG_FILE_PATH
* field. Google Play Music playlist songs don't have a file path, but we're using a
* JOIN in PlaylistsFlippedFragment that relies on this field, so we'll need to use the
* "songId" param as a placeholder instead. The "trackId" key corresponds to "songId"
* in the songs table.
playlistValues.put(DBAccessHelper.PLAYLIST_SONG_FILE_PATH, trackId);
//Add all the entries to the database to build the songs library.
musicLibraryPlaylistsDBHelper.getWritableDatabase().insert(DBAccessHelper.MUSIC_LIBRARY_PLAYLISTS_NAME,
null,
playlistValues);
}
musicLibraryPlaylistsDBHelper.getWritableDatabase().setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//Seal off all connections to the database.
musicLibraryPlaylistsDBHelper.getWritableDatabase().endTransaction();
musicLibraryPlaylistsDBHelper.close();
}*/
}
/****************************************************************************************
* Scans the entire Music Library for songs, fetches their genres, and inputs the total
* count for that genre into each song's genre.
****************************************************************************************/
public void updateGenreSongCount() {
//We'll get the number of songs in a particular genre and apply that tag to all songs.
String genre = "";
int songCount = 0;
int buildingGenresIncrement;
currentTask = "Building Genres";
if (genresList.size()!=0) {
buildingGenresIncrement = 100000/genresList.size();
} else {
buildingGenresIncrement = 100000/1;
}
//Open a single transaction connection to keep the operation as efficient as possible.
for (int i=0; i < genresList.size(); i++) {
currentProgressValue = currentProgressValue + buildingGenresIncrement;
publishProgress();
try {
genre = genresList.get(i);
if (genre.contains("'")) {
genre = genre.replace("'", "''");
}
//Get the number of songs in this genre.
songCount = mApp.getDBAccessHelper().getGenreSongCount(genre);
mApp.getDBAccessHelper().insertNumberOfSongsInGenre(genre, songCount);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
/**
* Public method that provides access to the onProgressUpdate() method.
* Used to update the progress bar from a different class/activity.
*
* @param progressParams
*/
public void callOnProgressUpdate(String... progressParams) {
publishProgress(progressParams);
}
@Override
protected void onProgressUpdate(String... progressParams) {
super.onProgressUpdate(progressParams);
/*//Update the notification.
BuildMusicLibraryService.mBuilder.setTicker(null);
BuildMusicLibraryService.mBuilder.setContentTitle(mContext.getResources().getString(R.string.getting_google_play_music_library));
BuildMusicLibraryService.mBuilder.setContentText(currentTask);
BuildMusicLibraryService.mBuilder.setContentInfo(null);
BuildMusicLibraryService.mBuilder.setProgress(100000, currentProgressValue, false);
BuildMusicLibraryService.mNotification = BuildMusicLibraryService.mBuilder.build();
BuildMusicLibraryService.mNotifyManager.notify(BuildMusicLibraryService.mNotificationId,
BuildMusicLibraryService.mNotification);*/
}
@Override
protected void onPostExecute(String arg0) {
//Release the wakelock.
wakeLock.release();
}
}