You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
8.2 KiB
205 lines
8.2 KiB
/*
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.music;
|
|
|
|
import android.app.PendingIntent;
|
|
import android.appwidget.AppWidgetManager;
|
|
import android.appwidget.AppWidgetProvider;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.res.Resources;
|
|
import android.os.Environment;
|
|
import android.view.View;
|
|
import android.widget.RemoteViews;
|
|
|
|
/**
|
|
* Simple widget to show currently playing album art along
|
|
* with play/pause and next track buttons.
|
|
*/
|
|
public class MediaAppWidgetProvider extends AppWidgetProvider {
|
|
static final String TAG = "MusicAppWidgetProvider";
|
|
|
|
public static final String CMDAPPWIDGETUPDATE = "appwidgetupdate";
|
|
|
|
private static MediaAppWidgetProvider sInstance;
|
|
|
|
static synchronized MediaAppWidgetProvider getInstance() {
|
|
if (sInstance == null) {
|
|
sInstance = new MediaAppWidgetProvider();
|
|
}
|
|
return sInstance;
|
|
}
|
|
|
|
@Override
|
|
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
defaultAppWidget(context, appWidgetIds);
|
|
|
|
// Send broadcast intent to any running MediaPlaybackService so it can
|
|
// wrap around with an immediate update.
|
|
Intent updateIntent = new Intent(MediaPlaybackService.SERVICECMD);
|
|
updateIntent.putExtra(
|
|
MediaPlaybackService.CMDNAME, MediaAppWidgetProvider.CMDAPPWIDGETUPDATE);
|
|
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
|
updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
|
context.sendBroadcast(updateIntent);
|
|
}
|
|
|
|
/**
|
|
* Initialize given widgets to default state, where we launch Music on default click
|
|
* and hide actions if service not running.
|
|
*/
|
|
private void defaultAppWidget(Context context, int[] appWidgetIds) {
|
|
final Resources res = context.getResources();
|
|
final RemoteViews views =
|
|
new RemoteViews(context.getPackageName(), R.layout.album_appwidget);
|
|
|
|
views.setViewVisibility(R.id.title, View.GONE);
|
|
views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text));
|
|
|
|
linkButtons(context, views, false /* not playing */);
|
|
pushUpdate(context, appWidgetIds, views);
|
|
}
|
|
|
|
private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) {
|
|
// Update specific list of appWidgetIds if given, otherwise default to all
|
|
final AppWidgetManager gm = AppWidgetManager.getInstance(context);
|
|
if (appWidgetIds != null) {
|
|
gm.updateAppWidget(appWidgetIds, views);
|
|
} else {
|
|
gm.updateAppWidget(new ComponentName(context, this.getClass()), views);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check against {@link AppWidgetManager} if there are any instances of this widget.
|
|
*/
|
|
private boolean hasInstances(Context context) {
|
|
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
|
int[] appWidgetIds =
|
|
appWidgetManager.getAppWidgetIds(new ComponentName(context, this.getClass()));
|
|
return (appWidgetIds.length > 0);
|
|
}
|
|
|
|
/**
|
|
* Handle a change notification coming over from {@link MediaPlaybackService}
|
|
*/
|
|
void notifyChange(MediaPlaybackService service, String what) {
|
|
if (hasInstances(service)) {
|
|
if (MediaPlaybackService.META_CHANGED.equals(what)
|
|
|| MediaPlaybackService.PLAYSTATE_CHANGED.equals(what)) {
|
|
performUpdate(service, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update all active widget instances by pushing changes
|
|
*/
|
|
void performUpdate(MediaPlaybackService service, int[] appWidgetIds) {
|
|
final Resources res = service.getResources();
|
|
final RemoteViews views =
|
|
new RemoteViews(service.getPackageName(), R.layout.album_appwidget);
|
|
|
|
CharSequence titleName = service.getTrackName();
|
|
CharSequence artistName = service.getArtistName();
|
|
CharSequence errorState = null;
|
|
|
|
// Format title string with track number, or show SD card message
|
|
String status = Environment.getExternalStorageState();
|
|
if (status.equals(Environment.MEDIA_SHARED) || status.equals(Environment.MEDIA_UNMOUNTED)) {
|
|
if (android.os.Environment.isExternalStorageRemovable()) {
|
|
errorState = res.getText(R.string.sdcard_busy_title);
|
|
} else {
|
|
errorState = res.getText(R.string.sdcard_busy_title_nosdcard);
|
|
}
|
|
} else if (status.equals(Environment.MEDIA_REMOVED)) {
|
|
if (android.os.Environment.isExternalStorageRemovable()) {
|
|
errorState = res.getText(R.string.sdcard_missing_title);
|
|
} else {
|
|
errorState = res.getText(R.string.sdcard_missing_title_nosdcard);
|
|
}
|
|
} else if (titleName == null) {
|
|
errorState = res.getText(R.string.emptyplaylist);
|
|
}
|
|
|
|
if (errorState != null) {
|
|
// Show error state to user
|
|
views.setViewVisibility(R.id.title, View.GONE);
|
|
views.setTextViewText(R.id.artist, errorState);
|
|
|
|
} else {
|
|
// No error, so show normal titles
|
|
views.setViewVisibility(R.id.title, View.VISIBLE);
|
|
views.setTextViewText(R.id.title, titleName);
|
|
views.setTextViewText(R.id.artist, artistName);
|
|
}
|
|
|
|
// Set correct drawable for pause state
|
|
final boolean playing = service.isPlaying();
|
|
if (playing) {
|
|
views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_pause);
|
|
} else {
|
|
views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_play);
|
|
}
|
|
|
|
// Link actions buttons to intents
|
|
linkButtons(service, views, playing);
|
|
|
|
pushUpdate(service, appWidgetIds, views);
|
|
}
|
|
|
|
/**
|
|
* Link up various button actions using {@link PendingIntents}.
|
|
*
|
|
* @param playerActive True if player is active in background, which means
|
|
* widget click will launch {@link MediaPlaybackActivity},
|
|
* otherwise we launch {@link MusicBrowserActivity}.
|
|
*/
|
|
private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
|
|
// Connect up various buttons and touch events
|
|
Intent intent;
|
|
PendingIntent pendingIntent;
|
|
|
|
final ComponentName serviceName = new ComponentName(context, MediaPlaybackService.class);
|
|
|
|
if (playerActive) {
|
|
intent = new Intent(context, MediaPlaybackActivity.class);
|
|
pendingIntent = PendingIntent.getActivity(
|
|
context, 0 /* no requestCode */, intent, 0 /* no flags */);
|
|
views.setOnClickPendingIntent(R.id.album_appwidget, pendingIntent);
|
|
} else {
|
|
intent = new Intent(context, MusicBrowserActivity.class);
|
|
pendingIntent = PendingIntent.getActivity(
|
|
context, 0 /* no requestCode */, intent, 0 /* no flags */);
|
|
views.setOnClickPendingIntent(R.id.album_appwidget, pendingIntent);
|
|
}
|
|
|
|
intent = new Intent(MediaPlaybackService.TOGGLEPAUSE_ACTION);
|
|
intent.setComponent(serviceName);
|
|
pendingIntent =
|
|
PendingIntent.getService(context, 0 /* no requestCode */, intent, 0 /* no flags */);
|
|
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
|
|
|
|
intent = new Intent(MediaPlaybackService.NEXT_ACTION);
|
|
intent.setComponent(serviceName);
|
|
pendingIntent =
|
|
PendingIntent.getService(context, 0 /* no requestCode */, intent, 0 /* no flags */);
|
|
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
|
|
}
|
|
}
|