/* This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Subsonic. If not, see . Copyright 2009 (C) Sindre Mehus */ package com.thejoshwa.ultrasonic.androidapp.activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import com.thejoshwa.ultrasonic.androidapp.R; import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory; import com.thejoshwa.ultrasonic.androidapp.service.DownloadFile; import com.thejoshwa.ultrasonic.androidapp.service.MusicService; import com.thejoshwa.ultrasonic.androidapp.service.MusicServiceFactory; import com.thejoshwa.ultrasonic.androidapp.util.Constants; import com.thejoshwa.ultrasonic.androidapp.util.EntryAdapter; import com.thejoshwa.ultrasonic.androidapp.util.Pair; import com.thejoshwa.ultrasonic.androidapp.util.TabActivityBackgroundTask; import com.thejoshwa.ultrasonic.androidapp.util.Util; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; public class SelectAlbumActivity extends SubsonicTabActivity { private static final String TAG = SelectAlbumActivity.class.getSimpleName(); private ListView entryList; private View header; private View footer; private View emptyView; private Button selectButton; private Button playNowButton; private Button playLastButton; private Button pinButton; private Button unpinButton; private Button deleteButton; private Button moreButton; private boolean licenseValid; private boolean playAllButtonVisible; private MenuItem playAllButton; private boolean showHeader = true; private Random random = new Random(); /** * Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.select_album); entryList = (ListView) findViewById(R.id.select_album_entries); header = LayoutInflater.from(this).inflate(R.layout.select_album_header, entryList, false); footer = LayoutInflater.from(this).inflate(R.layout.select_album_footer, entryList, false); entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); entryList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { if (position >= 0) { MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position); if (entry.isDirectory()) { Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class); intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent); } else if (entry.isVideo()) { playVideo(entry); } else { enableButtons(); } } } }); entryList.setOnTouchListener(gestureListener); selectButton = (Button) findViewById(R.id.select_album_select); playNowButton = (Button) findViewById(R.id.select_album_play_now); playLastButton = (Button) findViewById(R.id.select_album_play_last); pinButton = (Button) footer.findViewById(R.id.select_album_pin); unpinButton = (Button) footer.findViewById(R.id.select_album_unpin); deleteButton = (Button) footer.findViewById(R.id.select_album_delete); moreButton = (Button) footer.findViewById(R.id.select_album_more); emptyView = findViewById(R.id.select_album_empty); selectButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { selectAllOrNone(); } }); playNowButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { download(false, false, true, false); selectAll(false, false); } }); playLastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { download(true, false, false, false); selectAll(false, false); } }); pinButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { download(true, true, false, false); selectAll(false, false); } }); unpinButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { unpin(); selectAll(false, false); } }); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { delete(); selectAll(false, false); } }); registerForContextMenu(entryList); enableButtons(); String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID); String name = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME); String playlistId = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID); String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME); String albumListType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); String genreName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_GENRE_NAME); int albumListTitle = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0); int getStarredTracks = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_STARRED, 0); int getRandomTracks = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_RANDOM, 0); int albumListSize = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); int albumListOffset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); if (playlistId != null) { getPlaylist(playlistId, playlistName); } else if (albumListType != null) { getAlbumList(albumListType, albumListTitle, albumListSize, albumListOffset); } else if (genreName != null) { getSongsForGenre(genreName, albumListSize, albumListOffset); } else if (getStarredTracks != 0) { getStarred(); } else if (getRandomTracks != 0) { getRandom(albumListSize); } else { getMusicDirectory(id, name); } } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); playAllButton = menu.findItem(R.id.select_album_play_all); playAllButton.setVisible(playAllButtonVisible); return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.select_album, menu); inflater.inflate(R.menu.select_common, menu); super.onCreateOptionsMenu(menu); return true; } private void playAll() { boolean hasSubFolders = false; for (int i = 0; i < entryList.getCount(); i++) { MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i); if (entry != null && entry.isDirectory()) { hasSubFolders = true; break; } } String id = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID); if (hasSubFolders && id != null) { downloadRecursively(id, false, false, true); } else { selectAll(true, false); download(false, false, true, false); selectAll(false, false); } } private void refresh() { finish(); Intent intent = getIntent(); intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true); Util.startActivityWithoutTransition(this, intent); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position); if (entry.isDirectory()) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.select_album_context, menu); } else { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.select_song_context, menu); } } @Override public boolean onContextItemSelected(MenuItem menuItem) { AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position); List songs = new ArrayList(10); songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(info.position)); switch (menuItem.getItemId()) { case R.id.album_menu_play_now: downloadRecursively(entry.getId(), false, false, true); break; case R.id.album_menu_play_last: downloadRecursively(entry.getId(), false, true, false); break; case R.id.album_menu_pin: downloadRecursively(entry.getId(), true, true, false); break; case R.id.song_menu_play_now: getDownloadService().download(songs, false, true, true); break; case R.id.song_menu_play_next: getDownloadService().download(songs, false, false, true); break; case R.id.song_menu_play_last: getDownloadService().download(songs, false, false, false); break; case R.id.select_album_play_all: playAll(); break; default: return super.onContextItemSelected(menuItem); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.main_shuffle: Intent intent1 = new Intent(this, DownloadActivity.class); intent1.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); Util.startActivityWithoutTransition(this, intent1); return true; case R.id.menu_refresh: refresh(); return true; case R.id.select_album_play_all: playAll(); return true; case R.id.menu_exit: Intent intent = new Intent(this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true); Util.startActivityWithoutTransition(this, intent); return true; case R.id.menu_settings: startActivity(new Intent(this, SettingsActivity.class)); return true; case R.id.menu_help: startActivity(new Intent(this, HelpActivity.class)); return true; } return false; } private void getMusicDirectory(final String id, String name) { setTitle(name); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false); return service.getMusicDirectory(id, refresh, SelectAlbumActivity.this, this); } }.execute(); } private void getSongsForGenre(final String genre, final int count, final int offset) { setTitle(genre); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { return service.getSongsByGenre(genre, count, offset, SelectAlbumActivity.this, this); } @Override protected void done(Pair result) { // Hide more button when results are less than album list size if (result.getFirst().getChildren().size() < getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)) { moreButton.setVisibility(View.GONE); } else { moreButton.setVisibility(View.VISIBLE); } moreButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class); String genre = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_GENRE_NAME); int size = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); int offset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) + size; intent.putExtra(Constants.INTENT_EXTRA_NAME_GENRE_NAME, genre); intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size); intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset); Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent); } }); super.done(result); } }.execute(); } private void getStarred() { setTitle(R.string.main_songs_starred); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { return Util.getSongsFromSearchResult(service.getStarred(SelectAlbumActivity.this, this)); } }.execute(); } private void getRandom(final int size) { setTitle(R.string.main_songs_random); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { return service.getRandomSongs(size, SelectAlbumActivity.this, this); } }.execute(); } private void getPlaylist(final String playlistId, String playlistName) { setTitle(playlistName); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { return service.getPlaylist(playlistId, SelectAlbumActivity.this, this); } }.execute(); } private void getAlbumList(final String albumListType, final int albumListTitle, final int size, final int offset) { showHeader = false; setTitle(albumListTitle); new LoadTask() { @Override protected MusicDirectory load(MusicService service) throws Exception { return service.getAlbumList(albumListType, size, offset, SelectAlbumActivity.this, this); } @Override protected void done(Pair result) { if (!result.getFirst().getChildren().isEmpty()) { pinButton.setVisibility(View.GONE); unpinButton.setVisibility(View.GONE); deleteButton.setVisibility(View.GONE); // Hide more button when results are less than album list size if (result.getFirst().getChildren().size() < getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0)) { moreButton.setVisibility(View.GONE); } else { entryList.addFooterView(footer); moreButton.setVisibility(View.VISIBLE); } moreButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(SelectAlbumActivity.this, SelectAlbumActivity.class); int albumListTitle = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0); String type = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); int size = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); int offset = getIntent().getIntExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) + size; intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, albumListTitle); intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size); intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset); Util.startActivityWithoutTransition(SelectAlbumActivity.this, intent); } }); } super.done(result); } }.execute(); } private void selectAllOrNone() { boolean someUnselected = false; int count = entryList.getCount(); for (int i = 0; i < count; i++) { if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof MusicDirectory.Entry) { someUnselected = true; break; } } selectAll(someUnselected, true); } private void selectAll(boolean selected, boolean toast) { int count = entryList.getCount(); int selectedCount = 0; for (int i = 0; i < count; i++) { MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i); if (entry != null && !entry.isDirectory() && !entry.isVideo()) { entryList.setItemChecked(i, selected); selectedCount++; } } // Display toast: N tracks selected / N tracks unselected if (toast) { int toastResId = selected ? R.string.select_album_n_selected : R.string.select_album_n_unselected; Util.toast(this, getString(toastResId, selectedCount)); } enableButtons(); } private void enableButtons() { if (getDownloadService() == null) { return; } List selection = getSelectedSongs(); boolean enabled = !selection.isEmpty(); boolean unpinEnabled = false; boolean deleteEnabled = false; for (MusicDirectory.Entry song : selection) { DownloadFile downloadFile = getDownloadService().forSong(song); if (downloadFile.isCompleteFileAvailable()) { deleteEnabled = true; } if (downloadFile.isSaved()) { unpinEnabled = true; } } playNowButton.setEnabled(enabled); playLastButton.setEnabled(enabled); pinButton.setEnabled(enabled && !Util.isOffline(this)); unpinButton.setEnabled(unpinEnabled); deleteButton.setEnabled(deleteEnabled); } private List getSelectedSongs() { List songs = new ArrayList(10); int count = entryList.getCount(); for (int i = 0; i < count; i++) { if (entryList.isItemChecked(i)) { songs.add((MusicDirectory.Entry) entryList.getItemAtPosition(i)); } } return songs; } private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext) { if (getDownloadService() == null) { return; } final List songs = getSelectedSongs(); Runnable onValid = new Runnable() { @Override public void run() { if (!append) { getDownloadService().clear(); } warnIfNetworkOrStorageUnavailable(); getDownloadService().download(songs, save, autoplay, playNext); String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME); if (playlistName != null) { getDownloadService().setSuggestedPlaylistName(playlistName); } if (autoplay) { Util.startActivityWithoutTransition(SelectAlbumActivity.this, DownloadActivity.class); } else if (save) { Util.toast(SelectAlbumActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); } else if (append) { Util.toast(SelectAlbumActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size())); } } }; checkLicenseAndTrialPeriod(onValid); } private void delete() { if (getDownloadService() != null) { getDownloadService().delete(getSelectedSongs()); } } private void unpin() { if (getDownloadService() != null) { getDownloadService().unpin(getSelectedSongs()); } } private void playVideo(MusicDirectory.Entry entry) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(this, entry.getId()))); startActivity(intent); } private void checkLicenseAndTrialPeriod(Runnable onValid) { if (licenseValid) { onValid.run(); return; } int trialDaysLeft = Util.getRemainingTrialDays(this); Log.i(TAG, trialDaysLeft + " trial days left."); if (trialDaysLeft == 0) { showDonationDialog(trialDaysLeft, null); } else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2) { showDonationDialog(trialDaysLeft, onValid); } else { Util.toast(this, getResources().getString(R.string.select_album_not_licensed, trialDaysLeft)); onValid.run(); } } private void showDonationDialog(int trialDaysLeft, final Runnable onValid) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(android.R.drawable.ic_dialog_info); if (trialDaysLeft == 0) { builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left); } else { builder.setTitle(getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left, trialDaysLeft, trialDaysLeft)); } builder.setMessage(R.string.select_album_donate_dialog_message); builder.setPositiveButton(R.string.select_album_donate_dialog_now, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL))); } }); builder.setNegativeButton(R.string.select_album_donate_dialog_later, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); if (onValid != null) { onValid.run(); } } }); builder.create().show(); } private abstract class LoadTask extends TabActivityBackgroundTask> { public LoadTask() { super(SelectAlbumActivity.this); } protected abstract MusicDirectory load(MusicService service) throws Exception; @Override protected Pair doInBackground() throws Throwable { MusicService musicService = MusicServiceFactory.getMusicService(SelectAlbumActivity.this); MusicDirectory dir = load(musicService); boolean valid = musicService.isLicenseValid(SelectAlbumActivity.this, this); return new Pair(dir, valid); } @Override protected void done(Pair result) { MusicDirectory musicDirectory = result.getFirst(); List entries = musicDirectory.getChildren(); String directoryName = musicDirectory.getName(); int songCount = 0; for (MusicDirectory.Entry entry : entries) { if (!entry.isDirectory()) { songCount++; } } if (songCount > 0) { if(showHeader) { entryList.addHeaderView(createHeader(entries, directoryName, songCount), null, false); } entryList.addFooterView(footer); selectButton.setVisibility(View.VISIBLE); playNowButton.setVisibility(View.VISIBLE); playLastButton.setVisibility(View.VISIBLE); } boolean isAlbumList = getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); playAllButtonVisible = !(isAlbumList || entries.isEmpty()); emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE); if (playAllButton != null) { playAllButton.setVisible(playAllButtonVisible); } entryList.setAdapter(new EntryAdapter(SelectAlbumActivity.this, getImageLoader(), entries, true)); licenseValid = result.getSecond(); boolean playAll = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false); if (playAll && songCount > 0) { playAll(); } } private View createHeader(List entries, String name, int songCount) { View coverArtView = header.findViewById(R.id.select_album_art); int artworkSelection = random.nextInt(entries.size()); getImageLoader().loadImage(coverArtView, entries.get(artworkSelection), true, true); TextView titleView = (TextView) header.findViewById(R.id.select_album_title); titleView.setText(name != null ? name : getTitle()); Set artists = new HashSet(); Set grandParents = new HashSet(); Set genres = new HashSet(); long totalDuration = 0; for (MusicDirectory.Entry entry : entries) { if (!entry.isDirectory()) { if (Util.shouldUseFolderForArtistName(getBaseContext())) { // Find the top level folder, assume it is the album artist String path = entry.getPath(); if (path != null) { int slashIndex = path.indexOf("/"); if (slashIndex != 0) { grandParents.add(path.substring(0, slashIndex)); } } } if (entry.getArtist() != null) { totalDuration += entry.getDuration(); artists.add(entry.getArtist()); } if (entry.getGenre() != null) { genres.add(entry.getGenre()); } } } TextView artistView = (TextView) header.findViewById(R.id.select_album_artist); String artist = null; if (artists.size() == 1) { artist = artists.iterator().next(); } else if (grandParents.size() == 1) { artist = grandParents.iterator().next(); } else { artist = getResources().getString(R.string.common_various_artists); } artistView.setText(artist); TextView genreView = (TextView) header.findViewById(R.id.select_album_genre); String genre = null; if (genres.size() == 1) { genre = genres.iterator().next(); } else { genre = getResources().getString(R.string.common_multiple_genres); } genreView.setText(genre); TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count); String songs = getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount); songCountView.setText(songs); long millis = totalDuration * 1000; String duration = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millis), TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)), TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)) ); TextView durationView = (TextView) header.findViewById(R.id.select_album_duration); durationView.setText(duration); return header; } } }