package com.hourlyweather.appwidget;
import org.joda.time.MutableDateTime;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.IBinder;
import android.os.SystemClock;
import android.widget.RemoteViews;
import com.hourlyweather.ForecastCacher;
import com.hourlyweather.HourlyWeather;
import com.hourlyweather.R;
import com.hourlyweather.SettingsManager;
import com.hourlyweather.forecast.ForecastHour;
import com.hourlyweather.forecast.HourlyForecast;
import com.hourlyweather.util.WidgetForecastIconUtil;
/**
* A simple scroll list to work around the lack of a core android one. Displays
* the forecast in the widget and handles scrolling via buttons and launching
* the main app.
*
* @author dhgonsalves
*
*/
public class WidgetScrollList extends Service {
public static final String NEXT = "NEXT";
public static final String BACK = "BACK";
public static final int LIST_SLOT_COUNT = 6;
private static final String PREF_NAME = "HOURLY_WEATHER_PREFS";
private static final String PREF_POSITION = "POSITION";
public static String WIDGET_INDEX = "com.hourlyweather.widget.index";
@Override
public void onStart(Intent intent, int startId) {
System.out.println("called!");
super.onStart(intent, startId);
// handle the scroll action
if (NEXT.equals(intent.getAction()))
addToPosition(1);
else if (BACK.equals(intent.getAction()))
addToPosition(-1);
// update view to reflect position change if cached copy exists
HourlyForecast forecast = ForecastCacher.getCachedForecast(this);
if (forecast != null)
populateList(this, forecast);
}
/**
* get the current list index
*/
public static int getPosition(Context context) {
SharedPreferences config = context.getSharedPreferences(PREF_NAME, 0);
return config.getInt(PREF_POSITION, 0);
}
/**
* Set the current list index
*/
public static void setPosition(Context context, int value) {
SharedPreferences.Editor configEditor = context.getSharedPreferences(
PREF_NAME, 0).edit();
configEditor.putInt(PREF_POSITION, value);
configEditor.commit();
}
/**
* Add the passed value to the current position if it results in a possiable
* position
*/
protected void addToPosition(int value) {
SharedPreferences config = getSharedPreferences(PREF_NAME, 0);
int position = config.getInt(PREF_POSITION, 0) + value;
if (position < 0
|| position >= HourlyWeather.FORECAST_HOUR_SPAN
- LIST_SLOT_COUNT)
return;
SharedPreferences.Editor configEditor = config.edit();
configEditor.putInt(PREF_POSITION, position);
configEditor.commit();
}
/**
* Hooks up the forecast list buttons which are next, back and the forecast
* area which starts the parent application
*/
protected static void hookUpListButtons(Context context, RemoteViews views) {
// add the scroll buttons press handling
Intent scrollIntent = new Intent(context, WidgetScrollList.class);
views.setOnClickPendingIntent(
R.id.next,
PendingIntent.getService(context, 0,
scrollIntent.setAction(WidgetScrollList.NEXT), 0));
views.setOnClickPendingIntent(
R.id.back,
PendingIntent.getService(context, 0,
scrollIntent.setAction(WidgetScrollList.BACK), 0));
// set up click listener to start parent application if the forecast is
// clicked and scroll to the current forecast time span
Intent hourlyWeatherIntent = new Intent(context, HourlyWeather.class);
hourlyWeatherIntent.setAction(Intent.ACTION_VIEW);
hourlyWeatherIntent.putExtra(WIDGET_INDEX, getPosition(context));
hourlyWeatherIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
hourlyWeatherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
hourlyWeatherIntent.setData((Uri.parse("foobar://"
+ SystemClock.elapsedRealtime())));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
hourlyWeatherIntent, 0);
views.setOnClickPendingIntent(R.id.weather_content, pendingIntent);
}
/**
* Populates the list with the passed in forecast at the current position
* applying the current settings and formatting options
*/
public static void populateList(Context context, HourlyForecast forecast) {
// get the settings to use
SettingsManager settings = new SettingsManager(
context.getSharedPreferences("com.hourlyweather",
Context.MODE_PRIVATE));
// get the weather formatter
WidgetForecastFormatter formatter = new WidgetForecastFormatter(
settings);
// create the view
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget);
views.removeAllViews(R.id.weather_content);
hookUpListButtons(context, views);
ForecastHour forecastHour;
int position = WidgetScrollList.getPosition(context);
for (int j = position; j < WidgetScrollList.LIST_SLOT_COUNT + position; j++) {
forecastHour = forecast.getForecastHours()[j];
// set the forecast widget type to current, day or night
int widgetTypeId;
boolean useAlt = j % 2 == 0 ? true : false;
if (j == 0)
widgetTypeId = R.layout.widget_forecast_item_current;
else if (forecastHour.isSunUp())
if (useAlt)
widgetTypeId = R.layout.widget_forecast_item_alt;
else
widgetTypeId = R.layout.widget_forecast_item;
else if (useAlt)
widgetTypeId = R.layout.widget_forecast_night_item_alt;
else
widgetTypeId = R.layout.widget_forecast_night_item;
// create the forecast hour widget
RemoteViews forecastItem = new RemoteViews(
context.getPackageName(), widgetTypeId);
forecastItem.setTextViewText(R.id.temp,
formatter.formatTemperature(forecastHour));
// get the time that corresponds to this forecast
MutableDateTime forecastTime = new MutableDateTime(
forecast.getStart());
forecastTime.addHours(j);
forecastItem.setTextViewText(
R.id.time,
formatter.formatTime(forecastTime,
context.getContentResolver()));
forecastItem.setImageViewResource(R.id.icon,
WidgetForecastIconUtil.getIconId(forecastHour));
views.addView(R.id.weather_content, forecastItem);
}
// Push update for this widget to the home screen
// ComponentName thisWidget = new
// ComponentName(context,HourlyWeatherWidget.class);
ComponentName thisWidget = new ComponentName("com.hourlyweather",
"com.hourlyweather.appwidget.HourlyWeatherWidget");
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(thisWidget, views);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}