package com.simplecity.amp_library.ui.widgets; 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.SharedPreferences; import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.support.annotation.LayoutRes; import android.widget.RemoteViews; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.simplecity.amp_library.R; import com.simplecity.amp_library.ShuttleApplication; import com.simplecity.amp_library.glide.utils.CustomAppWidgetTarget; import com.simplecity.amp_library.playback.MusicService; import com.simplecity.amp_library.ui.activities.MainActivity; import com.simplecity.amp_library.utils.DrawableUtils; import rx.functions.Action0; public abstract class BaseWidgetProvider extends AppWidgetProvider { public abstract String getUpdateCommandString(); public abstract String getLayoutIdString(); public abstract int getWidgetLayoutId(); public abstract int getRootViewId(); protected void doOnMainThread(Action0 action) { new Handler(Looper.getMainLooper()).post(action::call); } public static final String ARG_WIDGET_BACKGROUND_COLOR = "widget_background_color_"; public static final String ARG_WIDGET_TEXT_COLOR = "widget_text_color_"; public static final String ARG_WIDGET_INVERT_ICONS = "widget_invert_icons_"; public static final String ARG_WIDGET_SHOW_ARTWORK = "widget_show_artwork_"; public static final String ARG_WIDGET_COLOR_FILTER = "widget_color_filter_"; public SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(ShuttleApplication.getInstance()); @LayoutRes public int mLayoutId; public abstract void update(MusicService service, int[] appWidgetIds, boolean updateArtwork); protected abstract void initialiseWidget(Context context, int appWidgetId); @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for (int appWidgetId : appWidgetIds) { mLayoutId = mPrefs.getInt(getLayoutIdString() + appWidgetId, getWidgetLayoutId()); initialiseWidget(context, appWidgetId); } // Send broadcast intent to any running MusicService so it can wrap around with an immediate update. Intent updateIntent = new Intent(MusicService.ServiceCommand.SERVICE_COMMAND); updateIntent.putExtra(MusicService.MediaButtonCommand.CMD_NAME, getUpdateCommandString()); updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); context.sendBroadcast(updateIntent); } protected void pushUpdate(Context context, int appWidgetId, RemoteViews views) { // Update specific list of appWidgetIds if given, otherwise default to all final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); if (appWidgetId != -1) { appWidgetManager.updateAppWidget(appWidgetId, views); } else { appWidgetManager.updateAppWidget(new ComponentName(context, this.getClass()), views); } } private int[] getInstances(Context context) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); return (appWidgetManager.getAppWidgetIds(new ComponentName(context, this.getClass()))); } public void notifyChange(MusicService service, String what) { if (getInstances(service) != null) { if (MusicService.InternalIntents.META_CHANGED.equals(what) || MusicService.InternalIntents.PLAY_STATE_CHANGED.equals(what) || MusicService.InternalIntents.SHUFFLE_CHANGED.equals(what) || MusicService.InternalIntents.REPEAT_CHANGED.equals(what)) { update(service, getInstances(service), MusicService.InternalIntents.META_CHANGED.equals(what)); } } } public static void setupButtons(Context context, RemoteViews views, int appWidgetId, int rootViewId) { Intent intent; PendingIntent pendingIntent; final ComponentName serviceName = new ComponentName(context, MusicService.class); intent = new Intent(context, MainActivity.class); pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); views.setOnClickPendingIntent(rootViewId, pendingIntent); intent = new Intent(MusicService.ServiceCommand.TOGGLE_PAUSE_ACTION); intent.setComponent(serviceName); pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0); views.setOnClickPendingIntent(R.id.play_button, pendingIntent); intent = new Intent(MusicService.ServiceCommand.NEXT_ACTION); intent.setComponent(serviceName); pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0); views.setOnClickPendingIntent(R.id.next_button, pendingIntent); intent = new Intent(MusicService.ServiceCommand.PREV_ACTION); intent.setComponent(serviceName); pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0); views.setOnClickPendingIntent(R.id.prev_button, pendingIntent); intent = new Intent(MusicService.ServiceCommand.SHUFFLE_ACTION); intent.setComponent(serviceName); pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0); views.setOnClickPendingIntent(R.id.shuffle_button, pendingIntent); intent = new Intent(MusicService.ServiceCommand.REPEAT_ACTION); intent.setComponent(serviceName); pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0); views.setOnClickPendingIntent(R.id.repeat_button, pendingIntent); } void loadArtwork(MusicService service, int[] appWidgetIds, RemoteViews views, int bitmapSize) { //Try to load the artwork. If it fails, halve the dimensions and try again. loadArtwork(service, views, bitmapSize, e -> loadArtwork(service, views, bitmapSize / 2, e1 -> //If this one doesn't work, load a placeholder. loadArtwork(service, views, bitmapSize / 3, e2 -> views.setImageViewResource(R.id.album_art, R.drawable.ic_placeholder_light_medium), appWidgetIds), appWidgetIds), appWidgetIds); } void loadArtwork(MusicService service, RemoteViews views, int size, CustomAppWidgetTarget.CustomErrorListener errorListener, int... appWidgetIds) { Glide.with(service) .load(service.getSong()) .asBitmap() .diskCacheStrategy(DiskCacheStrategy.ALL) .into(new CustomAppWidgetTarget(service, views, R.id.album_art, size, size, errorListener, appWidgetIds)); } void setupRepeatView(MusicService service, RemoteViews views, boolean invertIcons) { switch (service.getRepeatMode()) { case MusicService.RepeatMode.ALL: views.setImageViewBitmap(R.id.repeat_button, DrawableUtils.getColoredBitmap(service, R.drawable.ic_repeat_white)); views.setContentDescription(R.id.shuffle_button, service.getString(R.string.btn_repeat_current)); break; case MusicService.RepeatMode.ONE: views.setImageViewBitmap(R.id.repeat_button, DrawableUtils.getColoredBitmap(service, R.drawable.ic_repeat_one_white)); views.setContentDescription(R.id.shuffle_button, service.getString(R.string.btn_repeat_off)); break; default: if (invertIcons) { views.setImageViewBitmap(R.id.repeat_button, DrawableUtils.getBlackBitmap(service, R.drawable.ic_repeat_white)); } else { views.setImageViewResource(R.id.repeat_button, R.drawable.ic_repeat_white); } views.setContentDescription(R.id.shuffle_button, service.getString(R.string.btn_repeat_all)); break; } } void setupShuffleView(MusicService service, RemoteViews views, boolean invertIcons) { switch (service.getShuffleMode()) { case MusicService.ShuffleMode.OFF: if (invertIcons) { views.setImageViewBitmap(R.id.shuffle_button, DrawableUtils.getBlackBitmap(service, R.drawable.ic_shuffle_white)); } else { views.setImageViewResource(R.id.shuffle_button, R.drawable.ic_shuffle_white); } views.setContentDescription(R.id.shuffle_button, service.getString(R.string.btn_shuffle_on)); break; default: views.setImageViewBitmap(R.id.shuffle_button, DrawableUtils.getColoredBitmap(service, R.drawable.ic_shuffle_white)); views.setContentDescription(R.id.shuffle_button, service.getString(R.string.btn_shuffle_off)); break; } } }