2 * Copyright (C) 2012 Andrew Neal Licensed under the Apache License, Version 2.0
3 * (the "License"); you may not use this file except in compliance with the
4 * License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 * or agreed to in writing, software distributed under the License is
7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 * KIND, either express or implied. See the License for the specific language
9 * governing permissions and limitations under the License.
12 package com.cyngn.eleven.ui.activities;
14 import android.app.ActionBar;
15 import android.app.Activity;
16 import android.app.SearchManager;
17 import android.content.Intent;
18 import android.content.pm.ActivityInfo;
19 import android.database.Cursor;
20 import android.graphics.Bitmap;
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.os.SystemClock;
24 import android.provider.MediaStore;
25 import android.support.v4.view.ViewPager;
26 import android.support.v4.view.ViewPager.OnPageChangeListener;
27 import android.view.Menu;
28 import android.view.MenuItem;
29 import android.view.View;
31 import com.cyngn.eleven.Config;
32 import com.cyngn.eleven.R;
33 import com.cyngn.eleven.adapters.PagerAdapter;
34 import com.cyngn.eleven.cache.ImageFetcher;
35 import com.cyngn.eleven.menu.PhotoSelectionDialog;
36 import com.cyngn.eleven.menu.PhotoSelectionDialog.ProfileType;
37 import com.cyngn.eleven.ui.fragments.profile.AlbumSongFragment;
38 import com.cyngn.eleven.ui.fragments.profile.ArtistAlbumFragment;
39 import com.cyngn.eleven.ui.fragments.profile.ArtistSongFragment;
40 import com.cyngn.eleven.ui.fragments.profile.GenreSongFragment;
41 import com.cyngn.eleven.ui.fragments.profile.LastAddedFragment;
42 import com.cyngn.eleven.utils.ApolloUtils;
43 import com.cyngn.eleven.utils.MusicUtils;
44 import com.cyngn.eleven.utils.NavUtils;
45 import com.cyngn.eleven.utils.PreferenceUtils;
46 import com.cyngn.eleven.utils.SortOrder;
47 import com.cyngn.eleven.widgets.ProfileTabCarousel;
48 import com.cyngn.eleven.widgets.ProfileTabCarousel.Listener;
51 * The {@link Activity} is used to display the data for specific
52 * artists, albums, playlists, and genres. This class is only used on phones.
54 * @author Andrew Neal (andrewdneal@gmail.com)
56 public class ProfileActivity extends SlidingPanelActivity implements OnPageChangeListener, Listener {
58 private static final int NEW_PHOTO = 1;
61 * The Bundle to pass into the Fragments
63 private Bundle mArguments;
68 private ViewPager mViewPager;
73 private PagerAdapter mPagerAdapter;
76 * Profile header carousel
78 private ProfileTabCarousel mTabCarousel;
81 * MIME type of the profile
86 * Artist name passed into the class
88 private String mArtistName;
91 * The main profile title
93 private String mProfileName;
98 private ImageFetcher mImageFetcher;
100 private PreferenceUtils mPreferences;
106 public void onCreate(final Bundle savedInstanceState) {
107 mTargetNavigatePanel = Panel.Browse;
108 super.onCreate(savedInstanceState);
109 // Temporay until I can work out a nice landscape layout
110 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
112 // Get the preferences
113 mPreferences = PreferenceUtils.getInstance(this);
115 // Initialze the image fetcher
116 mImageFetcher = ApolloUtils.getImageFetcher(this);
118 // Initialize the Bundle
119 mArguments = savedInstanceState != null ? savedInstanceState : getIntent().getExtras();
121 mType = mArguments.getString(Config.MIME_TYPE);
122 // Get the profile title
123 mProfileName = mArguments.getString(Config.NAME);
124 // Get the artist name
125 if (isArtist() || isAlbum()) {
126 mArtistName = mArguments.getString(Config.ARTIST_NAME);
129 // Initialize the pager adapter
130 mPagerAdapter = new PagerAdapter(this);
132 // Initialze the carousel
133 mTabCarousel = (ProfileTabCarousel)findViewById(R.id.acivity_profile_base_tab_carousel);
134 mTabCarousel.reset();
135 mTabCarousel.getPhoto().setOnClickListener(new View.OnClickListener() {
138 public void onClick(final View v) {
139 ProfileType profileType;
141 profileType = ProfileType.ARTIST;
142 } else if (isAlbum()) {
143 profileType = ProfileType.ALBUM;
145 profileType = ProfileType.OTHER;
147 PhotoSelectionDialog.newInstance(isArtist() ? mArtistName : mProfileName,
148 profileType).show(getSupportFragmentManager(), "PhotoSelectionDialog");
151 // Set up the action bar
152 final ActionBar actionBar = getActionBar();
153 actionBar.setIcon(R.drawable.ic_action_back);
154 actionBar.setHomeButtonEnabled(true);
156 /* Set up the artist profile */
158 // Add the carousel images
159 mTabCarousel.setArtistProfileHeader(this, mArtistName);
161 // Artist profile fragments
162 mPagerAdapter.add(ArtistSongFragment.class, mArguments);
163 mPagerAdapter.add(ArtistAlbumFragment.class, mArguments);
166 getActionBar().setTitle(mArtistName);
169 // Set up the album profile
171 // Add the carousel images
172 mTabCarousel.setAlbumProfileHeader(this, mProfileName, mArtistName);
174 // Album profile fragments
175 mPagerAdapter.add(AlbumSongFragment.class, mArguments);
177 // Action bar title = album name
178 getActionBar().setTitle(mProfileName);
179 // Action bar subtitle = year released
180 getActionBar().setSubtitle(mArguments.getString(Config.ALBUM_YEAR));
182 // Set up the last added profile
184 // Add the carousel images
185 mTabCarousel.setPlaylistOrGenreProfileHeader(this, mProfileName);
187 // Last added fragment
188 mPagerAdapter.add(LastAddedFragment.class, null);
190 // Action bar title = Last added
191 getActionBar().setTitle(mProfileName);
193 // Set up the genre profile
195 // Add the carousel images
196 mTabCarousel.setPlaylistOrGenreProfileHeader(this, mProfileName);
198 // Genre profile fragments
199 mPagerAdapter.add(GenreSongFragment.class, mArguments);
201 // Action bar title = playlist name
202 getActionBar().setTitle(mProfileName);
205 // Initialize the ViewPager
206 mViewPager = (ViewPager)findViewById(R.id.acivity_profile_base_pager);
208 mViewPager.setAdapter(mPagerAdapter);
210 mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount() - 1);
211 // Attach the page change listener
212 mViewPager.setOnPageChangeListener(this);
213 // Attach the carousel listener
214 mTabCarousel.setListener(this);
218 protected int getLayoutToInflate() {
219 return R.layout.activity_profile_base;
226 protected void onPause() {
228 mImageFetcher.flush();
235 public boolean onPrepareOptionsMenu(final Menu menu) {
236 // Set the shuffle all title to "play all" if a playlist.
237 final MenuItem shuffle = menu.findItem(R.id.menu_shuffle);
240 title = getString(R.string.menu_play_all);
242 title = getString(R.string.menu_shuffle);
244 shuffle.setTitle(title);
245 return super.onPrepareOptionsMenu(menu);
252 public boolean onCreateOptionsMenu(final Menu menu) {
254 getMenuInflater().inflate(R.menu.shuffle, menu);
256 if (isArtistSongPage()) {
257 getMenuInflater().inflate(R.menu.artist_song_sort_by, menu);
258 } else if (isArtistAlbumPage()) {
259 getMenuInflater().inflate(R.menu.artist_album_sort_by, menu);
260 } else if (isAlbum()) {
261 getMenuInflater().inflate(R.menu.album_song_sort_by, menu);
263 return super.onCreateOptionsMenu(menu);
270 public boolean onOptionsItemSelected(final MenuItem item) {
271 switch (item.getItemId()) {
272 case android.R.id.home:
273 // If an album profile, go up to the artist profile
275 NavUtils.openArtistProfile(this, mArtistName);
278 // Otherwise just go back
282 case R.id.menu_shuffle: {
283 final long id = mArguments.getLong(Config.ID);
286 list = MusicUtils.getSongListForArtist(this, id);
287 } else if (isAlbum()) {
288 list = MusicUtils.getSongListForAlbum(this, id);
289 } else if (isGenre()) {
290 list = MusicUtils.getSongListForGenre(this, id);
293 MusicUtils.playLastAdded(this);
295 if (list != null && list.length > 0) {
296 MusicUtils.playAll(this, list, 0, true);
301 case R.id.menu_sort_by_az:
302 if (isArtistSongPage()) {
303 mPreferences.setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_A_Z);
304 getArtistSongFragment().refresh();
305 } else if (isArtistAlbumPage()) {
306 mPreferences.setArtistAlbumSortOrder(SortOrder.ArtistAlbumSortOrder.ALBUM_A_Z);
307 getArtistAlbumFragment().refresh();
309 mPreferences.setAlbumSongSortOrder(SortOrder.AlbumSongSortOrder.SONG_A_Z);
310 getAlbumSongFragment().refresh();
313 case R.id.menu_sort_by_za:
314 if (isArtistSongPage()) {
315 mPreferences.setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_Z_A);
316 getArtistSongFragment().refresh();
317 } else if (isArtistAlbumPage()) {
318 mPreferences.setArtistAlbumSortOrder(SortOrder.ArtistAlbumSortOrder.ALBUM_Z_A);
319 getArtistAlbumFragment().refresh();
321 mPreferences.setAlbumSongSortOrder(SortOrder.AlbumSongSortOrder.SONG_Z_A);
322 getAlbumSongFragment().refresh();
325 case R.id.menu_sort_by_album:
326 if (isArtistSongPage()) {
327 mPreferences.setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_ALBUM);
328 getArtistSongFragment().refresh();
331 case R.id.menu_sort_by_year:
332 if (isArtistSongPage()) {
333 mPreferences.setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_YEAR);
334 getArtistSongFragment().refresh();
335 } else if (isArtistAlbumPage()) {
336 mPreferences.setArtistAlbumSortOrder(SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR);
337 getArtistAlbumFragment().refresh();
340 case R.id.menu_sort_by_duration:
341 if (isArtistSongPage()) {
343 .setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_DURATION);
344 getArtistSongFragment().refresh();
346 mPreferences.setAlbumSongSortOrder(SortOrder.AlbumSongSortOrder.SONG_DURATION);
347 getAlbumSongFragment().refresh();
350 case R.id.menu_sort_by_date_added:
351 if (isArtistSongPage()) {
352 mPreferences.setArtistSongSortOrder(SortOrder.ArtistSongSortOrder.SONG_DATE);
353 getArtistSongFragment().refresh();
356 case R.id.menu_sort_by_track_list:
357 mPreferences.setAlbumSongSortOrder(SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST);
358 getAlbumSongFragment().refresh();
360 case R.id.menu_sort_by_filename:
361 if(isArtistSongPage()) {
362 mPreferences.setArtistSortOrder(SortOrder.ArtistSongSortOrder.SONG_FILENAME);
363 getArtistSongFragment().refresh();
366 mPreferences.setAlbumSongSortOrder(SortOrder.AlbumSongSortOrder.SONG_FILENAME);
367 getAlbumSongFragment().refresh();
373 return super.onOptionsItemSelected(item);
380 protected void onSaveInstanceState(final Bundle outState) {
381 super.onSaveInstanceState(outState);
382 outState.putAll(mArguments);
389 public void onBackPressed() {
390 super.onBackPressed();
397 public void onPageScrolled(final int position, final float positionOffset,
398 final int positionOffsetPixels) {
399 if (mViewPager.isFakeDragging()) {
403 final int scrollToX = (int)((position + positionOffset) * mTabCarousel
404 .getAllowedHorizontalScrollLength());
405 mTabCarousel.scrollTo(scrollToX, 0);
412 public void onPageSelected(final int position) {
413 mTabCarousel.setCurrentTab(position);
420 public void onPageScrollStateChanged(final int state) {
421 if (state == ViewPager.SCROLL_STATE_IDLE) {
422 mTabCarousel.restoreYCoordinate(75, mViewPager.getCurrentItem());
430 public void onTouchDown() {
431 if (!mViewPager.isFakeDragging()) {
432 mViewPager.beginFakeDrag();
440 public void onTouchUp() {
441 if (mViewPager.isFakeDragging()) {
442 mViewPager.endFakeDrag();
450 public void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
451 if (mViewPager.isFakeDragging()) {
452 mViewPager.fakeDragBy(oldl - l);
460 public void onTabSelected(final int position) {
461 mViewPager.setCurrentItem(position);
468 protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
469 super.onActivityResult(requestCode, resultCode, data);
470 if (requestCode == NEW_PHOTO) {
471 if (resultCode == RESULT_OK) {
472 final Uri selectedImage = data.getData();
473 final String[] filePathColumn = {
474 MediaStore.Images.Media.DATA
477 Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null,
479 if (cursor != null && cursor.moveToFirst()) {
480 final int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
481 final String picturePath = cursor.getString(columnIndex);
485 String key = mProfileName;
488 } else if (isAlbum()) {
489 key = ImageFetcher.generateAlbumCacheKey(mProfileName, mArtistName);
492 final Bitmap bitmap = ImageFetcher.decodeSampledBitmapFromFile(picturePath);
493 mImageFetcher.addBitmapToCache(key, bitmap);
495 mTabCarousel.getAlbumArt().setImageBitmap(bitmap);
497 mTabCarousel.getPhoto().setImageBitmap(bitmap);
507 * Starts an activity for result that returns an image from the Gallery.
509 public void selectNewPhoto() {
510 // First remove the old image
512 // Now open the gallery
513 final Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
514 intent.setType("image/*");
515 startActivityForResult(intent, NEW_PHOTO);
519 * Fetchs for the artist or album art, other wise sets the default header
522 public void selectOldPhoto() {
523 // First remove the old image
525 // Apply the old photo
527 mTabCarousel.setArtistProfileHeader(this, mArtistName);
528 } else if (isAlbum()) {
529 mTabCarousel.setAlbumProfileHeader(this, mProfileName, mArtistName);
531 mTabCarousel.setPlaylistOrGenreProfileHeader(this, mProfileName);
536 * When the user chooses {@code #selectOldPhoto()} while viewing an album
537 * profile, the image is, most likely, reverted back to the locally found
538 * artwork. This is specifically for fetching the image from Last.fm.
540 public void fetchAlbumArt() {
541 // First remove the old image
543 // Fetch for the artwork
544 mTabCarousel.fetchAlbumPhoto(this, mProfileName, mArtistName);
548 * Searches Google for the artist or album
550 public void googleSearch() {
551 String query = mProfileName;
554 } else if (isAlbum()) {
555 query = mProfileName + " " + mArtistName;
557 final Intent googleSearch = new Intent(Intent.ACTION_WEB_SEARCH);
558 googleSearch.putExtra(SearchManager.QUERY, query);
559 startActivity(googleSearch);
563 * Removes the header image from the cache.
565 private void removeFromCache() {
566 String key = mProfileName;
569 } else if (isAlbum()) {
570 key = ImageFetcher.generateAlbumCacheKey(mProfileName, mArtistName);
572 mImageFetcher.removeFromCache(key);
573 // Give the disk cache a little time before requesting a new image.
574 SystemClock.sleep(80);
578 * Finishes the activity and overrides the default animation.
580 private void goBack() {
585 * @return True if the MIME type is vnd.android.cursor.dir/artists, false
588 private final boolean isArtist() {
589 return mType.equals(MediaStore.Audio.Artists.CONTENT_TYPE);
593 * @return True if the MIME type is vnd.android.cursor.dir/albums, false
596 private final boolean isAlbum() {
597 return mType.equals(MediaStore.Audio.Albums.CONTENT_TYPE);
601 * @return True if the MIME type is vnd.android.cursor.dir/gere, false
604 private final boolean isGenre() {
605 return mType.equals(MediaStore.Audio.Genres.CONTENT_TYPE);
609 * @return True if the MIME type is "LastAdded", false otherwise.
611 private final boolean isLastAdded() {
612 return mType.equals(getString(R.string.playlist_last_added));
615 private boolean isArtistSongPage() {
616 return isArtist() && mViewPager.getCurrentItem() == 0;
619 private boolean isArtistAlbumPage() {
620 return isArtist() && mViewPager.getCurrentItem() == 1;
623 private ArtistSongFragment getArtistSongFragment() {
624 return (ArtistSongFragment)mPagerAdapter.getFragment(0);
627 private ArtistAlbumFragment getArtistAlbumFragment() {
628 return (ArtistAlbumFragment)mPagerAdapter.getFragment(1);
631 private AlbumSongFragment getAlbumSongFragment() {
632 return (AlbumSongFragment)mPagerAdapter.getFragment(0);