Move service-related code out of ContextApplication

This commit is contained in:
Christopher Eby 2011-09-18 15:36:13 -05:00
parent ccac623322
commit 34326718ad
10 changed files with 124 additions and 155 deletions

View File

@ -22,23 +22,16 @@
package org.kreed.vanilla;
import java.util.ArrayList;
import java.util.Random;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.provider.MediaStore;
/**
* Subclass of Application that provides various static utility functions
*/
public class ContextApplication extends Application {
private static ContextApplication mInstance;
public static ArrayList<Activity> mActivities;
private static PlaybackService mService;
private static Random mRandom;
public ContextApplication()
@ -46,30 +39,6 @@ public class ContextApplication extends Application {
mInstance = this;
}
@Override
public void onCreate()
{
getContentResolver().registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mObserver);
}
private ContentObserver mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange)
{
Song.onMediaChange();
if (mService != null)
mService.onMediaChange();
ArrayList<Activity> list = mActivities;
if (list != null) {
for (int i = list.size(); --i != -1; ) {
Activity activity = list.get(i);
if (activity instanceof PlaybackActivity)
((PlaybackActivity)activity).onMediaChange();
}
}
}
};
/**
* Returns a shared, application-wide Random instance.
*/
@ -87,88 +56,4 @@ public class ContextApplication extends Application {
{
return mInstance;
}
/**
* Return the PlaybackService instance, creating one if needed.
*/
public static PlaybackService getService()
{
if (mService == null) {
mInstance.startService(new Intent(mInstance, PlaybackService.class));
while (mService == null) {
try {
synchronized (mInstance) {
mInstance.wait();
}
} catch (InterruptedException e) {
}
}
}
return mService;
}
/**
* Returns whether a PlaybackService instance is active.
*/
public static boolean hasService()
{
return mService != null;
}
/**
* Set the PlaybackService instance to <code>service</code> and notify all
* clients waiting for an instance.
*/
public static void setService(PlaybackService service)
{
mService = service;
synchronized (mInstance) {
mInstance.notifyAll();
}
}
/**
* Add an Activity to the list of Activities.
*
* @param activity The Activity to be added
*/
public static void addActivity(Activity activity)
{
if (mActivities == null)
mActivities = new ArrayList<Activity>();
mActivities.add(activity);
}
/**
* Remove an Activity from the list of Activities.
*
* @param activity The Activity to be removed
*/
public static void removeActivity(Activity activity)
{
if (mActivities != null)
mActivities.remove(activity);
}
/**
* Send a broadcast to all PlaybackActivities that have been added with
* addActivity and then with Context.sendBroadcast.
*
* @param intent The intent to be sent as a broadcast
*/
public static void broadcast(Intent intent)
{
ArrayList<Activity> list = mActivities;
if (list != null) {
for (int i = list.size(); --i != -1; ) {
Activity activity = list.get(i);
if (activity instanceof PlaybackActivity)
((PlaybackActivity)activity).receive(intent);
}
}
if (mInstance != null)
mInstance.sendBroadcast(intent);
}
}

View File

@ -347,10 +347,11 @@ public final class CoverView extends View implements Handler.Callback {
/**
* Query all songs. Must be called on the UI thread.
*
* @param service Service to query from.
*/
public void querySongs()
public void querySongs(PlaybackService service)
{
PlaybackService service = ContextApplication.getService();
for (int i = STORE_SIZE; --i != -1; )
setSong(i, service.getSong(i - STORE_SIZE / 2));
resetScroll();

View File

@ -56,8 +56,8 @@ public class FourLongWidget extends AppWidgetProvider {
Song song = null;
int state = 0;
if (ContextApplication.hasService()) {
PlaybackService service = ContextApplication.getService();
if (PlaybackService.hasInstance()) {
PlaybackService service = PlaybackService.get(context);
song = service.getSong(0);
state = service.getState();
}

View File

@ -56,8 +56,8 @@ public class FourSquareWidget extends AppWidgetProvider {
Song song = null;
int state = 0;
if (ContextApplication.hasService()) {
PlaybackService service = ContextApplication.getService();
if (PlaybackService.hasInstance()) {
PlaybackService service = PlaybackService.get(context);
song = service.getSong(0);
state = service.getState();
}

View File

@ -318,7 +318,7 @@ public class FullPlaybackActivity extends PlaybackActivity implements SeekBar.On
*/
private void updateProgress()
{
int position = ContextApplication.hasService() ? ContextApplication.getService().getPosition() : 0;
int position = PlaybackService.hasInstance() ? PlaybackService.get(this).getPosition() : 0;
if (!mSeekBarTracking)
mSeekBar.setProgress(mDuration == 0 ? 0 : (int)(1000 * position / mDuration));
@ -409,7 +409,7 @@ public class FullPlaybackActivity extends PlaybackActivity implements SeekBar.On
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
if (fromUser)
ContextApplication.getService().seekToProgress(progress);
PlaybackService.get(this).seekToProgress(progress);
}
public void onStartTrackingTouch(SeekBar seekBar)

View File

@ -26,6 +26,7 @@ import java.io.File;
import java.util.Random;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
@ -192,20 +193,21 @@ public class MediaUtils {
/**
* Delete all the songs in the given media set.
*
* @param context A context to use.
* @param type One of the TYPE_* constants, excluding playlists.
* @param id The MediaStore id of the media to delete.
* @return The number of songs deleted.
*/
public static int deleteMedia(int type, long id)
public static int deleteMedia(Context context, int type, long id)
{
int count = 0;
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
ContentResolver resolver = context.getContentResolver();
String[] projection = new String [] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA };
Cursor cursor = getMediaCursor(type, id, projection, null);
if (cursor != null) {
PlaybackService service = ContextApplication.hasService() ? ContextApplication.getService() : null;
PlaybackService service = PlaybackService.hasInstance() ? PlaybackService.get(context) : null;
while (cursor.moveToNext()) {
if (new File(cursor.getString(1)).delete()) {

View File

@ -57,8 +57,8 @@ public class OneCellWidget extends AppWidgetProvider {
Song song = null;
int state = 0;
if (ContextApplication.hasService()) {
PlaybackService service = ContextApplication.getService();
if (PlaybackService.hasInstance()) {
PlaybackService service = PlaybackService.get(context);
song = service.getSong(0);
state = service.getState();
}

View File

@ -70,7 +70,8 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
public void onCreate(Bundle state)
{
super.onCreate(state);
ContextApplication.addActivity(this);
PlaybackService.addActivity(this);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
@ -88,9 +89,9 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
@Override
public void onDestroy()
{
super.onDestroy();
ContextApplication.removeActivity(this);
PlaybackService.removeActivity(this);
mLooper.quit();
super.onDestroy();
}
@Override
@ -98,7 +99,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
{
super.onStart();
if (ContextApplication.hasService())
if (PlaybackService.hasInstance())
onServiceReady();
else
startService(new Intent(this, PlaybackService.class));
@ -108,8 +109,8 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
public void onResume()
{
super.onResume();
if (ContextApplication.hasService()) {
PlaybackService service = ContextApplication.getService();
if (PlaybackService.hasInstance()) {
PlaybackService service = PlaybackService.get(this);
service.userActionTriggered();
MediaButtonHandler buttons = MediaButtonHandler.getInstance();
@ -148,17 +149,17 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
public void nextSong()
{
setSong(ContextApplication.getService().nextSong());
setSong(PlaybackService.get(this).nextSong());
}
public void previousSong()
{
setSong(ContextApplication.getService().previousSong());
setSong(PlaybackService.get(this).previousSong());
}
public void playPause()
{
PlaybackService service = ContextApplication.getService();
PlaybackService service = PlaybackService.get(this);
int state = service.playPause();
if ((state & PlaybackService.FLAG_ERROR) != 0)
Toast.makeText(this, service.getErrorMessage(), Toast.LENGTH_LONG).show();
@ -214,7 +215,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
*/
protected void onServiceReady()
{
PlaybackService service = ContextApplication.getService();
PlaybackService service = PlaybackService.get(this);
setSong(service.getSong(0));
setState(service.getState());
}
@ -227,7 +228,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
protected void onSongChange(Song song)
{
if (mCoverView != null)
mCoverView.querySongs();
mCoverView.querySongs(PlaybackService.get(this));
}
protected void setSong(final Song song)
@ -339,7 +340,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
*/
public void toggleShuffle()
{
int state = ContextApplication.getService().toggleShuffle();
int state = PlaybackService.get(this).toggleShuffle();
int res = (state & PlaybackService.FLAG_SHUFFLE) == 0 ? R.string.shuffle_disabling : R.string.shuffle_enabling;
Toast.makeText(this, res, Toast.LENGTH_SHORT).show();
setState(state);
@ -350,7 +351,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
*/
public void toggleRepeat()
{
int state = ContextApplication.getService().toggleRepeat();
int state = PlaybackService.get(this).toggleRepeat();
int res = (state & PlaybackService.FLAG_REPEAT) == 0 ? R.string.repeat_disabling : R.string.repeat_enabling;
Toast.makeText(this, res, Toast.LENGTH_SHORT).show();
setState(state);
@ -361,7 +362,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
*/
public void toggleRandom()
{
int state = ContextApplication.getService().toggleRandom();
int state = PlaybackService.get(this).toggleRandom();
int res = (state & PlaybackService.FLAG_RANDOM) == 0 ? R.string.random_disabling : R.string.random_enabling;
Toast.makeText(this, res, Toast.LENGTH_SHORT).show();
setState(state);
@ -377,7 +378,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
public void enqueue(int type)
{
int count = ContextApplication.getService().enqueueFromCurrent(type);
int count = PlaybackService.get(this).enqueueFromCurrent(type);
String text = getResources().getQuantityString(R.plurals.enqueued, count, count);
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
@ -418,7 +419,7 @@ public class PlaybackActivity extends Activity implements Handler.Callback, View
enqueue(MediaUtils.TYPE_GENRE);
break;
case ACTION_CLEAR_QUEUE:
ContextApplication.getService().clearQueue();
PlaybackService.get(this).clearQueue();
Toast.makeText(this, R.string.queue_cleared, Toast.LENGTH_SHORT).show();
break;
default:

View File

@ -25,7 +25,6 @@ package org.kreed.vanilla;
import java.io.IOException;
import java.util.ArrayList;
import android.app.Activity;
import android.app.NotificationManager;
import android.app.Service;
import android.appwidget.AppWidgetManager;
@ -34,6 +33,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
@ -43,6 +43,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
@ -135,6 +136,10 @@ public final class PlaybackService extends Service implements Handler.Callback,
public static final int WHEN_PLAYING = 1;
public static final int ALWAYS = 2;
private static Object sWait = new Object();
private static PlaybackService sInstance;
private static ArrayList<PlaybackActivity> sActivities = new ArrayList<PlaybackActivity>();
boolean mHeadsetPause;
private boolean mScrobble;
private int mNotificationMode;
@ -227,7 +232,10 @@ public final class PlaybackService extends Service implements Handler.Callback,
updateState(state);
setCurrentSong(0);
ContextApplication.setService(this);
sInstance = this;
synchronized (sWait) {
sWait.notifyAll();
}
}
@Override
@ -272,7 +280,7 @@ public final class PlaybackService extends Service implements Handler.Callback,
@Override
public void onDestroy()
{
ContextApplication.setService(null);
sInstance = null;
mLooper.quit();
@ -340,8 +348,8 @@ public final class PlaybackService extends Service implements Handler.Callback,
} else if ("disable_cover_art".equals(key)) {
Song.mDisableCoverArt = settings.getBoolean("disable_cover_art", false);
} else if ("display_mode".equals(key)) {
ArrayList<Activity> activities = ContextApplication.mActivities;
for (Activity activity : activities) {
ArrayList<PlaybackActivity> activities = sActivities;
for (PlaybackActivity activity : activities) {
if (activity instanceof FullPlaybackActivity)
activity.finish();
}
@ -446,6 +454,13 @@ public final class PlaybackService extends Service implements Handler.Callback,
}
}
private void broadcast(Intent intent)
{
ArrayList<PlaybackActivity> list = sActivities;
for (int i = list.size(); --i != -1; )
list.get(i).receive(intent);
}
private void broadcastChange(int state, Song song, long uptime)
{
Intent intent = new Intent(EVENT_CHANGED);
@ -454,7 +469,7 @@ public final class PlaybackService extends Service implements Handler.Callback,
if (song != null)
intent.putExtra("song", song);
intent.putExtra("time", uptime);
ContextApplication.broadcast(intent);
broadcast(intent);
updateWidgets();
@ -745,6 +760,11 @@ public final class PlaybackService extends Service implements Handler.Callback,
} else {
setFlag(FLAG_NO_MEDIA);
}
ArrayList<PlaybackActivity> list = sActivities;
for (int i = list.size(); --i != -1; )
list.get(i).onMediaChange();
}
public void onSharedPreferenceChanged(SharedPreferences settings, String key)
@ -816,6 +836,8 @@ public final class PlaybackService extends Service implements Handler.Callback,
mCallListener = new InCallListener();
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mCallListener, PhoneStateListener.LISTEN_CALL_STATE);
getContentResolver().registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mObserver);
break;
case IDLE_TIMEOUT:
if ((mState & FLAG_PLAYING) != 0)
@ -839,7 +861,7 @@ public final class PlaybackService extends Service implements Handler.Callback,
processNewState(message.arg1, message.arg2);
break;
case BROADCAST:
ContextApplication.broadcast((Intent)message.obj);
broadcast((Intent)message.obj);
break;
case BROADCAST_CHANGE:
broadcastChange(message.arg1, (Song)message.obj, message.getWhen());
@ -1028,4 +1050,62 @@ public final class PlaybackService extends Service implements Handler.Callback,
mHandler.removeMessages(SAVE_STATE);
mHandler.sendEmptyMessageDelayed(SAVE_STATE, 5000);
}
private ContentObserver mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange)
{
Song.onMediaChange();
onMediaChange();
}
};
/**
* Return the PlaybackService instance, creating one if needed.
*/
public static PlaybackService get(Context context)
{
if (sInstance == null) {
context.startService(new Intent(context, PlaybackService.class));
while (sInstance == null) {
try {
synchronized (sWait) {
sWait.wait();
}
} catch (InterruptedException e) {
}
}
}
return sInstance;
}
/**
* Returns true if a PlaybackService instance is active.
*/
public static boolean hasInstance()
{
return sInstance != null;
}
/**
* Add an Activity to the registered PlaybackActivities.
*
* @param activity The Activity to be added
*/
public static void addActivity(PlaybackActivity activity)
{
sActivities.add(activity);
}
/**
* Remove an Activity from the registered PlaybackActivities
*
* @param activity The Activity to be removed
*/
public static void removeActivity(PlaybackActivity activity)
{
sActivities.remove(activity);
}
}

View File

@ -167,8 +167,8 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
if (mSearchBoxVisible)
mControls.setVisibility(View.GONE);
if (ContextApplication.hasService()) {
PlaybackService service = ContextApplication.getService();
if (PlaybackService.hasInstance()) {
PlaybackService service = PlaybackService.get(this);
// Force the state to be updated, even if PlaybackActivity has
// already loaded it. This is needed to set the proper image
// for the play/pause button.
@ -243,7 +243,7 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
*/
private void pickSongs(MediaAdapter.MediaView view, int action)
{
PlaybackService service = ContextApplication.getService();
PlaybackService service = PlaybackService.get(this);
int type = view.getMediaType();
long id = view.getMediaId();
int mode;
@ -493,7 +493,7 @@ public class SongSelector extends PlaybackActivity implements AdapterView.OnItem
String message = getResources().getString(R.string.playlist_deleted, title);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
} else {
int count = MediaUtils.deleteMedia(type, id);
int count = MediaUtils.deleteMedia(this, type, id);
String message = getResources().getQuantityString(R.plurals.deleted, count, count);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}