summaryrefslogtreecommitdiffstats
path: root/src/com/cyngn/eleven/adapters/AlbumArtPagerAdapter.java
blob: 996231b1e3133aa597a5190c906f44763e031fab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/*
 * Copyright (C) 2014 Cyanogen, Inc.
 */

package com.cyngn.eleven.adapters;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.cyngn.eleven.MusicPlaybackService;
import com.cyngn.eleven.R;
import com.cyngn.eleven.cache.ICacheListener;
import com.cyngn.eleven.cache.ImageCache;
import com.cyngn.eleven.model.AlbumArtistDetails;
import com.cyngn.eleven.utils.ApolloUtils;
import com.cyngn.eleven.utils.MusicUtils;
import com.cyngn.eleven.widgets.SquareImageView;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * A {@link android.support.v4.app.FragmentStatePagerAdapter} class for swiping between album art
 */
public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter {
    private static boolean DEBUG = false;
    private static final String TAG = AlbumArtPagerAdapter.class.getSimpleName();

    public static final long NO_TRACK_ID = -1;
    private static final int MAX_ALBUM_ARTIST_SIZE = 10;

    // This helps with flickering and jumping and reloading the same tracks
    private final static LinkedList<AlbumArtistDetails> sCacheAlbumArtistDetails = new LinkedList<AlbumArtistDetails>();

    /**
     * Adds the album artist details to the cache
     * @param details the AlbumArtistDetails to add
     */
    public static void addAlbumArtistDetails(AlbumArtistDetails details) {
        if (getAlbumArtistDetails(details.mAudioId) == null) {
            sCacheAlbumArtistDetails.add(details);
            if (sCacheAlbumArtistDetails.size() > MAX_ALBUM_ARTIST_SIZE) {
                sCacheAlbumArtistDetails.remove();
            }
        }
    }

    /**
     * Gets the album artist details for the audio track.  If it exists, it re-inserts the item
     * to the end of the queue so it is considered the 'freshest' and stays longer
     * @param audioId the audio track to look for
     * @return the details of the album artist
     */
    public static AlbumArtistDetails getAlbumArtistDetails(long audioId) {
        for (Iterator<AlbumArtistDetails> i = sCacheAlbumArtistDetails.descendingIterator(); i.hasNext();) {
            final AlbumArtistDetails entry = i.next();
            if (entry.mAudioId == audioId) {
                // remove it from the stack to re-add to the top
                i.remove();
                sCacheAlbumArtistDetails.add(entry);
                return entry;
            }
        }

        return null;
    }

    // the length of the playlist
    private int mPlaylistLen = 0;

    public AlbumArtPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(final int position) {
        long trackID = getTrackId(position);
        return AlbumArtFragment.newInstance(trackID);
    }

    @Override
    public int getCount() {
        return mPlaylistLen;
    }

    public void setPlaylistLength(final int len) {
        mPlaylistLen = len;
        notifyDataSetChanged();
    }

    /**
     * Gets the track id for the item at position
     * @param position position of the item of the queue
     * @return track id of the item at position or NO_TRACK_ID if unknown
     */
    private long getTrackId(int position) {
        if (MusicUtils.getRepeatMode() == MusicPlaybackService.REPEAT_CURRENT) {
            // if we are only playing one song, return the current audio id
            return MusicUtils.getCurrentAudioId();
        } else if (MusicUtils.getShuffleMode() == MusicPlaybackService.SHUFFLE_NONE) {
            // if we aren't shuffling, just return based on the queue position
            // add a check for empty queue
            return MusicUtils.getQueueItemAtPosition(position);
        } else {
            // if we are shuffling, there is no 'queue' going forward per say
            // because it is dynamically generated.  In that case we can only look
            // at the history and up to the very next track.  When we come back to this
            // after the demo, we should redo that queue logic to be able to give us
            // tracks going forward

            // how far into the history we are
            int positionOffset = MusicUtils.getQueueHistorySize();

            if (position - positionOffset == 0) { // current track
                return MusicUtils.getCurrentAudioId();
            } else if (position - positionOffset == 1) { // next track
                return MusicUtils.getNextAudioId();
            } else if (position < positionOffset) {
                int queuePosition = MusicUtils.getQueueHistoryPosition(position);
                if (position >= 0) {
                    return MusicUtils.getQueueItemAtPosition(queuePosition);
                }
            }
        }

        // fallback case
        return NO_TRACK_ID;
    }

    /**
     * The fragments to be displayed inside this adapter.  This wraps the album art
     * and handles loading the album art for a given audio id
     */
    public static class AlbumArtFragment extends Fragment implements ICacheListener {
        private static final String ID = "com.cyngn.eleven.adapters.AlbumArtPagerAdapter.AlbumArtFragment.ID";

        private View mRootView;
        private AlbumArtistLoader mTask;
        private SquareImageView mImageView;
        private long mAudioId = NO_TRACK_ID;

        public static AlbumArtFragment newInstance(final long trackId) {
            AlbumArtFragment frag = new AlbumArtFragment();
            final Bundle args = new Bundle();
            args.putLong(ID, trackId);
            frag.setArguments(args);
            return frag;
        }

        @Override
        public void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            mAudioId = getArguments().getLong(ID, NO_TRACK_ID);
            ImageCache.getInstance(getActivity()).addCacheListener(this);
        }

        @Override
        public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
            mRootView = inflater.inflate(R.layout.album_art_fragment, null);
            return mRootView;
        }

        @Override
        public void onDestroy() {
            super.onDestroy();

            ImageCache.getInstance(getActivity()).removeCacheListener(this);
        }

        @Override
        public void onDestroyView() {
            super.onDestroyView();

            // if we are destroying our view, cancel our task and null it
            if (mTask != null) {
                mTask.cancel(true);
                mTask = null;
            }
        }

        @Override
        public void onActivityCreated(final Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            mImageView = (SquareImageView)mRootView.findViewById(R.id.audio_player_album_art);
            loadImageAsync();
        }

        /**
         * Loads the image asynchronously
         */
        private void loadImageAsync() {
            // if we have no track id, quit
            if (mAudioId == NO_TRACK_ID) {
                return;
            }

            // try loading from the cache
            AlbumArtistDetails details = getAlbumArtistDetails(mAudioId);
            if (details != null) {
                loadImageAsync(details);
            } else {
                // Cancel any previous tasks
                if (mTask != null) {
                    mTask.cancel(true);
                    mTask = null;
                }

                mTask = new AlbumArtistLoader(this, getActivity());
                ApolloUtils.execute(false, mTask, mAudioId);
            }

        }

        /**
         * Loads the image asynchronously
         * @param details details of the image to load
         */
        private void loadImageAsync(AlbumArtistDetails details) {
            // load the actual image
            ApolloUtils.getImageFetcher(getActivity()).loadAlbumImage(
                    details.mArtistName,
                    details.mAlbumName,
                    details.mAlbumId,
                    mImageView
            );
        }

        @Override
        public void onCacheUnpaused() {
            loadImageAsync();
        }
    }

    /**
     * This looks up the album and artist details for a track
     */
    private static class AlbumArtistLoader extends AsyncTask<Long, Void, AlbumArtistDetails> {
        private Context mContext;
        private AlbumArtFragment mFragment;

        public AlbumArtistLoader(final AlbumArtFragment albumArtFragment, final Context context) {
            mContext = context;
            mFragment = albumArtFragment;
        }

        @Override
        protected AlbumArtistDetails doInBackground(final Long... params) {
            long id = params[0];
            return MusicUtils.getAlbumArtDetails(mContext, id);
        }

        @Override
        protected void onPostExecute(final AlbumArtistDetails result) {
            if (result != null) {
                if (DEBUG) {
                    Log.d(TAG, "[" + mFragment.mAudioId + "] Loading image: "
                            + result.mAlbumId + ","
                            + result.mAlbumName + ","
                            + result.mArtistName);
                }

                AlbumArtPagerAdapter.addAlbumArtistDetails(result);
                mFragment.loadImageAsync(result);
            } else if (DEBUG) {
                Log.d(TAG, "No Image found for audioId: " + mFragment.mAudioId);
            }
        }
    }
}