PageRenderTime 40ms CodeModel.GetById 16ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Sky/src/org/jsharkey/sky/MedAppWidget.java

http://android-sky.googlecode.com/
Java | 177 lines | 114 code | 28 blank | 35 comment | 19 complexity | 2e2add21e990d77a952b42c47e1c8200 MD5 | raw file
  1/*
  2 * Copyright (C) 2009 Jeff Sharkey, http://jsharkey.org/
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 *      http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16
 17package org.jsharkey.sky;
 18
 19import org.jsharkey.sky.ForecastProvider.AppWidgets;
 20import org.jsharkey.sky.ForecastProvider.AppWidgetsColumns;
 21import org.jsharkey.sky.ForecastProvider.ForecastsColumns;
 22
 23import android.app.PendingIntent;
 24import android.appwidget.AppWidgetManager;
 25import android.appwidget.AppWidgetProvider;
 26import android.content.ComponentName;
 27import android.content.ContentResolver;
 28import android.content.ContentUris;
 29import android.content.Context;
 30import android.content.Intent;
 31import android.content.res.Resources;
 32import android.database.Cursor;
 33import android.net.Uri;
 34import android.util.Log;
 35import android.view.View;
 36import android.widget.RemoteViews;
 37
 38/**
 39 * Definition of a medium-sized forecast widget. Passes any requested updates to
 40 * {@link UpdateService} to perform on background thread and prevent ANR.
 41 */
 42public class MedAppWidget extends AppWidgetProvider {
 43    private static final String TAG = "MedAppWidget";
 44
 45    private static final String[] PROJECTION_APPWIDGETS = new String[] {
 46        AppWidgetsColumns.TITLE,
 47        AppWidgetsColumns.UNITS,
 48    };
 49
 50    private static final int COL_TITLE = 0;
 51    private static final int COL_UNITS = 1;
 52
 53    private static final String[] PROJECTION_FORECASTS = new String[] {
 54        ForecastsColumns.CONDITIONS,
 55        ForecastsColumns.TEMP_HIGH,
 56        ForecastsColumns.TEMP_LOW,
 57    };
 58
 59    private static final int COL_CONDITIONS = 0;
 60    private static final int COL_TEMP_HIGH = 1;
 61    private static final int COL_TEMP_LOW = 2;
 62
 63    /**
 64     * {@inheritDoc}
 65     */
 66    @Override
 67    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
 68        // If no specific widgets requested, collect list of all
 69        if (appWidgetIds == null) {
 70            appWidgetIds = appWidgetManager.getAppWidgetIds(
 71                    new ComponentName(context, MedAppWidget.class));
 72        }
 73
 74        // Request update for these widgets and launch updater service
 75        UpdateService.requestUpdate(appWidgetIds);
 76        context.startService(new Intent(context, UpdateService.class));
 77    }
 78
 79    /**
 80     * {@inheritDoc}
 81     */
 82    @Override
 83    public void onDeleted(Context context, int[] appWidgetIds) {
 84        ContentResolver resolver = context.getContentResolver();
 85        for (int appWidgetId : appWidgetIds) {
 86            Log.d(TAG, "Deleting appWidgetId=" + appWidgetId);
 87            Uri appWidgetUri = ContentUris.withAppendedId(AppWidgets.CONTENT_URI, appWidgetId);
 88            resolver.delete(appWidgetUri, null, null);
 89        }
 90    }
 91
 92    /**
 93     * Build an update for the given medium widget. Should only be called from a
 94     * service or thread to prevent ANR during database queries.
 95     */
 96    public static RemoteViews buildUpdate(Context context, Uri appWidgetUri) {
 97        Log.d(TAG, "Building medium widget update");
 98
 99        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_med);
100
101        boolean daytime = ForecastUtils.isDaytime();
102        boolean forecastFilled = false;
103
104        ContentResolver resolver = context.getContentResolver();
105        Resources res = context.getResources();
106
107        Cursor cursor = null;
108        int tempUnits = AppWidgetsColumns.UNITS_FAHRENHEIT;
109
110        // Pull out widget title and desired temperature units
111        try {
112            cursor = resolver.query(appWidgetUri, PROJECTION_APPWIDGETS, null, null, null);
113            if (cursor != null && cursor.moveToFirst()) {
114                String title = cursor.getString(COL_TITLE);
115                views.setTextViewText(R.id.location, title);
116
117                tempUnits = cursor.getInt(COL_UNITS);
118            }
119        } finally {
120            if (cursor != null) {
121                cursor.close();
122            }
123        }
124
125        // Find the forecast nearest now and build update using it
126        try {
127            Uri forecastAtUri = Uri.withAppendedPath(appWidgetUri, AppWidgets.TWIG_FORECAST_AT);
128            Uri forecastAtNowUri = Uri.withAppendedPath(forecastAtUri,
129                    Long.toString(System.currentTimeMillis()));
130            cursor = resolver.query(forecastAtNowUri, PROJECTION_FORECASTS, null, null, null);
131            if (cursor != null && cursor.moveToFirst()) {
132
133                String conditions = cursor.getString(COL_CONDITIONS);
134                int iconResource = ForecastUtils.getIconForForecast(conditions, daytime);
135                int tempHigh = cursor.getInt(COL_TEMP_HIGH);
136                int tempLow = cursor.getInt(COL_TEMP_LOW);
137
138                views.setTextViewText(R.id.conditions, conditions);
139                views.setImageViewResource(R.id.icon, iconResource);
140
141                if (tempHigh == Integer.MIN_VALUE || tempLow == Integer.MIN_VALUE) {
142                    views.setViewVisibility(R.id.high, View.GONE);
143                    views.setViewVisibility(R.id.low, View.GONE);
144                } else {
145                    views.setViewVisibility(R.id.high, View.VISIBLE);
146                    views.setViewVisibility(R.id.low, View.VISIBLE);
147                    views.setTextViewText(R.id.high,
148                            ForecastUtils.formatTemp(res, tempHigh, tempUnits));
149                    views.setTextViewText(R.id.low,
150                            ForecastUtils.formatTemp(res, tempLow, tempUnits));
151                }
152
153                forecastFilled = true;
154            }
155        } finally {
156            if (cursor != null) {
157                cursor.close();
158            }
159        }
160
161        // If not filled correctly, show error message and hide other fields
162        if (!forecastFilled) {
163            views = new RemoteViews(context.getPackageName(), R.layout.widget_loading);
164            views.setTextViewText(R.id.loading, res.getString(R.string.widget_error));
165        }
166
167        // Connect click intent to launch details dialog
168        Intent detailIntent = new Intent(context, DetailsActivity.class);
169        detailIntent.setData(appWidgetUri);
170
171        PendingIntent pending = PendingIntent.getActivity(context, 0, detailIntent, 0);
172
173        views.setOnClickPendingIntent(R.id.widget, pending);
174
175        return views;
176    }
177}