DigitalWidgetViewsFactory.java revision d851e8a4b134028bd12f509312d31664e4c826dd
1/* 2 * Copyright (C) 2012 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 17package com.android.alarmclock; 18 19import android.appwidget.AppWidgetManager; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.provider.Settings; 25import android.text.TextUtils; 26import android.text.format.DateFormat; 27import android.util.Log; 28import android.util.TypedValue; 29import android.view.View; 30import android.widget.RemoteViews; 31import android.widget.RemoteViewsService.RemoteViewsFactory; 32 33import com.android.deskclock.Alarms; 34import com.android.deskclock.R; 35import com.android.deskclock.Utils; 36import com.android.deskclock.worldclock.CityObj; 37import com.android.deskclock.worldclock.WorldClockAdapter; 38 39import java.util.Calendar; 40import java.util.Locale; 41import java.util.TimeZone; 42 43public class DigitalWidgetViewsFactory extends BroadcastReceiver implements RemoteViewsFactory { 44 private static final String TAG = "DigitalWidgetViewsFactory"; 45 46 private Context mContext; 47 private int mId = AppWidgetManager.INVALID_APPWIDGET_ID; 48 private RemoteWorldClockAdapter mAdapter; 49 private boolean mReloadCitiesList = true; 50 private boolean mReloadCitiesDb = true; 51 private float mFontScale = 1; 52 53 // An adapter to provide the view for the list of cities in the world clock. 54 private class RemoteWorldClockAdapter extends WorldClockAdapter { 55 private final float mFontSize; 56 57 public RemoteWorldClockAdapter(Context context) { 58 super(context); 59 mFontSize = context.getResources().getDimension(R.dimen.widget_medium_font_size); 60 } 61 62 public RemoteViews getViewAt(int position) { 63 // There are 2 cities per item 64 int index = position * 2; 65 if (index < 0 || index >= mCitiesList.length) { 66 return null; 67 } 68 69 RemoteViews views = new RemoteViews( 70 mContext.getPackageName(), R.layout.world_clock_remote_list_item); 71 72 // Always how the left clock 73 updateView(views, (CityObj) mCitiesList[index], R.id.leftClock1, R.id.leftClock2, 74 R.id.city_name_left, R.id.city_day_left); 75 // Show the right clock if any, make it invisible if there is no 76 // clock on the right 77 // to keep the left view on the left. 78 if (index + 1 < mCitiesList.length) { 79 updateView(views, (CityObj) mCitiesList[index + 1], R.id.rightClock1, 80 R.id.rightClock2, R.id.city_name_right, R.id.city_day_right); 81 } else { 82 hideView(views, R.id.rightClock1, R.id.rightClock2, R.id.city_name_right, 83 R.id.city_day_right); 84 } 85 return views; 86 } 87 88 private void updateView(RemoteViews clock, CityObj cityObj, int clockId1, int clockId2, 89 int labelId, int dayId) { 90 final Calendar now = Calendar.getInstance(); 91 now.setTimeInMillis(System.currentTimeMillis()); 92 int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 93 CityObj cityInDb = mCitiesDb.get(cityObj.mCityId); 94 String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone; 95 now.setTimeZone(TimeZone.getTimeZone(cityTZ)); 96 int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK); 97 98 clock.setTextViewTextSize(clockId1, TypedValue.COMPLEX_UNIT_PX, mFontSize * mFontScale); 99 clock.setTextViewTextSize(clockId2, TypedValue.COMPLEX_UNIT_PX, mFontSize * mFontScale); 100 clock.setString(clockId1, "setTimeZone", cityObj.mTimeZone); 101 clock.setString(clockId2, "setTimeZone", cityObj.mTimeZone); 102 103 // Home city or city not in DB , use data from the save selected cities list 104 clock.setTextViewText(labelId, Utils.getCityName(cityObj, cityInDb)); 105 106 if (myDayOfWeek != cityDayOfWeek) { 107 clock.setTextViewText(dayId, mContext.getString( 108 R.string.world_day_of_week_label, now.getDisplayName( 109 Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault()))); 110 clock.setViewVisibility(dayId, View.VISIBLE); 111 } else { 112 clock.setViewVisibility(dayId, View.GONE); 113 } 114 115 clock.setViewVisibility(clockId1, View.VISIBLE); 116 clock.setViewVisibility(clockId2, View.VISIBLE); 117 clock.setViewVisibility(labelId, View.VISIBLE); 118 } 119 120 private void hideView( 121 RemoteViews clock, int clockId1, int clockId2, int labelId, int dayId) { 122 clock.setViewVisibility(clockId1, View.INVISIBLE); 123 clock.setViewVisibility(clockId2, View.INVISIBLE); 124 clock.setViewVisibility(labelId, View.INVISIBLE); 125 clock.setViewVisibility(dayId, View.INVISIBLE); 126 } 127 } 128 129 public DigitalWidgetViewsFactory(Context c, Intent intent) { 130 mContext = c; 131 mId = intent.getIntExtra( 132 AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); 133 mAdapter = new RemoteWorldClockAdapter(c); 134 } 135 136 public DigitalWidgetViewsFactory() { 137 } 138 139 @Override 140 public int getCount() { 141 if (WidgetUtils.showList(mContext, mId, mFontScale)) { 142 return mAdapter.getCount(); 143 } 144 return 0; 145 } 146 147 @Override 148 public long getItemId(int position) { 149 return position; 150 } 151 152 @Override 153 public RemoteViews getLoadingView() { 154 return null; 155 } 156 157 @Override 158 public RemoteViews getViewAt(int position) { 159 RemoteViews v = mAdapter.getViewAt(position); 160 if (v != null) { 161 Intent fillInIntent = new Intent(); 162 v.setOnClickFillInIntent(R.id.widget_item, fillInIntent); 163 } 164 return v; 165 } 166 167 @Override 168 public int getViewTypeCount() { 169 return 1; 170 } 171 172 @Override 173 public boolean hasStableIds() { 174 return true; 175 } 176 177 @Override 178 public void onCreate() { 179 // Do intent listening registration here since doing it in the manifest creates a new 180 // new factory 181 IntentFilter filter = new IntentFilter(); 182 filter.addAction(Intent.ACTION_DATE_CHANGED); 183 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 184 filter.addAction(Intent.ACTION_SCREEN_ON); 185 filter.addAction(Intent.ACTION_TIME_TICK); 186 filter.addAction(Intent.ACTION_TIME_CHANGED); 187 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 188 filter.addAction("com.android.deskclock.NEXT_ALARM_TIME_SET"); 189 filter.addAction("com.android.deskclock.worldclock.update"); 190 mContext.registerReceiver(this, filter); 191 } 192 193 @Override 194 public void onDataSetChanged() { 195 if (mReloadCitiesList) { 196 mAdapter.loadData(mContext); 197 mReloadCitiesList = false; 198 } 199 if (mReloadCitiesDb) { 200 mAdapter.loadCitiesDb(mContext); 201 mReloadCitiesDb = false; 202 } 203 204 mFontScale = WidgetUtils.getScaleRatio(mContext, null, mId); 205 } 206 207 @Override 208 public void onDestroy() { 209 mContext.unregisterReceiver(this); 210 } 211 212 213 @Override 214 public void onReceive(Context context, Intent intent) { 215 if (mId == AppWidgetManager.INVALID_APPWIDGET_ID) { 216 return; 217 } 218 mContext = context; 219 String action = intent.getAction(); 220 AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); 221 if (action.equals("com.android.deskclock.NEXT_ALARM_TIME_SET")) { 222 // Update the next alarm text view 223 RemoteViews widget = 224 new RemoteViews(context.getPackageName(), R.layout.digital_appwidget); 225 refreshAlarm(context, widget); 226 widgetManager.partiallyUpdateAppWidget(mId, widget); 227 } else if (action.equals("com.android.deskclock.worldclock.update")) { 228 // Reload the list of cities 229 mReloadCitiesList = true; 230 widgetManager.notifyAppWidgetViewDataChanged(mId, R.id.digital_appwidget_listview); 231 232 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 233 RemoteViews widget = 234 new RemoteViews(context.getPackageName(), R.layout.digital_appwidget); 235 refreshAlarm(context, widget); 236 widgetManager.partiallyUpdateAppWidget(mId, widget); 237 } else { 238 if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { 239 // refresh the list to make sure home time zone is displayed / removed 240 mReloadCitiesList = true; 241 } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { 242 // reload the cities DB to pick up the cities name in the new language 243 mReloadCitiesDb = true; 244 } 245 // For any time change or locale change, refresh all 246 widgetManager.notifyAppWidgetViewDataChanged(mId, R.id.digital_appwidget_listview); 247 RemoteViews widget = 248 new RemoteViews(context.getPackageName(), R.layout.digital_appwidget); 249 float ratio = WidgetUtils.getScaleRatio(context, null, mId); 250 WidgetUtils.setClockSize(context, widget, ratio); 251 refreshAlarm(context, widget); 252 widgetManager.partiallyUpdateAppWidget(mId, widget); 253 } 254 } 255 256 private void refreshAlarm(Context c, RemoteViews widget) { 257 String nextAlarm = Settings.System.getString(c.getContentResolver(), 258 Settings.System.NEXT_ALARM_FORMATTED); 259 if (!TextUtils.isEmpty(nextAlarm)) { 260 widget.setTextViewText(R.id.nextAlarm, 261 c.getString(R.string.control_set_alarm_with_existing, nextAlarm)); 262 widget.setViewVisibility(R.id.nextAlarm, View.VISIBLE); 263 } else { 264 widget.setViewVisibility(R.id.nextAlarm, View.GONE); 265 } 266 } 267} 268 269