• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
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 
17 package com.android.calendar.widget;
18 
19 import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
20 import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
21 
22 import com.android.calendar.AllInOneActivity;
23 import com.android.calendar.R;
24 import com.android.calendar.Utils;
25 
26 import android.app.AlarmManager;
27 import android.app.PendingIntent;
28 import android.appwidget.AppWidgetManager;
29 import android.appwidget.AppWidgetProvider;
30 import android.content.ComponentName;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.net.Uri;
34 import android.provider.CalendarContract;
35 import android.text.format.DateUtils;
36 import android.text.format.Time;
37 import android.util.Log;
38 import android.widget.RemoteViews;
39 
40 /**
41  * Simple widget to show next upcoming calendar event.
42  */
43 public class CalendarAppWidgetProvider extends AppWidgetProvider {
44     static final String TAG = "CalendarAppWidgetProvider";
45     static final boolean LOGD = false;
46 
47     // TODO Move these to Calendar.java
48     static final String EXTRA_EVENT_IDS = "com.android.calendar.EXTRA_EVENT_IDS";
49 
50     /**
51      * {@inheritDoc}
52      */
53     @Override
onReceive(Context context, Intent intent)54     public void onReceive(Context context, Intent intent) {
55         // Handle calendar-specific updates ourselves because they might be
56         // coming in without extras, which AppWidgetProvider then blocks.
57         final String action = intent.getAction();
58         if (LOGD)
59             Log.d(TAG, "AppWidgetProvider got the intent: " + intent.toString());
60         if (Utils.getWidgetUpdateAction(context).equals(action)) {
61             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
62             performUpdate(context, appWidgetManager,
63                     appWidgetManager.getAppWidgetIds(getComponentName(context)),
64                     null /* no eventIds */);
65         } else if (action.equals(Intent.ACTION_PROVIDER_CHANGED)
66                 || action.equals(Intent.ACTION_TIME_CHANGED)
67                 || action.equals(Intent.ACTION_TIMEZONE_CHANGED)
68                 || action.equals(Intent.ACTION_DATE_CHANGED)
69                 || action.equals(Utils.getWidgetScheduledUpdateAction(context))) {
70             Intent service = new Intent(context, CalendarAppWidgetService.class);
71             context.startService(service);
72         } else {
73             super.onReceive(context, intent);
74         }
75     }
76 
77     /**
78      * {@inheritDoc}
79      */
80     @Override
onDisabled(Context context)81     public void onDisabled(Context context) {
82         // Unsubscribe from all AlarmManager updates
83         AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
84         PendingIntent pendingUpdate = getUpdateIntent(context);
85         am.cancel(pendingUpdate);
86     }
87 
88     /**
89      * {@inheritDoc}
90      */
91     @Override
onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)92     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
93         performUpdate(context, appWidgetManager, appWidgetIds, null /* no eventIds */);
94     }
95 
96 
97     /**
98      * Build {@link ComponentName} describing this specific
99      * {@link AppWidgetProvider}
100      */
getComponentName(Context context)101     static ComponentName getComponentName(Context context) {
102         return new ComponentName(context, CalendarAppWidgetProvider.class);
103     }
104 
105     /**
106      * Process and push out an update for the given appWidgetIds. This call
107      * actually fires an intent to start {@link CalendarAppWidgetService} as a
108      * background service which handles the actual update, to prevent ANR'ing
109      * during database queries.
110      *
111      * @param context Context to use when starting {@link CalendarAppWidgetService}.
112      * @param appWidgetIds List of specific appWidgetIds to update, or null for
113      *            all.
114      * @param changedEventIds Specific events known to be changed. If present,
115      *            we use it to decide if an update is necessary.
116      */
performUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, long[] changedEventIds)117     private void performUpdate(Context context,
118             AppWidgetManager appWidgetManager, int[] appWidgetIds,
119             long[] changedEventIds) {
120         // Launch over to service so it can perform update
121         for (int appWidgetId : appWidgetIds) {
122             if (LOGD) Log.d(TAG, "Building widget update...");
123             Intent updateIntent = new Intent(context, CalendarAppWidgetService.class);
124             updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
125             if (changedEventIds != null) {
126                 updateIntent.putExtra(EXTRA_EVENT_IDS, changedEventIds);
127             }
128             updateIntent.setData(Uri.parse(updateIntent.toUri(Intent.URI_INTENT_SCHEME)));
129 
130             RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);
131             // Calendar header
132             Time time = new Time(Utils.getTimeZone(context, null));
133             time.setToNow();
134             long millis = time.toMillis(true);
135             final String dayOfWeek = DateUtils.getDayOfWeekString(time.weekDay + 1,
136                     DateUtils.LENGTH_MEDIUM);
137             final String date = Utils.formatDateRange(context, millis, millis,
138                     DateUtils.FORMAT_ABBREV_ALL | DateUtils.FORMAT_SHOW_DATE
139                             | DateUtils.FORMAT_NO_YEAR);
140             views.setTextViewText(R.id.day_of_week, dayOfWeek);
141             views.setTextViewText(R.id.date, date);
142             // Attach to list of events
143             views.setRemoteAdapter(appWidgetId, R.id.events_list, updateIntent);
144             appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.events_list);
145 
146 
147             // Launch calendar app when the user taps on the header
148             final Intent launchCalendarIntent = new Intent(Intent.ACTION_VIEW);
149             launchCalendarIntent.setClass(context, AllInOneActivity.class);
150             launchCalendarIntent
151                     .setData(Uri.parse("content://com.android.calendar/time/" + millis));
152             final PendingIntent launchCalendarPendingIntent = PendingIntent.getActivity(
153                     context, 0 /* no requestCode */, launchCalendarIntent, 0 /* no flags */);
154             views.setOnClickPendingIntent(R.id.header, launchCalendarPendingIntent);
155 
156             // Each list item will call setOnClickExtra() to let the list know
157             // which item
158             // is selected by a user.
159             final PendingIntent updateEventIntent = getLaunchPendingIntentTemplate(context);
160             views.setPendingIntentTemplate(R.id.events_list, updateEventIntent);
161 
162             appWidgetManager.updateAppWidget(appWidgetId, views);
163         }
164     }
165 
166     /**
167      * Build the {@link PendingIntent} used to trigger an update of all calendar
168      * widgets. Uses {@link Utils#getWidgetScheduledUpdateAction(Context)} to
169      * directly target all widgets instead of using
170      * {@link AppWidgetManager#EXTRA_APPWIDGET_IDS}.
171      *
172      * @param context Context to use when building broadcast.
173      */
getUpdateIntent(Context context)174     static PendingIntent getUpdateIntent(Context context) {
175         Intent intent = new Intent(Utils.getWidgetScheduledUpdateAction(context));
176         intent.setDataAndType(CalendarContract.CONTENT_URI, Utils.APPWIDGET_DATA_TYPE);
177         return PendingIntent.getBroadcast(context, 0 /* no requestCode */, intent,
178                 0 /* no flags */);
179     }
180 
181     /**
182      * Build a {@link PendingIntent} to launch the Calendar app. This should be used
183      * in combination with {@link RemoteViews#setPendingIntentTemplate(int, PendingIntent)}.
184      */
getLaunchPendingIntentTemplate(Context context)185     static PendingIntent getLaunchPendingIntentTemplate(Context context) {
186         Intent launchIntent = new Intent();
187         launchIntent.setAction(Intent.ACTION_VIEW);
188         launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
189                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED |
190                 Intent.FLAG_ACTIVITY_CLEAR_TOP);
191         launchIntent.setClass(context, AllInOneActivity.class);
192         return PendingIntent.getActivity(context, 0 /* no requestCode */,
193                 launchIntent,  PendingIntent.FLAG_UPDATE_CURRENT);
194     }
195 
196     /**
197      * Build an {@link Intent} available as FillInIntent to launch the Calendar app.
198      * This should be used in combination with
199      * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
200      * If the go to time is 0, then calendar will be launched without a starting time.
201      *
202      * @param goToTime time that calendar should take the user to, or 0 to
203      *            indicate no specific start time.
204      */
getLaunchFillInIntent(Context context, long id, long start, long end)205     static Intent getLaunchFillInIntent(Context context, long id, long start, long end) {
206         final Intent fillInIntent = new Intent();
207         fillInIntent.setClass(context, AllInOneActivity.class);
208         String dataString = "content://com.android.calendar/events";
209         if (id != 0) {
210             fillInIntent.putExtra(Utils.INTENT_KEY_DETAIL_VIEW, true);
211             dataString += "/" + id;
212         }
213         Uri data = Uri.parse(dataString);
214         fillInIntent.setData(data);
215         fillInIntent.putExtra(EXTRA_EVENT_BEGIN_TIME, start);
216         fillInIntent.putExtra(EXTRA_EVENT_END_TIME, end);
217 
218         return fillInIntent;
219     }
220 
221 //    private static PendingIntent getNewEventPendingIntent(Context context) {
222 //        Intent newEventIntent = new Intent(Intent.ACTION_EDIT);
223 //        newEventIntent.setClass(context, EditEventActivity.class);
224 //        Builder builder = CalendarContract.CONTENT_URI.buildUpon();
225 //        builder.appendPath("events");
226 //        newEventIntent.setData(builder.build());
227 //        return PendingIntent.getActivity(context, 0, newEventIntent,
228 //                PendingIntent.FLAG_UPDATE_CURRENT);
229 //    }
230 }
231