|
|
|
@ -1,110 +1,127 @@
|
|
|
|
|
package org.isoron.uhabits.widgets;
|
|
|
|
|
|
|
|
|
|
import android.appwidget.AppWidgetManager;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.os.Handler;
|
|
|
|
|
import android.os.Looper;
|
|
|
|
|
import android.support.annotation.NonNull;
|
|
|
|
|
import android.widget.RemoteViews;
|
|
|
|
|
import android.widget.RemoteViewsService;
|
|
|
|
|
|
|
|
|
|
import org.isoron.uhabits.HabitsApplication;
|
|
|
|
|
import org.isoron.uhabits.core.models.Habit;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT;
|
|
|
|
|
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH;
|
|
|
|
|
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
|
|
|
|
|
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH;
|
|
|
|
|
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
|
|
|
|
import static org.isoron.uhabits.widgets.StackWidgetService.WIDGET_TYPE;
|
|
|
|
|
import android.appwidget.*;
|
|
|
|
|
import android.content.*;
|
|
|
|
|
import android.os.*;
|
|
|
|
|
import android.support.annotation.*;
|
|
|
|
|
import android.widget.*;
|
|
|
|
|
|
|
|
|
|
import org.isoron.uhabits.*;
|
|
|
|
|
import org.isoron.uhabits.core.models.*;
|
|
|
|
|
import org.isoron.uhabits.core.utils.*;
|
|
|
|
|
|
|
|
|
|
public class StackWidgetService extends RemoteViewsService {
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
import static android.appwidget.AppWidgetManager.*;
|
|
|
|
|
import static org.isoron.androidbase.utils.InterfaceUtils.dpToPixels;
|
|
|
|
|
import static org.isoron.uhabits.widgets.StackWidgetService.*;
|
|
|
|
|
|
|
|
|
|
public class StackWidgetService extends RemoteViewsService
|
|
|
|
|
{
|
|
|
|
|
public static final String WIDGET_TYPE = "WIDGET_TYPE";
|
|
|
|
|
public static final String HABIT_IDS = "HABIT_IDS";
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public RemoteViewsFactory onGetViewFactory(Intent intent) {
|
|
|
|
|
public RemoteViewsFactory onGetViewFactory(Intent intent)
|
|
|
|
|
{
|
|
|
|
|
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
|
|
|
|
private Context mContext;
|
|
|
|
|
private int mAppWidgetId;
|
|
|
|
|
private ArrayList<Habit> mHabitList;
|
|
|
|
|
private StackWidgetType mWidgetType;
|
|
|
|
|
|
|
|
|
|
public StackRemoteViewsFactory(Context context, Intent intent) {
|
|
|
|
|
mContext = context;
|
|
|
|
|
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
|
|
|
|
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
|
|
|
|
|
{
|
|
|
|
|
private Context context;
|
|
|
|
|
private int widgetId;
|
|
|
|
|
private long[] habitIds;
|
|
|
|
|
private ArrayList<Habit> habits = new ArrayList<>();
|
|
|
|
|
private StackWidgetType widgetType;
|
|
|
|
|
|
|
|
|
|
public StackRemoteViewsFactory(Context context, Intent intent)
|
|
|
|
|
{
|
|
|
|
|
this.context = context;
|
|
|
|
|
widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
|
|
|
|
AppWidgetManager.INVALID_APPWIDGET_ID);
|
|
|
|
|
int widgetTypeValue = intent.getIntExtra(WIDGET_TYPE, -1);
|
|
|
|
|
if (widgetTypeValue != -1) {
|
|
|
|
|
mWidgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue);
|
|
|
|
|
}
|
|
|
|
|
String habitIdsStr = intent.getStringExtra(HABIT_IDS);
|
|
|
|
|
|
|
|
|
|
if (widgetTypeValue < 0) throw new RuntimeException("invalid widget type");
|
|
|
|
|
if (habitIdsStr == null) throw new RuntimeException("habitIdsStr is null");
|
|
|
|
|
|
|
|
|
|
widgetType = StackWidgetType.getWidgetTypeFromValue(widgetTypeValue);
|
|
|
|
|
habitIds = StringUtils.splitLongs(habitIdsStr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onCreate() {
|
|
|
|
|
public void onCreate()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onDestroy() {
|
|
|
|
|
public void onDestroy()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getCount() {
|
|
|
|
|
return mHabitList.size();
|
|
|
|
|
public int getCount()
|
|
|
|
|
{
|
|
|
|
|
return habits.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
public WidgetDimensions getDimensionsFromOptions(@NonNull Context ctx,
|
|
|
|
|
@NonNull Bundle options) {
|
|
|
|
|
@NonNull Bundle options)
|
|
|
|
|
{
|
|
|
|
|
int maxWidth =
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_WIDTH));
|
|
|
|
|
int maxHeight =
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MAX_HEIGHT));
|
|
|
|
|
int minWidth =
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_WIDTH));
|
|
|
|
|
int minHeight =
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
|
|
|
|
(int) dpToPixels(ctx, options.getInt(OPTION_APPWIDGET_MIN_HEIGHT));
|
|
|
|
|
|
|
|
|
|
return new WidgetDimensions(minWidth, maxHeight, maxWidth, minHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RemoteViews getViewAt(int position) {
|
|
|
|
|
public RemoteViews getViewAt(int position)
|
|
|
|
|
{
|
|
|
|
|
RemoteViews rv = null;
|
|
|
|
|
if (position < getCount()) {
|
|
|
|
|
Habit habit = mHabitList.get(position);
|
|
|
|
|
if (position < getCount())
|
|
|
|
|
{
|
|
|
|
|
Habit habit = habits.get(position);
|
|
|
|
|
BaseWidget widget = initializeWidget(habit);
|
|
|
|
|
Bundle options = AppWidgetManager.getInstance(mContext).getAppWidgetOptions(mAppWidgetId);
|
|
|
|
|
widget.setDimensions(getDimensionsFromOptions(mContext, options));
|
|
|
|
|
Bundle options =
|
|
|
|
|
AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
|
|
|
|
|
widget.setDimensions(getDimensionsFromOptions(context, options));
|
|
|
|
|
final RemoteViews[] landscape = new RemoteViews[1];
|
|
|
|
|
final RemoteViews[] portrait = new RemoteViews[1];
|
|
|
|
|
|
|
|
|
|
Object lock = new Object();
|
|
|
|
|
final boolean[] flag = {false};
|
|
|
|
|
|
|
|
|
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
landscape[0] = widget.getLandscapeRemoteViews();
|
|
|
|
|
portrait[0] = widget.getPortraitRemoteViews();
|
|
|
|
|
flag[0] = true;
|
|
|
|
|
lock.notifyAll();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
synchronized (lock) {
|
|
|
|
|
while (!flag[0]) {
|
|
|
|
|
try {
|
|
|
|
|
new Handler(Looper.getMainLooper()).post(() ->
|
|
|
|
|
{
|
|
|
|
|
synchronized (lock)
|
|
|
|
|
{
|
|
|
|
|
landscape[0] =
|
|
|
|
|
widget.getLandscapeRemoteViews();
|
|
|
|
|
portrait[0] =
|
|
|
|
|
widget.getPortraitRemoteViews();
|
|
|
|
|
flag[0] = true;
|
|
|
|
|
lock.notifyAll();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
synchronized (lock)
|
|
|
|
|
{
|
|
|
|
|
while (!flag[0])
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
lock.wait();
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (InterruptedException e)
|
|
|
|
|
{
|
|
|
|
|
// ignored
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -115,44 +132,55 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BaseWidget initializeWidget(Habit habit) {
|
|
|
|
|
switch (mWidgetType) {
|
|
|
|
|
private BaseWidget initializeWidget(Habit habit)
|
|
|
|
|
{
|
|
|
|
|
switch (widgetType)
|
|
|
|
|
{
|
|
|
|
|
case CHECKMARK:
|
|
|
|
|
return new CheckmarkWidget(mContext, mAppWidgetId, habit);
|
|
|
|
|
return new CheckmarkWidget(context, widgetId, habit);
|
|
|
|
|
case FREQUENCY:
|
|
|
|
|
return new FrequencyWidget(mContext, mAppWidgetId, habit);
|
|
|
|
|
return new FrequencyWidget(context, widgetId, habit);
|
|
|
|
|
case SCORE:
|
|
|
|
|
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
|
|
|
|
return new ScoreWidget(mContext, mAppWidgetId, habit, app.getComponent().getPreferences());
|
|
|
|
|
return new ScoreWidget(context, widgetId, habit);
|
|
|
|
|
case HISTORY:
|
|
|
|
|
return new HistoryWidget(mContext, mAppWidgetId, habit);
|
|
|
|
|
return new HistoryWidget(context, widgetId, habit);
|
|
|
|
|
case STREAKS:
|
|
|
|
|
return new StreakWidget(mContext, mAppWidgetId, habit);
|
|
|
|
|
return new StreakWidget(context, widgetId, habit);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RemoteViews getLoadingView() {
|
|
|
|
|
public RemoteViews getLoadingView()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getViewTypeCount() {
|
|
|
|
|
public int getViewTypeCount()
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long getItemId(int position) {
|
|
|
|
|
public long getItemId(int position)
|
|
|
|
|
{
|
|
|
|
|
return position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean hasStableIds() {
|
|
|
|
|
public boolean hasStableIds()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onDataSetChanged() {
|
|
|
|
|
mHabitList = new ArrayList<>();
|
|
|
|
|
HabitsApplication app = (HabitsApplication) mContext.getApplicationContext();
|
|
|
|
|
for (Habit h : app.getComponent().getHabitList()) {
|
|
|
|
|
mHabitList.add(h);
|
|
|
|
|
public void onDataSetChanged()
|
|
|
|
|
{
|
|
|
|
|
habits.clear();
|
|
|
|
|
HabitsApplication app = (HabitsApplication) context.getApplicationContext();
|
|
|
|
|
HabitList habitList = app.getComponent().getHabitList();
|
|
|
|
|
|
|
|
|
|
for (long id : habitIds)
|
|
|
|
|
{
|
|
|
|
|
Habit h = habitList.getById(id);
|
|
|
|
|
if (h == null) throw new HabitNotFoundException();
|
|
|
|
|
habits.add(h);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|