2 * Copyright (C) 2009 The Android Open Source Project
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.android.music;
\r
19 import android.app.PendingIntent;
\r
20 import android.appwidget.AppWidgetManager;
\r
21 import android.appwidget.AppWidgetProvider;
\r
22 import android.content.ComponentName;
\r
23 import android.content.Context;
\r
24 import android.content.Intent;
\r
25 import android.content.SharedPreferences;
\r
26 import android.content.pm.PackageManager;
\r
27 import android.content.pm.PackageManager.NameNotFoundException;
\r
28 import android.content.res.Resources;
\r
29 import android.graphics.Color;
\r
30 import android.net.Uri;
\r
31 import android.os.Environment;
\r
32 import android.preference.PreferenceManager;
\r
33 import android.view.View;
\r
34 import android.widget.RemoteViews;
\r
37 * Simple widget to show currently playing album art along with play/pause and
\r
38 * next track buttons.
\r
40 public class MediaAppWidgetProvider4x2 extends AppWidgetProvider {
\r
41 static final String TAG = "MusicAppWidgetProvider4x2";
\r
43 public static final String CMDAPPWIDGETUPDATE = "appwidgetupdate4x2";
\r
45 // ADW Theme constants
\r
46 public static final int THEME_ITEM_BACKGROUND = 0;
\r
47 public static final int THEME_ITEM_FOREGROUND = 1;
\r
48 private static MediaAppWidgetProvider4x2 sInstance;
\r
50 static synchronized MediaAppWidgetProvider4x2 getInstance() {
\r
51 if (sInstance == null) {
\r
52 sInstance = new MediaAppWidgetProvider4x2();
\r
58 public void onUpdate(Context context, AppWidgetManager appWidgetManager,
\r
59 int[] appWidgetIds) {
\r
60 defaultAppWidget(context, appWidgetIds);
\r
62 // Send broadcast intent to any running MediaPlaybackService so it can
\r
63 // wrap around with an immediate update.
\r
64 Intent updateIntent = new Intent(MediaPlaybackService.SERVICECMD);
\r
65 updateIntent.putExtra(MediaPlaybackService.CMDNAME,
\r
66 MediaAppWidgetProvider4x2.CMDAPPWIDGETUPDATE);
\r
67 updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
\r
69 updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
\r
70 context.sendBroadcast(updateIntent);
\r
74 * Initialize given widgets to default state, where we launch Music on
\r
75 * default click and hide actions if service not running.
\r
77 private void defaultAppWidget(Context context, int[] appWidgetIds) {
\r
78 final Resources res = context.getResources();
\r
79 final RemoteViews views = new RemoteViews(context.getPackageName(),
\r
80 R.layout.album_appwidget4x2);
\r
82 views.setViewVisibility(R.id.albumname, View.GONE);
\r
83 views.setViewVisibility(R.id.trackname, View.GONE);
\r
84 views.setTextViewText(R.id.artistname,
\r
85 res.getText(R.string.widget_initial_text));
\r
86 views.setImageViewResource(R.id.albumart,
\r
87 R.drawable.albumart_mp_unknown);
\r
89 linkButtons(context, views, false /* not playing */);
\r
90 pushUpdate(context, appWidgetIds, views);
\r
93 private void pushUpdate(Context context, int[] appWidgetIds,
\r
94 RemoteViews views) {
\r
95 // Update specific list of appWidgetIds if given, otherwise default to
\r
97 final AppWidgetManager gm = AppWidgetManager.getInstance(context);
\r
98 if (appWidgetIds != null) {
\r
99 gm.updateAppWidget(appWidgetIds, views);
\r
101 gm.updateAppWidget(new ComponentName(context, this.getClass()),
\r
107 * Check against {@link AppWidgetManager} if there are any instances of this
\r
110 private boolean hasInstances(Context context) {
\r
111 AppWidgetManager appWidgetManager = AppWidgetManager
\r
112 .getInstance(context);
\r
113 int[] appWidgetIds = appWidgetManager
\r
114 .getAppWidgetIds(new ComponentName(context, this.getClass()));
\r
115 return (appWidgetIds.length > 0);
\r
119 * Handle a change notification coming over from
\r
120 * {@link MediaPlaybackService}
\r
122 void notifyChange(MediaPlaybackService service, String what) {
\r
123 if (hasInstances(service)) {
\r
124 if (MediaPlaybackService.META_CHANGED.equals(what)
\r
125 || MediaPlaybackService.PROGRESSBAR_CHANGED.equals(what)
\r
126 || MediaPlaybackService.PLAYSTATE_CHANGED.equals(what)
\r
127 || MediaPlaybackService.REPEATMODE_CHANGED.equals(what)
\r
128 || MediaPlaybackService.SHUFFLEMODE_CHANGED.equals(what)) {
\r
129 performUpdate(service, null);
\r
135 * Update all active widget instances by pushing changes
\r
137 void performUpdate(MediaPlaybackService service, int[] appWidgetIds) {
\r
138 final Resources res = service.getResources();
\r
139 final RemoteViews views = new RemoteViews(service.getPackageName(),
\r
140 R.layout.album_appwidget4x2);
\r
142 CharSequence artistName = service.getArtistName();
\r
143 CharSequence albumName = service.getAlbumName();
\r
144 CharSequence trackName = service.getTrackName();
\r
145 long albumId = service.getAlbumId();
\r
146 long songId = service.getAudioId();
\r
147 long pos = service.position();
\r
148 long dur = service.duration();
\r
149 CharSequence errorState = null;
\r
151 // Format title string with track number, or show SD card message
\r
152 String status = Environment.getExternalStorageState();
\r
153 if (status.equals(Environment.MEDIA_SHARED)
\r
154 || status.equals(Environment.MEDIA_UNMOUNTED)) {
\r
155 if (android.os.Environment.isExternalStorageRemovable()) {
\r
156 errorState = res.getText(R.string.sdcard_busy_title);
\r
158 errorState = res.getText(R.string.sdcard_busy_title_nosdcard);
\r
160 } else if (status.equals(Environment.MEDIA_REMOVED)) {
\r
161 if (android.os.Environment.isExternalStorageRemovable()) {
\r
162 errorState = res.getText(R.string.sdcard_missing_title);
\r
165 .getText(R.string.sdcard_missing_title_nosdcard);
\r
167 } else if (trackName == null) {
\r
168 errorState = res.getText(R.string.emptyplaylist);
\r
170 SharedPreferences mPrefs = PreferenceManager
\r
171 .getDefaultSharedPreferences(service);
\r
172 int aColor = new Integer(mPrefs.getInt(null,
\r
173 MusicSettingsActivity.DEFAULT_SCREENSAVER_COLOR_ALPHA));
\r
174 int rColor = new Integer(mPrefs.getInt(null,
\r
175 MusicSettingsActivity.DEFAULT_SCREENSAVER_COLOR_RED));
\r
176 int gColor = new Integer(mPrefs.getInt(null,
\r
177 MusicSettingsActivity.DEFAULT_SCREENSAVER_COLOR_GREEN));
\r
178 int bColor = new Integer(mPrefs.getInt(null,
\r
179 MusicSettingsActivity.DEFAULT_SCREENSAVER_COLOR_BLUE));
\r
180 int SCREEN_SAVER_COLOR_DIM = Color.argb(aColor, rColor, gColor, bColor);
\r
182 if (errorState != null) {
\r
183 // Show error state to user
\r
184 views.setViewVisibility(R.id.albumname, View.GONE);
\r
185 views.setViewVisibility(R.id.trackname, View.GONE);
\r
186 views.setTextViewText(R.id.artistname, errorState);
\r
187 views.setImageViewResource(R.id.albumart,
\r
188 R.drawable.albumart_mp_unknown);
\r
190 // No error, so show normal titles and artwork
\r
191 views.setViewVisibility(R.id.albumname, View.VISIBLE);
\r
192 views.setViewVisibility(R.id.trackname, View.VISIBLE);
\r
193 views.setTextViewText(R.id.artistname, " " + artistName);
\r
194 views.setTextViewText(R.id.albumname, " " + albumName);
\r
195 views.setTextViewText(R.id.trackname, " " + trackName);
\r
196 views.setTextColor(R.id.artistname, SCREEN_SAVER_COLOR_DIM);
\r
197 views.setTextColor(R.id.albumname, SCREEN_SAVER_COLOR_DIM);
\r
198 views.setTextColor(R.id.trackname, SCREEN_SAVER_COLOR_DIM);
\r
199 views.setProgressBar(R.id.progress, 1000, (int) (1000 * pos / dur),
\r
203 Uri uri = MusicUtils.getArtworkUri(service, songId, albumId);
\r
205 views.setImageViewUri(R.id.albumart, uri);
\r
207 views.setImageViewResource(R.id.albumart,
\r
208 R.drawable.albumart_mp_unknown);
\r
212 // Set correct drawable for pause state
\r
213 final boolean playing = service.isPlaying();
\r
215 views.setImageViewResource(R.id.control_play,
\r
216 R.drawable.ic_media_pause);
\r
218 views.setImageViewResource(R.id.control_play,
\r
219 R.drawable.ic_appwidget_music_play);
\r
222 // Set correct drawable for repeat state
\r
223 switch (service.getRepeatMode()) {
\r
224 case MediaPlaybackService.REPEAT_ALL:
\r
225 views.setImageViewResource(R.id.control_repeat,
\r
226 R.drawable.ic_mp_repeat_all_btn);
\r
228 case MediaPlaybackService.REPEAT_CURRENT:
\r
229 views.setImageViewResource(R.id.control_repeat,
\r
230 R.drawable.ic_mp_repeat_once_btn);
\r
233 views.setImageViewResource(R.id.control_repeat,
\r
234 R.drawable.ic_mp_repeat_off_btn);
\r
238 // Set correct drawable for shuffle state
\r
239 switch (service.getShuffleMode()) {
\r
240 case MediaPlaybackService.SHUFFLE_NONE:
\r
241 views.setImageViewResource(R.id.control_shuffle,
\r
242 R.drawable.ic_mp_shuffle_off_btn);
\r
244 case MediaPlaybackService.SHUFFLE_AUTO:
\r
245 views.setImageViewResource(R.id.control_shuffle,
\r
246 R.drawable.ic_mp_partyshuffle_on_btn);
\r
249 views.setImageViewResource(R.id.control_shuffle,
\r
250 R.drawable.ic_mp_shuffle_on_btn);
\r
253 // Link actions buttons to intents
\r
254 linkButtons(service, views, playing);
\r
256 pushUpdate(service, appWidgetIds, views);
\r
261 * Link up various button actions using {@link PendingIntents}.
\r
263 * @param playerActive
\r
264 * True if player is active in background, which means widget
\r
265 * click will launch {@link MediaPlaybackActivity}, otherwise we
\r
266 * launch {@link MusicBrowserActivity}.
\r
268 private void linkButtons(Context context, RemoteViews views,
\r
269 boolean playerActive) {
\r
271 // ADW: Load the specified theme
\r
272 String themePackage = MusicUtils.getThemePackageName(context,
\r
273 MusicSettingsActivity.THEME_DEFAULT);
\r
274 PackageManager pm = context.getPackageManager();
\r
275 Resources themeResources = null;
\r
276 if (!themePackage.equals(MusicSettingsActivity.THEME_DEFAULT)) {
\r
278 themeResources = pm.getResourcesForApplication(themePackage);
\r
279 } catch (NameNotFoundException e) {
\r
280 // ADW The saved theme was uninstalled so we save the
\r
282 MusicUtils.setThemePackageName(context,
\r
283 MusicSettingsActivity.THEME_DEFAULT);
\r
285 int albumName = themeResources.getIdentifier(
\r
286 "four_by_two_album_name", "color", themePackage);
\r
287 if (albumName != 0) {
\r
288 views.setTextColor(R.id.albumname,
\r
289 themeResources.getColor(albumName));
\r
291 int trackName = themeResources.getIdentifier(
\r
292 "four_by_two_track_name", "color", themePackage);
\r
293 if (trackName != 0) {
\r
294 views.setTextColor(R.id.trackname,
\r
295 themeResources.getColor(trackName));
\r
297 int artistName = themeResources.getIdentifier(
\r
298 "four_by_two_artist_name", "color", themePackage);
\r
299 if (artistName != 0) {
\r
300 views.setTextColor(R.id.artistname,
\r
301 themeResources.getColor(artistName));
\r
305 // Connect up various buttons and touch events
\r
307 PendingIntent pendingIntent;
\r
309 final ComponentName serviceName = new ComponentName(context,
\r
310 MediaPlaybackService.class);
\r
312 if (playerActive) {
\r
313 intent = new Intent(context, MediaPlaybackActivity.class);
\r
314 pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
\r
315 views.setOnClickPendingIntent(R.id.albumart, pendingIntent);
\r
316 views.setOnClickPendingIntent(R.id.info, pendingIntent);
\r
318 intent = new Intent(context, MusicBrowserActivity.class);
\r
319 pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
\r
320 views.setOnClickPendingIntent(R.id.albumart, pendingIntent);
\r
321 views.setOnClickPendingIntent(R.id.info, pendingIntent);
\r
324 intent = new Intent(MediaPlaybackService.TOGGLEPAUSE_ACTION);
\r
325 intent.setComponent(serviceName);
\r
326 pendingIntent = PendingIntent.getService(context, 0, intent, 0);
\r
327 views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
\r
329 intent = new Intent(MediaPlaybackService.NEXT_ACTION);
\r
330 intent.setComponent(serviceName);
\r
331 pendingIntent = PendingIntent.getService(context, 0, intent, 0);
\r
332 views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
\r
334 intent = new Intent(MediaPlaybackService.PREVIOUS_ACTION);
\r
335 intent.setComponent(serviceName);
\r
336 pendingIntent = PendingIntent.getService(context, 0, intent, 0);
\r
337 views.setOnClickPendingIntent(R.id.control_prev, pendingIntent);
\r
339 intent = new Intent(MediaPlaybackService.CYCLEREPEAT_ACTION);
\r
340 intent.setComponent(serviceName);
\r
341 pendingIntent = PendingIntent.getService(context, 0, intent, 0);
\r
342 views.setOnClickPendingIntent(R.id.control_repeat, pendingIntent);
\r
344 intent = new Intent(MediaPlaybackService.TOGGLESHUFFLE_ACTION);
\r
345 intent.setComponent(serviceName);
\r
346 pendingIntent = PendingIntent.getService(context, 0, intent, 0);
\r
347 views.setOnClickPendingIntent(R.id.control_shuffle, pendingIntent);
\r