OSDN Git Service

4aca56944384fede5eb82ed0f0042b240ba86b99
[android-x86/packages-apps-Eleven.git] / src / com / cyanogenmod / eleven / ui / activities / BaseActivity.java
1 /*
2  * Copyright (C) 2012 Andrew Neal
3  * Copyright (C) 2014 The CyanogenMod Project
4  * Licensed under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with the
6  * License. You may obtain a copy of the License at
7  * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
8  * or agreed to in writing, software distributed under the License is
9  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
10  * KIND, either express or implied. See the License for the specific language
11  * governing permissions and limitations under the License.
12  */
13
14 package com.cyanogenmod.eleven.ui.activities;
15
16 import static com.cyanogenmod.eleven.utils.MusicUtils.mService;
17
18 import android.app.ActionBar;
19 import android.content.BroadcastReceiver;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.ServiceConnection;
25 import android.graphics.drawable.ColorDrawable;
26 import android.graphics.drawable.Drawable;
27 import android.media.AudioManager;
28 import android.os.Bundle;
29 import android.os.IBinder;
30 import android.support.v4.app.FragmentActivity;
31 import android.util.TypedValue;
32 import android.view.Menu;
33 import android.view.MenuItem;
34 import android.view.View;
35 import android.widget.ImageView;
36 import android.widget.TextView;
37 import android.widget.Toast;
38 import android.widget.Toolbar;
39
40 import com.cyanogenmod.eleven.IElevenService;
41 import com.cyanogenmod.eleven.MusicPlaybackService;
42 import com.cyanogenmod.eleven.MusicStateListener;
43 import com.cyanogenmod.eleven.R;
44 import com.cyanogenmod.eleven.cache.ICacheListener;
45 import com.cyanogenmod.eleven.cache.ImageFetcher;
46 import com.cyanogenmod.eleven.utils.ApolloUtils;
47 import com.cyanogenmod.eleven.utils.Lists;
48 import com.cyanogenmod.eleven.utils.MusicUtils;
49 import com.cyanogenmod.eleven.utils.MusicUtils.ServiceToken;
50 import com.cyanogenmod.eleven.utils.NavUtils;
51 import com.cyanogenmod.eleven.widgets.PlayPauseProgressButton;
52
53 import java.lang.ref.WeakReference;
54 import java.util.ArrayList;
55
56 /**
57  * A base {@link FragmentActivity} used to update the bottom bar and
58  * bind to Apollo's service.
59  * <p>
60  * {@link SlidingPanelActivity} extends from this skeleton.
61  *
62  * @author Andrew Neal (andrewdneal@gmail.com)
63  */
64 public abstract class BaseActivity extends FragmentActivity implements ServiceConnection,
65         MusicStateListener, ICacheListener {
66
67     /**
68      * Playstate and meta change listener
69      */
70     private final ArrayList<MusicStateListener> mMusicStateListener = Lists.newArrayList();
71
72     private Toolbar mToolBar;
73
74     private int mActionBarHeight;
75
76     /**
77      * The service token
78      */
79     private ServiceToken mToken;
80
81     /**
82      * Play pause progress button
83      */
84     private PlayPauseProgressButton mPlayPauseProgressButton;
85
86     /**
87      * Track name (BAB)
88      */
89     private TextView mTrackName;
90
91     /**
92      * Artist name (BAB)
93      */
94     private TextView mArtistName;
95
96     /**
97      * Album art (BAB)
98      */
99     private ImageView mAlbumArt;
100
101     /**
102      * Broadcast receiver
103      */
104     private PlaybackStatus mPlaybackStatus;
105
106     private Drawable mActionBarBackground;
107
108     /**
109      * {@inheritDoc}
110      */
111     @Override
112     protected void onCreate(final Bundle savedInstanceState) {
113         super.onCreate(savedInstanceState);
114
115         // Fade it in
116         overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
117
118         // Control the media volume
119         setVolumeControlStream(AudioManager.STREAM_MUSIC);
120
121         // Bind Apollo's service
122         mToken = MusicUtils.bindToService(this, this);
123
124         // Initialize the broadcast receiver
125         mPlaybackStatus = new PlaybackStatus(this);
126
127         // Calculate ActionBar height
128         TypedValue value = new TypedValue();
129         if (getTheme().resolveAttribute(android.R.attr.actionBarSize, value, true))
130         {
131             mActionBarHeight = TypedValue.complexToDimensionPixelSize(value.data,
132                     getResources().getDisplayMetrics());
133         }
134
135         // Set the layout
136         setContentView(setContentView());
137
138         mToolBar = (Toolbar) findViewById(R.id.toolbar);
139         setActionBar(mToolBar);
140
141         setActionBarTitle(getString(R.string.app_name));
142
143         // set the background on the root view
144         getWindow().getDecorView().getRootView().setBackgroundColor(
145                 getResources().getColor(R.color.background_color));
146         // Initialze the bottom action bar
147         initBottomActionBar();
148
149         // listen to changes to the cache status
150         ImageFetcher.getInstance(this).addCacheListener(this);
151     }
152
153     /**
154      * {@inheritDoc}
155      */
156     @Override
157     public void onServiceConnected(final ComponentName name, final IBinder service) {
158         mService = IElevenService.Stub.asInterface(service);
159         // Set the playback drawables
160         updatePlaybackControls();
161         // Current info
162         onMetaChanged();
163         // if there were any pending intents while the service was started
164         handlePendingPlaybackRequests();
165     }
166
167     /**
168      * {@inheritDoc}
169      */
170     @Override
171     public void onServiceDisconnected(final ComponentName name) {
172         mService = null;
173     }
174
175     /**
176      * {@inheritDoc}
177      */
178     @Override
179     public boolean onCreateOptionsMenu(final Menu menu) {
180         // Search view
181         getMenuInflater().inflate(R.menu.search_btn, menu);
182         // Settings
183         getMenuInflater().inflate(R.menu.activity_base, menu);
184
185         return super.onCreateOptionsMenu(menu);
186     }
187
188     /**
189      * {@inheritDoc}
190      */
191     @Override
192     public boolean onOptionsItemSelected(final MenuItem item) {
193         switch (item.getItemId()) {
194             case R.id.menu_settings:
195                 // Settings
196                 NavUtils.openSettings(this);
197                 return true;
198
199             case R.id.menu_search:
200                 NavUtils.openSearch(BaseActivity.this, "");
201                 return true;
202
203             default:
204                 break;
205         }
206         return super.onOptionsItemSelected(item);
207     }
208
209     /**
210      * {@inheritDoc}
211      */
212     @Override
213     protected void onResume() {
214         super.onResume();
215         // Set the playback drawables
216         updatePlaybackControls();
217         // Current info
218         onMetaChanged();
219     }
220
221     /**
222      * {@inheritDoc}
223      */
224     @Override
225     protected void onStart() {
226         super.onStart();
227         final IntentFilter filter = new IntentFilter();
228         // Play and pause changes
229         filter.addAction(MusicPlaybackService.PLAYSTATE_CHANGED);
230         // Track changes
231         filter.addAction(MusicPlaybackService.META_CHANGED);
232         // Update a list, probably the playlist fragment's
233         filter.addAction(MusicPlaybackService.REFRESH);
234         // If a playlist has changed, notify us
235         filter.addAction(MusicPlaybackService.PLAYLIST_CHANGED);
236         // If there is an error playing a track
237         filter.addAction(MusicPlaybackService.TRACK_ERROR);
238         registerReceiver(mPlaybackStatus, filter);
239
240         mPlayPauseProgressButton.resume();
241     }
242
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     protected void onStop() {
248         super.onStop();
249
250         mPlayPauseProgressButton.pause();
251     }
252
253     /**
254      * {@inheritDoc}
255      */
256     @Override
257     protected void onDestroy() {
258         super.onDestroy();
259         // Unbind from the service
260         if (mToken != null) {
261             MusicUtils.unbindFromService(mToken);
262             mToken = null;
263         }
264
265         // Unregister the receiver
266         try {
267             unregisterReceiver(mPlaybackStatus);
268         } catch (final Throwable e) {
269             //$FALL-THROUGH$
270         }
271
272         // Remove any music status listeners
273         mMusicStateListener.clear();
274
275         // remove cache listeners
276         ImageFetcher.getInstance(this).removeCacheListener(this);
277     }
278
279     public void setupActionBar(int resId) {
280         setupActionBar(getString(resId));
281     }
282
283     public void setupActionBar(String title) {
284         setActionBarTitle(title);
285
286         if (mActionBarBackground == null) {
287             final int actionBarColor = getResources().getColor(R.color.header_action_bar_color);
288             mActionBarBackground = new ColorDrawable(actionBarColor);
289             mToolBar.setBackgroundDrawable(mActionBarBackground);
290         }
291     }
292
293     public void setActionBarTitle(String title) {
294         ActionBar actionBar = getActionBar();
295         actionBar.setTitle(title);
296     }
297
298     public void setActionBarAlpha(int alpha) {
299         mActionBarBackground.setAlpha(alpha);
300     }
301
302     public void setActionBarElevation(boolean isElevated) {
303         float targetElevation = isElevated
304                 ? getResources().getDimension(R.dimen.action_bar_elevation) : 0;
305         mToolBar.setElevation(targetElevation);
306     }
307
308     public void setFragmentPadding(boolean enablePadding) {
309         final int height = enablePadding ? mActionBarHeight : 0;
310         findViewById(R.id.activity_base_content).setPadding(0, height, 0, 0);
311     }
312
313     /**
314      * Initializes the items in the bottom action bar.
315      */
316     protected void initBottomActionBar() {
317         // Play and pause button
318         mPlayPauseProgressButton = (PlayPauseProgressButton)findViewById(R.id.playPauseProgressButton);
319         mPlayPauseProgressButton.enableAndShow();
320
321         // Track name
322         mTrackName = (TextView)findViewById(R.id.bottom_action_bar_line_one);
323         // Artist name
324         mArtistName = (TextView)findViewById(R.id.bottom_action_bar_line_two);
325         // Album art
326         mAlbumArt = (ImageView)findViewById(R.id.bottom_action_bar_album_art);
327         // Open to the currently playing album profile
328         mAlbumArt.setOnClickListener(mOpenCurrentAlbumProfile);
329     }
330
331     protected void clearMetaInfo() {
332         mAlbumArt.setImageResource(R.drawable.default_artwork);
333     }
334
335     /**
336      * Sets the track name, album name, and album art.
337      */
338     private void updateBottomActionBarInfo() {
339         // Set the track name
340         mTrackName.setText(MusicUtils.getTrackName());
341         // Set the artist name
342         mArtistName.setText(MusicUtils.getArtistName());
343         // Set the album art
344         ApolloUtils.getImageFetcher(this).loadCurrentArtwork(mAlbumArt);
345     }
346
347     /**
348      * Sets the correct drawable states for the playback controls.
349      */
350     private void updatePlaybackControls() {
351         // Set the play and pause image
352         mPlayPauseProgressButton.getPlayPauseButton().updateState();
353     }
354
355     /**
356      * Opens the album profile of the currently playing album
357      */
358     private final View.OnClickListener mOpenCurrentAlbumProfile = new View.OnClickListener() {
359
360         /**
361          * {@inheritDoc}
362          */
363         @Override
364         public void onClick(final View v) {
365             if (MusicUtils.getCurrentAudioId() != -1) {
366                 NavUtils.openAlbumProfile(BaseActivity.this, MusicUtils.getAlbumName(),
367                         MusicUtils.getArtistName(), MusicUtils.getCurrentAlbumId());
368             } else {
369                 MusicUtils.shuffleAll(BaseActivity.this);
370             }
371         }
372     };
373
374     /**
375      * Used to monitor the state of playback
376      */
377     private final static class PlaybackStatus extends BroadcastReceiver {
378
379         private final WeakReference<BaseActivity> mReference;
380
381         /**
382          * Constructor of <code>PlaybackStatus</code>
383          */
384         public PlaybackStatus(final BaseActivity activity) {
385             mReference = new WeakReference<BaseActivity>(activity);
386         }
387
388         /**
389          * {@inheritDoc}
390          */
391         @Override
392         public void onReceive(final Context context, final Intent intent) {
393             final String action = intent.getAction();
394             BaseActivity baseActivity = mReference.get();
395             if (baseActivity != null) {
396                 if (action.equals(MusicPlaybackService.META_CHANGED)) {
397                     baseActivity.onMetaChanged();
398                 } else if (action.equals(MusicPlaybackService.PLAYSTATE_CHANGED)) {
399                     // Set the play and pause image
400                     baseActivity.mPlayPauseProgressButton.getPlayPauseButton().updateState();
401                 } else if (action.equals(MusicPlaybackService.REFRESH)) {
402                     baseActivity.restartLoader();
403                 } else if (action.equals(MusicPlaybackService.PLAYLIST_CHANGED)) {
404                     baseActivity.onPlaylistChanged();
405                 } else if (action.equals(MusicPlaybackService.TRACK_ERROR)) {
406                     final String errorMsg = context.getString(R.string.error_playing_track,
407                             intent.getStringExtra(MusicPlaybackService.TrackErrorExtra.TRACK_NAME));
408                     Toast.makeText(baseActivity, errorMsg, Toast.LENGTH_SHORT).show();
409                 }
410             }
411         }
412     }
413
414     @Override
415     public void onMetaChanged() {
416         // update action bar info
417         updateBottomActionBarInfo();
418
419         // Let the listener know to the meta chnaged
420         for (final MusicStateListener listener : mMusicStateListener) {
421             if (listener != null) {
422                 listener.onMetaChanged();
423             }
424         }
425     }
426
427     @Override
428     public void restartLoader() {
429         // Let the listener know to update a list
430         for (final MusicStateListener listener : mMusicStateListener) {
431             if (listener != null) {
432                 listener.restartLoader();
433             }
434         }
435     }
436
437     @Override
438     public void onPlaylistChanged() {
439         // Let the listener know to update a list
440         for (final MusicStateListener listener : mMusicStateListener) {
441             if (listener != null) {
442                 listener.onPlaylistChanged();
443             }
444         }
445     }
446
447     /**
448      * @param status The {@link MusicStateListener} to use
449      */
450     public void setMusicStateListenerListener(final MusicStateListener status) {
451         if (status == this) {
452             throw new UnsupportedOperationException("Override the method, don't add a listener");
453         }
454
455         if (status != null) {
456             mMusicStateListener.add(status);
457         }
458     }
459
460     /**
461      * @param status The {@link MusicStateListener} to use
462      */
463     public void removeMusicStateListenerListener(final MusicStateListener status) {
464         if (status != null) {
465             mMusicStateListener.remove(status);
466         }
467     }
468
469     @Override
470     public void onCacheUnpaused() {
471         // Set the album art
472         ApolloUtils.getImageFetcher(this).loadCurrentArtwork(mAlbumArt);
473     }
474
475     /**
476      * @return The resource ID to be inflated.
477      */
478     public abstract int setContentView();
479
480     /**
481      * handle pending playback requests
482      */
483     public abstract void handlePendingPlaybackRequests();
484 }