diff options
Diffstat (limited to 'src/com')
25 files changed, 929 insertions, 379 deletions
diff --git a/src/com/android/alarmclock/DigitalWidgetViewsFactory.java b/src/com/android/alarmclock/DigitalWidgetViewsFactory.java index 92d798bcf..d906b8991 100644 --- a/src/com/android/alarmclock/DigitalWidgetViewsFactory.java +++ b/src/com/android/alarmclock/DigitalWidgetViewsFactory.java @@ -16,6 +16,7 @@ package com.android.alarmclock; +import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -47,7 +48,12 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo private int mId = AppWidgetManager.INVALID_APPWIDGET_ID; private RemoteWorldClockAdapter mAdapter; private boolean mReloadCitiesList = true; + private boolean mReloadCitiesDb = true; private float mFontScale = 1; + private float mListScale = 1; + private PendingIntent mQuarterlyIntent; + private String mLastTimeZone; + // An adapter to provide the view for the list of cities in the world clock. private class RemoteWorldClockAdapter extends WorldClockAdapter { @@ -89,14 +95,20 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo final Calendar now = Calendar.getInstance(); now.setTimeInMillis(System.currentTimeMillis()); int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK); - now.setTimeZone(TimeZone.getTimeZone(cityObj.mTimeZone)); + CityObj cityInDb = mCitiesDb.get(cityObj.mCityId); + String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone; + now.setTimeZone(TimeZone.getTimeZone(cityTZ)); int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK); - clock.setTextViewTextSize(clockId1, TypedValue.COMPLEX_UNIT_PX, mFontSize * mFontScale); - clock.setTextViewTextSize(clockId2, TypedValue.COMPLEX_UNIT_PX, mFontSize * mFontScale); + float scale = Math.min(mFontScale, mListScale); + clock.setTextViewTextSize(clockId1, TypedValue.COMPLEX_UNIT_PX, mFontSize * scale); + clock.setTextViewTextSize(clockId2, TypedValue.COMPLEX_UNIT_PX, mFontSize * scale); clock.setString(clockId1, "setTimeZone", cityObj.mTimeZone); clock.setString(clockId2, "setTimeZone", cityObj.mTimeZone); - clock.setTextViewText(labelId, cityObj.mCityName); + + // Home city or city not in DB , use data from the save selected cities list + clock.setTextViewText(labelId, Utils.getCityName(cityObj, cityInDb)); + if (myDayOfWeek != cityDayOfWeek) { clock.setTextViewText(dayId, mContext.getString( R.string.world_day_of_week_label, now.getDisplayName( @@ -125,6 +137,7 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo mId = intent.getIntExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); mAdapter = new RemoteWorldClockAdapter(c); + mLastTimeZone = TimeZone.getDefault().getID(); } public DigitalWidgetViewsFactory() { @@ -170,13 +183,14 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo @Override public void onCreate() { + mQuarterlyIntent = Utils.startAlarmOnQuarterHour(mContext); // Do intent listening registration here since doing it in the manifest creates a new // new factory IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_DATE_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Utils.ACTION_ON_QUARTER_HOUR); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_LOCALE_CHANGED); filter.addAction("com.android.deskclock.NEXT_ALARM_TIME_SET"); @@ -190,11 +204,19 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo mAdapter.loadData(mContext); mReloadCitiesList = false; } + if (mReloadCitiesDb) { + mAdapter.loadCitiesDb(mContext); + mReloadCitiesDb = false; + } + mFontScale = WidgetUtils.getScaleRatio(mContext, null, mId); + mListScale = WidgetUtils.getHeightScaleRatio(mContext, null, mId); + } @Override public void onDestroy() { + Utils.cancelAlarmOnQuarterHour(mContext, mQuarterlyIntent); mContext.unregisterReceiver(this); } @@ -224,6 +246,26 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo refreshAlarm(context, widget); widgetManager.partiallyUpdateAppWidget(mId, widget); } else { + if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { + // refresh the list to make sure home time zone is displayed / removed + mReloadCitiesList = true; + mLastTimeZone = TimeZone.getDefault().getID(); + } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { + // reload the cities DB to pick up the cities name in the new language + mReloadCitiesDb = true; + } else if (action.equals(Utils.ACTION_ON_QUARTER_HOUR)) { + // Since the system may miss or not send time zone changes in all cases + // make sure to update the world clock list if the time zone + // changed in the last 15 minutes + String currentTimeZone = TimeZone.getDefault().getID(); + if (!TextUtils.equals(currentTimeZone, mLastTimeZone)) { + // refresh the list to make sure home time zone is displayed / removed + mReloadCitiesList = true; + mLastTimeZone = currentTimeZone; + Log.v(TAG,"Detected time zone change,updating time zone to " + currentTimeZone); + } + } + // For any time change or locale change, refresh all widgetManager.notifyAppWidgetViewDataChanged(mId, R.id.digital_appwidget_listview); RemoteViews widget = @@ -232,6 +274,7 @@ public class DigitalWidgetViewsFactory extends BroadcastReceiver implements Remo WidgetUtils.setClockSize(context, widget, ratio); refreshAlarm(context, widget); widgetManager.partiallyUpdateAppWidget(mId, widget); + mQuarterlyIntent = Utils.refreshAlarmOnQuarterHour(context, mQuarterlyIntent); } } diff --git a/src/com/android/alarmclock/WidgetUtils.java b/src/com/android/alarmclock/WidgetUtils.java index 757e062ad..d4a6b7066 100644 --- a/src/com/android/alarmclock/WidgetUtils.java +++ b/src/com/android/alarmclock/WidgetUtils.java @@ -56,6 +56,26 @@ public class WidgetUtils { return 1; } + // Calculate the scale factor of the fonts in the list of the widget using the widget height + public static float getHeightScaleRatio(Context context, Bundle options, int id) { + AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); + if (options == null) { + options = widgetManager.getAppWidgetOptions(id); + } + if (options != null) { + int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); + if (minHeight == 0) { + // No data , do no scaling + return 1f; + } + Resources res = context.getResources(); + float ratio = minHeight / res.getDimension(R.dimen.def_digital_widget_height); + return (ratio > 1) ? 1 : ratio; + } + return 1; + } + + // Decide if to show the list of world clock. // Check to see if the widget size is big enough, if it is return true. public static boolean showList(Context context, int id, float scale) { @@ -66,7 +86,7 @@ public class WidgetUtils { } int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); int neededSize = (int) context.getResources(). - getDimension(R.dimen.def_digital_widget_height); + getDimension(R.dimen.digital_widget_list_min_height); return (minHeight > neededSize); } } diff --git a/src/com/android/deskclock/AlarmAlertFullScreen.java b/src/com/android/deskclock/AlarmAlertFullScreen.java index 76166a9d2..b195a0ac0 100644 --- a/src/com/android/deskclock/AlarmAlertFullScreen.java +++ b/src/com/android/deskclock/AlarmAlertFullScreen.java @@ -95,11 +95,12 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig if (action.equals(Alarms.ALARM_SNOOZE_ACTION)) { snooze(); } else if (action.equals(Alarms.ALARM_DISMISS_ACTION)) { - dismiss(false); + dismiss(false, false); } else { Alarm alarm = intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA); + boolean replaced = intent.getBooleanExtra(Alarms.ALARM_REPLACED, false); if (alarm != null && mAlarm.id == alarm.id) { - dismiss(true); + dismiss(true, replaced); } } } @@ -232,7 +233,7 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig final String vol = PreferenceManager.getDefaultSharedPreferences(this) .getString(SettingsActivity.KEY_VOLUME_BEHAVIOR, - DEFAULT_VOLUME_BEHAVIOR); + SettingsActivity.DEFAULT_VOLUME_BEHAVIOR); mVolumeBehavior = Integer.parseInt(vol); final Window win = getWindow(); @@ -373,8 +374,12 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig } // Dismiss the alarm. - private void dismiss(boolean killed) { - Log.i(killed ? "Alarm killed" : "Alarm dismissed by user"); + private void dismiss(boolean killed, boolean replaced) { + if (LOG) { + Log.v("AlarmAlertFullScreen - dismiss"); + } + + Log.i("Alarm id=" + mAlarm.id + (killed ? (replaced ? " replaced" : " killed") : " dismissed by user")); // The service told us that the alarm has been killed, do not modify // the notification or stop the service. if (!killed) { @@ -383,7 +388,9 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig nm.cancel(mAlarm.id); stopService(new Intent(Alarms.ALARM_ALERT_ACTION)); } - finish(); + if (!replaced) { + finish(); + } } private void attachListeners() { @@ -514,7 +521,7 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig break; case 2: - dismiss(false); + dismiss(false, false); break; default: @@ -559,7 +566,7 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig break; case R.drawable.ic_alarm_alert_dismiss: - dismiss(false); + dismiss(false, false); break; default: // Code should never reach here. diff --git a/src/com/android/deskclock/AlarmClock.java b/src/com/android/deskclock/AlarmClock.java index 9f2498e05..fd6526e62 100644 --- a/src/com/android/deskclock/AlarmClock.java +++ b/src/com/android/deskclock/AlarmClock.java @@ -18,10 +18,12 @@ package com.android.deskclock; import android.app.ActionBar; import android.app.Activity; +import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.LoaderManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; import android.content.res.Resources; @@ -65,7 +67,7 @@ import java.util.HashSet; public class AlarmClock extends Activity implements LoaderManager.LoaderCallbacks<Cursor>, AlarmTimePickerDialogFragment.AlarmTimePickerDialogHandler, LabelDialogFragment.AlarmLabelDialogHandler, - OnLongClickListener, Callback { + OnLongClickListener, Callback, DialogInterface.OnClickListener { private static final String KEY_EXPANDED_IDS = "expandedIds"; private static final String KEY_REPEAT_CHECKED_IDS = "repeatCheckedIds"; @@ -75,6 +77,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback private static final String KEY_UNDO_SHOWING = "undoShowing"; private static final String KEY_PREVIOUS_DAY_MAP = "previousDayMap"; private static final String KEY_SELECTED_ALARM = "selectedAlarm"; + private static final String KEY_DELETE_CONFIRMATION = "deleteConfirmation"; private static final int REQUEST_CODE_RINGTONE = 1; @@ -86,6 +89,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback private Alarm mSelectedAlarm; private int mScrollToAlarmId = -1; + private boolean mInDeleteConfirmation = false; // This flag relies on the activity having a "standard" launchMode and a new instance of this // activity being created when launched. @@ -118,6 +122,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback selectedAlarms = savedState.getIntArray(KEY_SELECTED_ALARMS); previousDayMap = savedState.getBundle(KEY_PREVIOUS_DAY_MAP); mSelectedAlarm = savedState.getParcelable(KEY_SELECTED_ALARM); + mInDeleteConfirmation = savedState.getBoolean(KEY_DELETE_CONFIRMATION, false); } mAlarmsList = (SwipeableListView) findViewById(R.id.alarms_list); @@ -174,6 +179,13 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback } + @Override + public void onResume() { + super.onResume(); + if (mInDeleteConfirmation) { + showConfirmationDialog(); + } + } private void hideUndoBar(boolean animate, MotionEvent event) { if (mUndoBar != null) { if (event != null && mUndoBar.isEventInToastBar(event)) { @@ -197,6 +209,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback outState.putBoolean(KEY_UNDO_SHOWING, mUndoShowing); outState.putBundle(KEY_PREVIOUS_DAY_MAP, mAdapter.getPreviousDaysOfWeekMap()); outState.putParcelable(KEY_SELECTED_ALARM, mSelectedAlarm); + outState.putBoolean(KEY_DELETE_CONFIRMATION, mInDeleteConfirmation); } private void updateLayout() { @@ -458,6 +471,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback CheckBox incvol; ViewGroup collapse; TextView ringtone; + View hairLine; // Other states Alarm alarm; @@ -577,6 +591,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback holder.infoArea = view.findViewById(R.id.info_area); holder.repeat = (CheckBox) view.findViewById(R.id.repeat_onoff); holder.clickableLabel = (TextView) view.findViewById(R.id.edit_label); + holder.hairLine = view.findViewById(R.id.hairline); holder.repeatDays = (LinearLayout) view.findViewById(R.id.repeat_days); // Build button for each day. @@ -614,14 +629,12 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback itemHolder.onoff.setChecked(alarm.enabled); if (mSelectedAlarms.contains(itemHolder.alarm.id)) { itemHolder.alarmItem.setBackgroundColor(mBackgroundColorSelected); - itemHolder.alarmItem.setAlpha(1f); + setItemAlpha(itemHolder, true); + itemHolder.onoff.setEnabled(false); } else { + itemHolder.onoff.setEnabled(true); itemHolder.alarmItem.setBackgroundColor(mBackgroundColor); - if (itemHolder.onoff.isChecked()) { - itemHolder.alarmItem.setAlpha(1f); - } else { - itemHolder.alarmItem.setAlpha(0.5f); - } + setItemAlpha(itemHolder, itemHolder.onoff.isChecked()); } final CompoundButton.OnCheckedChangeListener onOffListener = new CompoundButton.OnCheckedChangeListener() { @@ -633,11 +646,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback return; } if (checked != alarm.enabled) { - if (checked) { - itemHolder.alarmItem.setAlpha(1f); - } else { - itemHolder.alarmItem.setAlpha(0.5f); - } + setItemAlpha(itemHolder, checked); alarm.enabled = checked; asyncUpdateAlarm(alarm, alarm.enabled); } @@ -944,6 +953,16 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback itemHolder.ringtone.setOnLongClickListener(mLongClickListener); } + // Sets the alpha of the item except the on/off switch. This gives a visual effect + // for enabled/disabled alarm while leaving the on/off switch more visible + private void setItemAlpha(ItemHolder holder, boolean enabled) { + float alpha = enabled ? 1f : 0.5f; + holder.clock.setAlpha(alpha); + holder.infoArea.setAlpha(alpha); + holder.expandArea.setAlpha(alpha); + holder.hairLine.setAlpha(alpha); + } + private void updateDaysOfWeekButtons(ItemHolder holder, Alarm.DaysOfWeek daysOfWeek) { HashSet<Integer> setDays = daysOfWeek.getSetDays(); for (int i = 0; i < 7; i++) { @@ -1246,10 +1265,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback switch (item.getItemId()) { // Delete selected items and close CAB. case R.id.menu_item_delete_alarm: - if (mAdapter != null) { - mAdapter.deleteSelectedAlarms(); - mode.finish(); - } + showConfirmationDialog(); break; default: break; @@ -1276,4 +1292,30 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback return false; } + /*** + * Handle the delete alarms confirmation dialog + */ + + private void showConfirmationDialog() { + AlertDialog.Builder b = new AlertDialog.Builder(this); + Resources res = getResources(); + String msg = String.format(res.getQuantityText(R.plurals.alarm_delete_confirmation, + mAdapter.getSelectedItemsNum()).toString()); + b.setCancelable(true).setMessage(msg) + .setNegativeButton(res.getString(android.R.string.cancel), this) + .setPositiveButton(res.getString(android.R.string.ok), this).show(); + mInDeleteConfirmation = true; + } + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == -1) { + if (mAdapter != null) { + mAdapter.deleteSelectedAlarms(); + mActionMode.finish(); + } + } + dialog.dismiss(); + mInDeleteConfirmation = false; + } + } diff --git a/src/com/android/deskclock/AlarmInitReceiver.java b/src/com/android/deskclock/AlarmInitReceiver.java index 83ca4a118..b2625f195 100644 --- a/src/com/android/deskclock/AlarmInitReceiver.java +++ b/src/com/android/deskclock/AlarmInitReceiver.java @@ -27,6 +27,9 @@ import com.android.deskclock.timer.TimerObj; public class AlarmInitReceiver extends BroadcastReceiver { + // A flag that indicates that switching the volume button default was done + private static final String PREF_VOLUME_DEF_DONE = "vol_def_done"; + /** * Sets alarm on ACTION_BOOT_COMPLETED. Resets alarm on * TIME_SET, TIMEZONE_CHANGED @@ -49,9 +52,15 @@ public class AlarmInitReceiver extends BroadcastReceiver { // Clear stopwatch and timers data SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - Log.v("AlarmInitReceiver - Cleaning old timer and stopwatch data"); - TimerObj.cleanTimersFromSharedPrefs(prefs); + Log.v("AlarmInitReceiver - Reset timers and clear stopwatch data"); + TimerObj.resetTimersInSharedPrefs(prefs); Utils.clearSwSharedPref(prefs); + + if (!prefs.getBoolean(PREF_VOLUME_DEF_DONE, false)) { + // Fix the default + Log.v("AlarmInitReceiver - resetting volume button default"); + switchVolumeButtonDefault(prefs); + } } Alarms.setNextAlert(context); result.finish(); @@ -60,4 +69,15 @@ public class AlarmInitReceiver extends BroadcastReceiver { } }); } + + private void switchVolumeButtonDefault(SharedPreferences prefs) { + SharedPreferences.Editor editor = prefs.edit(); + + editor.putString(SettingsActivity.KEY_VOLUME_BEHAVIOR, + SettingsActivity.DEFAULT_VOLUME_BEHAVIOR); + + // Make sure we do it only once + editor.putBoolean(PREF_VOLUME_DEF_DONE, true); + editor.apply(); + } } diff --git a/src/com/android/deskclock/AlarmKlaxon.java b/src/com/android/deskclock/AlarmKlaxon.java index 94643e683..82494727c 100644 --- a/src/com/android/deskclock/AlarmKlaxon.java +++ b/src/com/android/deskclock/AlarmKlaxon.java @@ -33,6 +33,7 @@ import android.os.Vibrator; import android.preference.PreferenceManager; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; +import android.text.format.DateUtils; import android.util.Log; /** @@ -69,9 +70,10 @@ public class AlarmKlaxon extends Service { public void handleMessage(Message msg) { switch (msg.what) { case KILLER: - Log.d(TAG, "*********** Alarm killer triggered ***********"); - - sendKillBroadcast((Alarm) msg.obj); + if (Log.LOGV) { + Log.v("*********** Alarm killer triggered ***********"); + } + sendKillBroadcast((Alarm) msg.obj, false); stopSelf(); break; case INCVOL: @@ -96,7 +98,7 @@ public class AlarmKlaxon extends Service { // we don't kill the alarm during a call. if (state != TelephonyManager.CALL_STATE_IDLE && state != mInitialCallState) { - sendKillBroadcast(mCurrentAlarm); + sendKillBroadcast(mCurrentAlarm, false); stopSelf(); } } @@ -147,7 +149,7 @@ public class AlarmKlaxon extends Service { } if (mCurrentAlarm != null) { - sendKillBroadcast(mCurrentAlarm); + sendKillBroadcast(mCurrentAlarm, true); } play(alarm); @@ -159,12 +161,13 @@ public class AlarmKlaxon extends Service { return START_STICKY; } - private void sendKillBroadcast(Alarm alarm) { + private void sendKillBroadcast(Alarm alarm, boolean replaced) { long millis = System.currentTimeMillis() - mStartTime; - int minutes = (int) Math.round(millis / 60000.0); + int minutes = (int) Math.round(millis / (double)DateUtils.MINUTE_IN_MILLIS); Intent alarmKilled = new Intent(Alarms.ALARM_KILLED); alarmKilled.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm); alarmKilled.putExtra(Alarms.ALARM_KILLED_TIMEOUT, minutes); + alarmKilled.putExtra(Alarms.ALARM_REPLACED, replaced); sendBroadcast(alarmKilled); } @@ -328,7 +331,7 @@ public class AlarmKlaxon extends Service { int autoSnoozeMinutes = Integer.parseInt(autoSnooze); if (autoSnoozeMinutes != -1) { mHandler.sendMessageDelayed(mHandler.obtainMessage(KILLER, alarm), - 1000 * autoSnoozeMinutes * 60); + autoSnoozeMinutes * DateUtils.MINUTE_IN_MILLIS); } } diff --git a/src/com/android/deskclock/AlarmReceiver.java b/src/com/android/deskclock/AlarmReceiver.java index 003ee09b0..69f726bbb 100644 --- a/src/com/android/deskclock/AlarmReceiver.java +++ b/src/com/android/deskclock/AlarmReceiver.java @@ -116,7 +116,7 @@ public class AlarmReceiver extends BroadcastReceiver { // Intentionally verbose: always log the alarm time to provide useful // information in bug reports. long now = System.currentTimeMillis(); - Log.v("Received alarm set for " + Log.formatTime(alarm.time)); + Log.v("Received alarm set for id=" + alarm.id + " " + Log.formatTime(alarm.time)); // Always verbose to track down time change problems. if (now > alarm.time + STALE_WINDOW) { diff --git a/src/com/android/deskclock/Alarms.java b/src/com/android/deskclock/Alarms.java index c9439e5ea..b9a848cfc 100644 --- a/src/com/android/deskclock/Alarms.java +++ b/src/com/android/deskclock/Alarms.java @@ -78,6 +78,9 @@ public class Alarms { // alarm played before being killed. public static final String ALARM_KILLED_TIMEOUT = "alarm_killed_timeout"; + // Extra in the ALARM_KILLED intent to indicate when alarm was replaced + public static final String ALARM_REPLACED = "alarm_replaced"; + // This string is used to indicate a silent alarm in the db. public static final String ALARM_ALERT_SILENT = "silent"; @@ -427,9 +430,9 @@ public class Alarms { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - if (Log.LOGV) { - Log.v("** setAlert id " + alarm.id + " atTime " + atTimeInMillis); - } + // Intentionally verbose: always log the alarm time to provide useful + // information in bug reports. + Log.v("Alarm set for id=" + alarm.id + " " + Log.formatTime(atTimeInMillis)); Intent intent = new Intent(ALARM_ALERT_ACTION); @@ -477,6 +480,9 @@ public class Alarms { PendingIntent.FLAG_CANCEL_CURRENT); am.cancel(sender); setStatusBarIcon(context, false); + // Intentionally verbose: always log the lack of a next alarm to provide useful + // information in bug reports. + Log.v("No next alarm"); saveNextAlarm(context, ""); } diff --git a/src/com/android/deskclock/AnalogClock.java b/src/com/android/deskclock/AnalogClock.java index 8b1bf9a57..55fff90a8 100644 --- a/src/com/android/deskclock/AnalogClock.java +++ b/src/com/android/deskclock/AnalogClock.java @@ -61,8 +61,8 @@ public class AnalogClock extends View { private String mTimeZoneId; private boolean mNoSeconds = false; - private float mDotRadius; - private float mDotOffset; + private final float mDotRadius; + private final float mDotOffset; private Paint mDotPaint; public AnalogClock(Context context) { @@ -207,47 +207,30 @@ public class AnalogClock extends View { canvas.drawCircle(x, y - (h / 2) + mDotOffset, mDotRadius, mDotPaint); } - canvas.save(); - canvas.rotate(mHour / 12.0f * 360.0f, x, y); - final Drawable hourHand = mHourHand; - if (changed) { - w = hourHand.getIntrinsicWidth(); - h = hourHand.getIntrinsicHeight(); - hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); - } - hourHand.draw(canvas); - canvas.restore(); - + drawHand(canvas, mHourHand, x, y, mHour / 12.0f * 360.0f, changed); + drawHand(canvas, mMinuteHand, x, y, mMinutes / 60.0f * 360.0f, changed); if (!mNoSeconds) { - canvas.save(); - canvas.rotate(mSeconds / 60.0f * 360.0f, x, y); - - final Drawable secondHand = mSecondHand; - if (changed) { - w = secondHand.getIntrinsicWidth(); - h = secondHand.getIntrinsicHeight(); - secondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); - } - secondHand.draw(canvas); - canvas.restore(); - } - canvas.save(); - canvas.rotate(mMinutes / 60.0f * 360.0f, x, y); - - final Drawable minuteHand = mMinuteHand; - if (changed) { - w = minuteHand.getIntrinsicWidth(); - h = minuteHand.getIntrinsicHeight(); - minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); + drawHand(canvas, mSecondHand, x, y, mSeconds / 60.0f * 360.0f, changed); } - minuteHand.draw(canvas); - canvas.restore(); if (scaled) { canvas.restore(); } } + private void drawHand(Canvas canvas, Drawable hand, int x, int y, float angle, + boolean changed) { + canvas.save(); + canvas.rotate(angle, x, y); + if (changed) { + final int w = hand.getIntrinsicWidth(); + final int h = hand.getIntrinsicHeight(); + hand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); + } + hand.draw(canvas); + canvas.restore(); + } + private void onTimeChanged() { mCalendar.setToNow(); diff --git a/src/com/android/deskclock/ClockFragment.java b/src/com/android/deskclock/ClockFragment.java index db3bc8ee8..bd1b581c8 100644 --- a/src/com/android/deskclock/ClockFragment.java +++ b/src/com/android/deskclock/ClockFragment.java @@ -16,7 +16,6 @@ package com.android.deskclock; -import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -27,7 +26,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; -import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -63,23 +61,33 @@ public class ClockFragment extends DeskClockFragment implements OnSharedPreferen private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - boolean changed = intent.getAction().equals(Intent.ACTION_TIME_CHANGED) - || intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED); - if (changed || intent.getAction().equals(Utils.ACTION_ON_QUARTER_HOUR)) { + String action = intent.getAction(); + boolean changed = action.equals(Intent.ACTION_TIME_CHANGED) + || action.equals(Intent.ACTION_TIMEZONE_CHANGED) + || action.equals(Intent.ACTION_LOCALE_CHANGED); + if (changed || action.equals(Utils.ACTION_ON_QUARTER_HOUR)) { Utils.updateDate(mDateFormat, mDateFormatForAccessibility,mClockFrame); if (mAdapter != null) { // *CHANGED may modify the need for showing the Home City if (changed && (mAdapter.hasHomeCity() != mAdapter.needHomeCity())) { - mAdapter.loadData(context); + mAdapter.reloadData(context); } else { mAdapter.notifyDataSetChanged(); } + // Reloading the cities list with new localized names + if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { + mAdapter.loadCitiesDb(context); + mAdapter.notifyDataSetChanged(); + } } } - if (changed || intent.getAction().equals(Alarms.ALARM_DONE_ACTION) - || intent.getAction().equals(Alarms.ALARM_SNOOZE_CANCELLED)) { + if (changed || action.equals(Alarms.ALARM_DONE_ACTION) + || action.equals(Alarms.ALARM_SNOOZE_CANCELLED)) { Utils.refreshAlarm(getActivity(), mClockFrame); } + if (changed) { + mQuarterlyIntent = Utils.refreshAlarmOnQuarterHour(getActivity(), mQuarterlyIntent); + } } }; @@ -153,12 +161,7 @@ public class ClockFragment extends DeskClockFragment implements OnSharedPreferen mDateFormat = getString(R.string.abbrev_wday_month_day_no_year); mDateFormatForAccessibility = getString(R.string.full_wday_month_day_no_year); - long alarmOnQuarterHour = Utils.getAlarmOnQuarterHour(); - mQuarterlyIntent = PendingIntent.getBroadcast( - getActivity(), 0, new Intent(Utils.ACTION_ON_QUARTER_HOUR), 0); - ((AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE)).setRepeating( - AlarmManager.RTC, alarmOnQuarterHour, AlarmManager.INTERVAL_FIFTEEN_MINUTES, - mQuarterlyIntent); + mQuarterlyIntent = Utils.startAlarmOnQuarterHour(getActivity()); // Besides monitoring when quarter-hour changes, monitor other actions that // effect clock time IntentFilter filter = new IntentFilter(Utils.ACTION_ON_QUARTER_HOUR); @@ -166,12 +169,14 @@ public class ClockFragment extends DeskClockFragment implements OnSharedPreferen filter.addAction(Alarms.ALARM_SNOOZE_CANCELLED); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + filter.addAction(Intent.ACTION_LOCALE_CHANGED); getActivity().registerReceiver(mIntentReceiver, filter); mButtons.setAlpha(mButtonsHidden ? 0 : 1); - // Resume can invoked after changing the cities list. + // Resume can invoked after changing the cities list or a change in locale if (mAdapter != null) { + mAdapter.loadCitiesDb(getActivity()); mAdapter.reloadData(getActivity()); } // Resume can invoked after changing the clock style. @@ -189,8 +194,7 @@ public class ClockFragment extends DeskClockFragment implements OnSharedPreferen public void onPause() { super.onPause(); mPrefs.unregisterOnSharedPreferenceChangeListener(this); - ((AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE)).cancel( - mQuarterlyIntent); + Utils.cancelAlarmOnQuarterHour(getActivity(), mQuarterlyIntent); getActivity().unregisterReceiver(mIntentReceiver); } diff --git a/src/com/android/deskclock/DeskClock.java b/src/com/android/deskclock/DeskClock.java index b084dccb0..18b70b07c 100644 --- a/src/com/android/deskclock/DeskClock.java +++ b/src/com/android/deskclock/DeskClock.java @@ -20,6 +20,7 @@ import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.ActivityNotFoundException; import android.content.Context; @@ -28,8 +29,6 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.graphics.drawable.TransitionDrawable; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.preference.PreferenceManager; import android.support.v13.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; @@ -56,6 +55,7 @@ import com.android.deskclock.timer.Timers; import com.android.deskclock.worldclock.CitiesActivity; import java.util.ArrayList; +import java.util.HashSet; import java.util.TimeZone; /** @@ -155,6 +155,7 @@ public class DeskClock extends Activity implements LabelDialogFragment.TimerLabe mStopwatchTab.setContentDescription(R.string.menu_stopwatch); mTabsAdapter.addTab(mStopwatchTab, StopwatchFragment.class,STOPWATCH_TAB_INDEX); mActionBar.setSelectedNavigationItem(selectedIndex); + mTabsAdapter.notifySelectedPage(selectedIndex); } } @@ -303,10 +304,19 @@ public class DeskClock extends Activity implements LabelDialogFragment.TimerLabe Log.v(LOG_TAG, "Setting home time zone to " + homeTimeZone); } - public boolean isClockTab() { - return mViewPager.getCurrentItem() == CLOCK_TAB_INDEX; + public void registerPageChangedListener(DeskClockFragment frag) { + if (mTabsAdapter != null) { + mTabsAdapter.registerPageChangedListener(frag); + } + } + + public void unregisterPageChangedListener(DeskClockFragment frag) { + if (mTabsAdapter != null) { + mTabsAdapter.unregisterPageChangedListener(frag); + } } + /*** * Adapter for wrapping together the ActionBar's tab with the ViewPager */ @@ -335,6 +345,8 @@ public class DeskClock extends Activity implements LabelDialogFragment.TimerLabe ActionBar mMainActionBar; Context mContext; ViewPager mPager; + // Used for doing callbacks to fragments. + HashSet<String> mFragmentTags = new HashSet<String>(); public TabsAdapter(Activity activity, ViewPager pager) { super(activity.getFragmentManager()); @@ -375,6 +387,7 @@ public class DeskClock extends Activity implements LabelDialogFragment.TimerLabe @Override public void onPageSelected(int position) { mMainActionBar.setSelectedNavigationItem(position); + notifyPageChanged(position); } @Override @@ -399,14 +412,44 @@ public class DeskClock extends Activity implements LabelDialogFragment.TimerLabe // Do nothing } + + public void notifySelectedPage(int page) { + notifyPageChanged(page); + } + + private void notifyPageChanged(int newPage) { + for (String tag : mFragmentTags) { + final FragmentManager fm = getFragmentManager(); + DeskClockFragment f = (DeskClockFragment) fm.findFragmentByTag(tag); + if (f != null) { + f.onPageChanged(newPage); + } + } + } + + public void registerPageChangedListener(DeskClockFragment frag) { + String tag = frag.getTag(); + if (mFragmentTags.contains(tag)) { + Log.wtf(LOG_TAG, "Trying to add an existing fragment " + tag); + } else { + mFragmentTags.add(frag.getTag()); + } + // Since registering a listener by the fragment is done sometimes after the page + // was already changed, make sure the fragment gets the current page + frag.onPageChanged(mMainActionBar.getSelectedNavigationIndex()); + } + + public void unregisterPageChangedListener(DeskClockFragment frag) { + mFragmentTags.remove(frag.getTag()); + } } public static abstract class OnTapListener implements OnTouchListener { private float mLastTouchX; private float mLastTouchY; private long mLastTouchTime; - private TextView mMakePressedTextView; - private int mPressedColor, mGrayColor; + private final TextView mMakePressedTextView; + private final int mPressedColor, mGrayColor; private final float MAX_MOVEMENT_ALLOWED = 20; private final long MAX_TIME_ALLOWED = 500; diff --git a/src/com/android/deskclock/DeskClockFragment.java b/src/com/android/deskclock/DeskClockFragment.java index 4df2fccd2..dcf7f7c3a 100644 --- a/src/com/android/deskclock/DeskClockFragment.java +++ b/src/com/android/deskclock/DeskClockFragment.java @@ -17,19 +17,10 @@ package com.android.deskclock; import android.app.Fragment; -import android.content.Context; public class DeskClockFragment extends Fragment { - protected Context mContext; - private boolean mButtonClicked = false; - protected void buttonClicked(boolean state) { - mButtonClicked = state; - } - - public boolean isButtonClicked() { - boolean res = mButtonClicked; - mButtonClicked = false; - return res; + public void onPageChanged(int page) { + // Do nothing here , only in derived classes } } diff --git a/src/com/android/deskclock/Log.java b/src/com/android/deskclock/Log.java index 39e7e3491..e075442bf 100644 --- a/src/com/android/deskclock/Log.java +++ b/src/com/android/deskclock/Log.java @@ -55,6 +55,6 @@ public class Log { } public static String formatTime(long millis) { - return new SimpleDateFormat("HH:mm:ss.SSS aaa").format(new Date(millis)); + return new SimpleDateFormat("HH:mm:ss.SSS/E").format(new Date(millis)); } } diff --git a/src/com/android/deskclock/ScreensaverActivity.java b/src/com/android/deskclock/ScreensaverActivity.java index 814888a9d..c75e1fc2a 100644 --- a/src/com/android/deskclock/ScreensaverActivity.java +++ b/src/com/android/deskclock/ScreensaverActivity.java @@ -16,44 +16,23 @@ package com.android.deskclock; -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; -import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; import android.os.BatteryManager; -import android.os.Bundle; import android.os.Handler; -import android.preference.PreferenceManager; -import android.provider.Settings; -import android.service.dreams.DreamService; -import android.text.TextUtils; -import android.text.format.DateFormat; import android.util.Log; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.widget.TextView; import com.android.deskclock.Utils.ScreensaverMoveSaverRunnable; -import java.util.Calendar; - public class ScreensaverActivity extends Activity { static final boolean DEBUG = false; static final String TAG = "DeskClock/ScreensaverActivity"; @@ -96,6 +75,8 @@ public class ScreensaverActivity extends Activity { if (changed) { Utils.refreshAlarm(ScreensaverActivity.this, mContentView); + mQuarterlyIntent = Utils.refreshAlarmOnQuarterHour( + ScreensaverActivity.this, mQuarterlyIntent); } } @@ -136,18 +117,13 @@ public class ScreensaverActivity extends Activity { layoutClockSaver(); mHandler.post(mMoveSaverRunnable); - long alarmOnQuarterHour = Utils.getAlarmOnQuarterHour(); - mQuarterlyIntent = PendingIntent.getBroadcast( - this, 0, new Intent(Utils.ACTION_ON_QUARTER_HOUR), 0); - ((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setRepeating( - AlarmManager.RTC, alarmOnQuarterHour, AlarmManager.INTERVAL_FIFTEEN_MINUTES, - mQuarterlyIntent); + mQuarterlyIntent = Utils.startAlarmOnQuarterHour(this); } @Override public void onPause() { mHandler.removeCallbacks(mMoveSaverRunnable); - ((AlarmManager) getSystemService(Context.ALARM_SERVICE)).cancel(mQuarterlyIntent); + Utils.cancelAlarmOnQuarterHour(this, mQuarterlyIntent); finish(); super.onPause(); } diff --git a/src/com/android/deskclock/SettingsActivity.java b/src/com/android/deskclock/SettingsActivity.java index bf2aa7ccb..11ee6bc4f 100644 --- a/src/com/android/deskclock/SettingsActivity.java +++ b/src/com/android/deskclock/SettingsActivity.java @@ -17,6 +17,7 @@ package com.android.deskclock; import android.app.ActionBar; +import android.content.Intent; import android.content.res.Resources; import android.media.AudioManager; import android.os.Bundle; @@ -30,6 +31,11 @@ import android.text.format.DateUtils; import android.view.Menu; import android.view.MenuItem; +import com.android.deskclock.worldclock.Cities; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.TimeZone; /** @@ -66,10 +72,11 @@ public class SettingsActivity extends PreferenceActivity static final String KEY_VOLUME_BUTTONS = "volume_button_setting"; + public static final String DEFAULT_VOLUME_BEHAVIOR = "0"; + private static CharSequence[][] mTimezones; private long mTime; - private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -164,10 +171,12 @@ public class SettingsActivity extends PreferenceActivity final ListPreference listPref = (ListPreference) pref; final int idx = listPref.findIndexOfValue((String) newValue); listPref.setSummary(listPref.getEntries()[idx]); + notifyHomeTimeZoneChanged(); } else if (KEY_AUTO_HOME_CLOCK.equals(pref.getKey())) { boolean state =((CheckBoxPreference) pref).isChecked(); Preference homeTimeZone = findPreference(KEY_HOME_TZ); homeTimeZone.setEnabled(!state); + notifyHomeTimeZoneChanged(); } else if (KEY_VOLUME_BUTTONS.equals(pref.getKey())) { final ListPreference listPref = (ListPreference) pref; final int idx = listPref.findIndexOfValue((String) newValue); @@ -204,6 +213,12 @@ public class SettingsActivity extends PreferenceActivity getResources().getStringArray(R.array.action_summary_entries)[i])); } + private void notifyHomeTimeZoneChanged() { + Intent i = new Intent(Cities.WORLDCLOCK_UPDATE_INTENT); + sendBroadcast(i); + } + + private void refresh() { ListPreference listPref = (ListPreference) findPreference(KEY_AUTO_SILENCE); String delay = listPref.getValue(); @@ -240,6 +255,52 @@ public class SettingsActivity extends PreferenceActivity SnoozeLengthDialog snoozePref = (SnoozeLengthDialog) findPreference(KEY_ALARM_SNOOZE); snoozePref.setSummary(); } + + private class TimeZoneRow implements Comparable<TimeZoneRow> { + private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false; + + public final String mId; + public final String mDisplayName; + public final int mOffset; + + public TimeZoneRow(String id, String name) { + mId = id; + TimeZone tz = TimeZone.getTimeZone(id); + boolean useDaylightTime = tz.useDaylightTime(); + mOffset = tz.getOffset(mTime); + mDisplayName = buildGmtDisplayName(id, name, useDaylightTime); + } + + @Override + public int compareTo(TimeZoneRow another) { + return mOffset - another.mOffset; + } + + public String buildGmtDisplayName(String id, String displayName, boolean useDaylightTime) { + int p = Math.abs(mOffset); + StringBuilder name = new StringBuilder("(GMT"); + name.append(mOffset < 0 ? '-' : '+'); + + name.append(p / DateUtils.HOUR_IN_MILLIS); + name.append(':'); + + int min = p / 60000; + min %= 60; + + if (min < 10) { + name.append('0'); + } + name.append(min); + name.append(") "); + name.append(displayName); + if (useDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) { + name.append(" \u2600"); // Sun symbol + } + return name.toString(); + } + } + + /** * Returns an array of ids/time zones. This returns a double indexed array * of ids and time zones for Calendar. It is an inefficient method and @@ -255,44 +316,19 @@ public class SettingsActivity extends PreferenceActivity if (ids.length != labels.length) { Log.wtf("Timezone ids and labels have different length!"); } - CharSequence[][] timeZones = new CharSequence[2][ids.length]; + List<TimeZoneRow> timezones = new ArrayList<TimeZoneRow>(); for (int i = 0; i < ids.length; i++) { - timeZones[0][i] = ids[i]; - timeZones[1][i] = buildGmtDisplayName(ids[i], labels[i]); - } - return timeZones; - } - - public String buildGmtDisplayName(String id, String displayName) { - TimeZone tz = TimeZone.getTimeZone(id); - boolean mUseDaylightTime = tz.useDaylightTime(); - int mOffset = tz.getOffset(mTime); - int p = Math.abs(mOffset); - StringBuilder name = new StringBuilder(); - name.append("GMT"); - - if (mOffset < 0) { - name.append('-'); - } else { - name.append('+'); + timezones.add(new TimeZoneRow(ids[i], labels[i])); } + Collections.sort(timezones); - name.append(p / (DateUtils.HOUR_IN_MILLIS)); - name.append(':'); - - int min = p / 60000; - min %= 60; - - if (min < 10) { - name.append('0'); - } - name.append(min); - name.insert(0, "("); - name.append(") "); - name.append(displayName); - if (mUseDaylightTime && SHOW_DAYLIGHT_SAVINGS_INDICATOR) { - name.append(" \u2600"); // Sun symbol + CharSequence[][] timeZones = new CharSequence[2][timezones.size()]; + int i = 0; + for (TimeZoneRow row : timezones) { + timeZones[0][i] = row.mId; + timeZones[1][i++] = row.mDisplayName; } - return name.toString(); + return timeZones; } + } diff --git a/src/com/android/deskclock/Utils.java b/src/com/android/deskclock/Utils.java index fcc2c7f22..ff05d2638 100644 --- a/src/com/android/deskclock/Utils.java +++ b/src/com/android/deskclock/Utils.java @@ -20,11 +20,14 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; +import android.app.AlarmManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -44,8 +47,12 @@ import android.widget.TextView; import com.android.deskclock.stopwatch.Stopwatches; import com.android.deskclock.timer.Timers; +import com.android.deskclock.worldclock.CityObj; +import java.text.Collator; +import java.util.Arrays; import java.util.Calendar; +import java.util.Comparator; import java.util.Locale; @@ -308,7 +315,7 @@ public class Utils { } /** Setup to find out when the quarter-hour changes (e.g. Kathmandu is GMT+5:45) **/ - public static long getAlarmOnQuarterHour() { + private static long getAlarmOnQuarterHour() { Calendar nextQuarter = Calendar.getInstance(); // Set 1 second to ensure quarter-hour threshold passed. nextQuarter.set(Calendar.SECOND, 1); @@ -322,6 +329,33 @@ public class Utils { return alarmOnQuarterHour; } + /** Setup alarm refresh when the quarter-hour changes **/ + public static PendingIntent startAlarmOnQuarterHour(Context context) { + if (context != null) { + PendingIntent quarterlyIntent = PendingIntent.getBroadcast( + context, 0, new Intent(Utils.ACTION_ON_QUARTER_HOUR), 0); + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setRepeating( + AlarmManager.RTC, getAlarmOnQuarterHour(), + AlarmManager.INTERVAL_FIFTEEN_MINUTES, quarterlyIntent); + return quarterlyIntent; + } else { + return null; + } + } + + public static void cancelAlarmOnQuarterHour(Context context, PendingIntent quarterlyIntent) { + if (quarterlyIntent != null && context != null) { + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel( + quarterlyIntent); + } + } + + public static PendingIntent refreshAlarmOnQuarterHour( + Context context, PendingIntent quarterlyIntent) { + cancelAlarmOnQuarterHour(context, quarterlyIntent); + return startAlarmOnQuarterHour(context); + } + /** * For screensavers to set whether the digital or analog clock should be displayed. * Returns the view to be displayed. @@ -390,4 +424,34 @@ public class Utils { } } + public static CityObj[] loadCitiesDataBase(Context c) { + final Collator collator = Collator.getInstance(); + Resources r = c.getResources(); + // Read strings array of name,timezone, id + // make sure the list are the same length + String[] cities = r.getStringArray(R.array.cities_names); + String[] timezones = r.getStringArray(R.array.cities_tz); + String[] ids = r.getStringArray(R.array.cities_id); + if (cities.length != timezones.length || ids.length != cities.length) { + Log.wtf("City lists sizes are not the same, cannot use the data"); + return null; + } + CityObj[] tempList = new CityObj[cities.length]; + for (int i = 0; i < cities.length; i++) { + tempList[i] = new CityObj(cities[i], timezones[i], ids[i]); + } + // Sort alphabetically + Arrays.sort(tempList, new Comparator<CityObj> () { + @Override + public int compare(CityObj c1, CityObj c2) { + Comparator<CityObj> mCollator; + return collator.compare(c1.mCityName, c2.mCityName); + } + }); + return tempList; + } + + public static String getCityName(CityObj city, CityObj dbCity) { + return (city.mCityId == null || dbCity == null) ? city.mCityName : dbCity.mCityName; + } } diff --git a/src/com/android/deskclock/stopwatch/StopwatchFragment.java b/src/com/android/deskclock/stopwatch/StopwatchFragment.java index b751cc048..6a8aa5140 100644 --- a/src/com/android/deskclock/stopwatch/StopwatchFragment.java +++ b/src/com/android/deskclock/stopwatch/StopwatchFragment.java @@ -9,7 +9,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.preference.PreferenceManager; +import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,7 +20,6 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListPopupWindow; @@ -28,7 +30,6 @@ import android.widget.TextView; import com.android.deskclock.CircleButtonsLinearLayout; import com.android.deskclock.CircleTimerView; import com.android.deskclock.DeskClock; -import com.android.deskclock.DeskClock.OnTapListener; import com.android.deskclock.DeskClockFragment; import com.android.deskclock.Log; import com.android.deskclock.R; @@ -38,10 +39,10 @@ import com.android.deskclock.timer.CountingTimerView; import java.util.ArrayList; import java.util.List; -/** - * TODO: Insert description here. (generated by isaackatz) - */ -public class StopwatchFragment extends DeskClockFragment implements OnSharedPreferenceChangeListener{ +public class StopwatchFragment extends DeskClockFragment + implements OnSharedPreferenceChangeListener { + + private static final String TAG = "StopwatchFragment"; int mState = Stopwatches.STOPWATCH_RESET; // Stopwatch views that are accessed by the activity @@ -52,6 +53,7 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref private ListView mLapsList; private ImageButton mShareButton; private ListPopupWindow mSharePopup; + private WakeLock mWakeLock; // Used for calculating the time from the start taking into account the pause times long mStartTime = 0; @@ -78,10 +80,26 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref ArrayList<Lap> mLaps = new ArrayList<Lap>(); private final LayoutInflater mInflater; private final int mBackgroundColor; + private final String[] mFormats; + private final String[] mLapFormatSet; + // Size of this array must match the size of formats + private final long[] mThresholds = { + 10 * DateUtils.MINUTE_IN_MILLIS, // < 10 minutes + DateUtils.HOUR_IN_MILLIS, // < 1 hour + 10 * DateUtils.HOUR_IN_MILLIS, // < 10 hours + 100 * DateUtils.HOUR_IN_MILLIS, // < 100 hours + 1000 * DateUtils.HOUR_IN_MILLIS // < 1000 hours + }; + private int mLapIndex = 0; + private int mTotalIndex = 0; + private String mLapFormat; public LapsListAdapter(Context context) { mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mBackgroundColor = getResources().getColor(R.color.blackish); + mFormats = context.getResources().getStringArray(R.array.stopwatch_format_set); + mLapFormatSet = context.getResources().getStringArray(R.array.sw_lap_number_set); + updateLapFormat(); } @Override @@ -103,10 +121,11 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref TextView count = (TextView)lapInfo.findViewById(R.id.lap_number); TextView lapTime = (TextView)lapInfo.findViewById(R.id.lap_time); TextView toalTime = (TextView)lapInfo.findViewById(R.id.lap_total); - lapTime.setText(Stopwatches.getTimeText(mLaps.get(position).mLapTime)); - toalTime.setText(Stopwatches.getTimeText(mLaps.get(position).mTotalTime)); - count.setText(getString(R.string.sw_notification_lap_number, mLaps.size() - position) - .toUpperCase()); + lapTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mLapTime, + mFormats[mLapIndex])); + toalTime.setText(Stopwatches.formatTimeText(mLaps.get(position).mTotalTime, + mFormats[mTotalIndex])); + count.setText(String.format(mLapFormat, mLaps.size() - position).toUpperCase()); lapInfo.setBackgroundColor(mBackgroundColor); return lapInfo; @@ -125,13 +144,38 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref return mLaps.get(position); } + private void updateLapFormat() { + // Note Stopwatches.MAX_LAPS < 100 + mLapFormat = mLapFormatSet[mLaps.size() < 10 ? 0 : 1]; + } + + private void resetTimeFormats() { + mLapIndex = mTotalIndex = 0; + } + + public boolean updateTimeFormats(Lap lap) { + boolean formatChanged = false; + while (mLapIndex + 1 < mThresholds.length && lap.mLapTime >= mThresholds[mLapIndex]) { + mLapIndex++; + formatChanged = true; + } + while (mTotalIndex + 1 < mThresholds.length && + lap.mTotalTime >= mThresholds[mTotalIndex]) { + mTotalIndex++; + formatChanged = true; + } + return formatChanged; + } + public void addLap(Lap l) { mLaps.add(0, l); - notifyDataSetChanged(); + // for efficiency caller also calls notifyDataSetChanged() } public void clearLaps() { mLaps.clear(); + updateLapFormat(); + resetTimeFormats(); notifyDataSetChanged(); } @@ -163,7 +207,9 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref for (int i = size -1; i >= 0; i --) { totalTime += laps[i]; mLaps.get(i).mTotalTime = totalTime; + updateTimeFormats(mLaps.get(i)); } + updateLapFormat(); notifyDataSetChanged(); } } @@ -185,7 +231,6 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref Intent intent = new Intent(context, StopwatchService.class); intent.putExtra(Stopwatches.MESSAGE_TIME, time); intent.putExtra(Stopwatches.SHOW_NOTIF, false); - buttonClicked(true); switch (mState) { case Stopwatches.STOPWATCH_RUNNING: // do stop @@ -194,6 +239,7 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref doStop(); intent.setAction(Stopwatches.STOP_STOPWATCH); context.startService(intent); + releaseWakeLock(); break; case Stopwatches.STOPWATCH_RESET: case Stopwatches.STOPWATCH_STOPPED: @@ -201,6 +247,7 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref doStart(time); intent.setAction(Stopwatches.START_STOPWATCH); context.startService(intent); + acquireWakeLock(); break; default: Log.wtf("Illegal state " + mState @@ -224,7 +271,6 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref Intent intent = new Intent(context, StopwatchService.class); intent.putExtra(Stopwatches.MESSAGE_TIME, time); intent.putExtra(Stopwatches.SHOW_NOTIF, false); - buttonClicked(true); switch (mState) { case Stopwatches.STOPWATCH_RUNNING: // Save lap time @@ -238,6 +284,7 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref doReset(); intent.setAction(Stopwatches.RESET_STOPWATCH); context.startService(intent); + releaseWakeLock(); break; default: Log.wtf("Illegal state " + mState @@ -300,12 +347,13 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref setButtons(mState); mTimeText.setTime(mAccumulatedTime, true, true); if (mState == Stopwatches.STOPWATCH_RUNNING) { + acquireWakeLock(); startUpdateThread(); } else if (mState == Stopwatches.STOPWATCH_STOPPED && mAccumulatedTime != 0) { mTimeText.blinkTimeStr(true); } showLaps(); - + ((DeskClock)getActivity()).registerPageChangedListener(this); super.onResume(); } @@ -325,10 +373,20 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref mSharePopup.dismiss(); mSharePopup = null; } - + ((DeskClock)getActivity()).unregisterPageChangedListener(this); + releaseWakeLock(); super.onPause(); } + @Override + public void onPageChanged(int page) { + if (page == DeskClock.STOPWATCH_TAB_INDEX && mState == Stopwatches.STOPWATCH_RUNNING) { + acquireWakeLock(); + } else { + releaseWakeLock(); + } + } + private void doStop() { stopUpdateThread(); mTime.pauseIntervalAnimation(); @@ -555,15 +613,18 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref long curTime = time - mStartTime + mAccumulatedTime; if (size == 0) { // Always show the ending lap and a new one - mLapsAdapter.addLap(new Lap(curTime, curTime)); + Lap firstLap = new Lap(curTime, curTime); + mLapsAdapter.addLap(firstLap); mLapsAdapter.addLap(new Lap(0, curTime)); mTime.setIntervalTime(curTime); + mLapsAdapter.updateTimeFormats(firstLap); } else { long lapTime = curTime - ((Lap) mLapsAdapter.getItem(1)).mTotalTime; ((Lap)mLapsAdapter.getItem(0)).mLapTime = lapTime; ((Lap)mLapsAdapter.getItem(0)).mTotalTime = curTime; mLapsAdapter.addLap(new Lap(0, 0)); mTime.setMarkerTime(lapTime); + mLapsAdapter.updateLapFormat(); // mTime.setIntervalTime(lapTime * 10); } mLapsAdapter.notifyDataSetChanged(); @@ -743,4 +804,24 @@ public class StopwatchFragment extends DeskClockFragment implements OnSharedPref } } } + + // Used to keeps screen on when stopwatch is running. + + private void acquireWakeLock() { + if (mWakeLock == null) { + final PowerManager pm = + (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG); + mWakeLock.setReferenceCounted(false); + } + mWakeLock.acquire(); + } + + private void releaseWakeLock() { + if (mWakeLock != null && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + } diff --git a/src/com/android/deskclock/stopwatch/Stopwatches.java b/src/com/android/deskclock/stopwatch/Stopwatches.java index d8d0741d5..94af594b4 100644 --- a/src/com/android/deskclock/stopwatch/Stopwatches.java +++ b/src/com/android/deskclock/stopwatch/Stopwatches.java @@ -19,7 +19,6 @@ package com.android.deskclock.stopwatch; import android.content.Context; import com.android.deskclock.R; -import com.android.deskclock.stopwatch.StopwatchFragment.Lap; public class Stopwatches { // Private actions processed by the receiver @@ -107,4 +106,23 @@ public class Stopwatches { return timeStr; } + /*** + * Sets the string of the time running on the stopwatch up to hundred of a second accuracy + * @param time - in hundreds of a second since the stopwatch started + */ + public static String formatTimeText(long time, final String format) { + if (time < 0) { + time = 0; + } + long hundreds, seconds, minutes, hours; + seconds = time / 1000; + hundreds = (time - seconds * 1000) / 10; + minutes = seconds / 60; + seconds = seconds - minutes * 60; + hours = minutes / 60; + minutes = minutes - hours * 60; + String timeStr = String.format(format, hours, minutes, seconds, hundreds); + return timeStr; + } + } diff --git a/src/com/android/deskclock/timer/CountingTimerView.java b/src/com/android/deskclock/timer/CountingTimerView.java index 14b4afa81..417e9b18b 100644 --- a/src/com/android/deskclock/timer/CountingTimerView.java +++ b/src/com/android/deskclock/timer/CountingTimerView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,14 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Typeface; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityManager; import android.widget.TextView; -import com.android.deskclock.DeskClock; +import com.android.deskclock.Log; import com.android.deskclock.R; import com.android.deskclock.Utils; @@ -42,17 +43,19 @@ public class CountingTimerView extends View { // vertically center. private static final float FONT_VERTICAL_OFFSET = 0.14f; - private String mHours, mMinutes, mSeconds, mHunderdths; - private final String mHoursLabel, mMinutesLabel, mSecondsLabel; - private float mHoursWidth, mMinutesWidth, mSecondsWidth, mHundredthsWidth; - private float mHoursLabelWidth, mMinutesLabelWidth, mSecondsLabelWidth, mHundredthsSepWidth; + private String mHours, mMinutes, mSeconds, mHundredths; private boolean mShowTimeStr = true; - private final Typeface mAndroidClockMonoThin, mAndroidClockMonoBold, mRobotoLabel, mAndroidClockMonoLight; + private final Typeface mAndroidClockMonoThin, mAndroidClockMonoBold, mAndroidClockMonoLight; + private final Typeface mRobotoLabel; private final Paint mPaintBig = new Paint(); private final Paint mPaintBigThin = new Paint(); private final Paint mPaintMed = new Paint(); private final Paint mPaintLabel = new Paint(); + private final float mBigFontSize, mSmallFontSize; + private SignedTime mBigHours, mBigMinutes; + private UnsignedTime mBigThinSeconds; + private Hundredths mMedHundredths; private float mTextHeight = 0; private float mTotalTextWidth; private static final String HUNDREDTH_SEPERATOR = "."; @@ -80,6 +83,151 @@ public class CountingTimerView extends View { }; + class UnsignedTime { + protected Paint mPaint; + protected float mEm; + protected float mWidth = 0; + private String mWidest; + protected String mLabel; + private float mLabelWidth = 0; + + public UnsignedTime(Paint paint, final String label, String allDigits) { + mPaint = paint; + mLabel = label; + + if (TextUtils.isEmpty(allDigits)) { + Log.wtf("Locale digits missing - using English"); + allDigits = "0123456789"; + } + + float widths[] = new float[allDigits.length()]; + int ll = mPaint.getTextWidths(allDigits, widths); + int largest = 0; + for (int ii = 1; ii < ll; ii++) { + if (widths[ii] > widths[largest]) { + largest = ii; + } + } + + mEm = widths[largest]; + mWidest = allDigits.substring(largest, largest + 1); + } + + public UnsignedTime(UnsignedTime unsignedTime, final String label) { + this.mPaint = unsignedTime.mPaint; + this.mEm = unsignedTime.mEm; + this.mWidth = unsignedTime.mWidth; + this.mWidest = unsignedTime.mWidest; + this.mLabel = label; + } + + protected void updateWidth(final String time) { + mEm = mPaint.measureText(mWidest); + mLabelWidth = mLabel == null ? 0 : mPaintLabel.measureText(mLabel); + mWidth = time.length() * mEm; + } + + protected void resetWidth() { + mWidth = mLabelWidth = 0; + } + + public float calcTotalWidth(final String time) { + if (time != null) { + updateWidth(time); + return mWidth + mLabelWidth; + } else { + resetWidth(); + return 0; + } + } + + public float getWidth() { + return mWidth; + } + + public float getLabelWidth() { + return mLabelWidth; + } + + protected float drawTime(Canvas canvas, final String time, int ii, float x, float y) { + float textEm = mEm / 2f; + while (ii < time.length()) { + x += textEm; + canvas.drawText(time.substring(ii, ii + 1), x, y, mPaint); + x += textEm; + ii++; + } + return x; + } + + public float draw(Canvas canvas, final String time, float x, float y, float yLabel) { + x = drawTime(canvas, time, 0, x, y); + if (mLabel != null ) { + canvas.drawText(mLabel, x, yLabel, mPaintLabel); + } + return x + getLabelWidth(); + } + } + + class Hundredths extends UnsignedTime { + public Hundredths(Paint paint, final String label, final String allDigits) { + super(paint, label, allDigits); + } + + @Override + public float draw(Canvas canvas, final String time, float x, float y, float yLabel) { + if (mLabel != null) { + canvas.drawText(mLabel, x, yLabel, mPaintLabel); + } + return drawTime(canvas, time, 0, x + getLabelWidth(), y); + } + } + + class SignedTime extends UnsignedTime { + private float mMinusWidth = 0; + + public SignedTime(Paint paint, final String label, final String allDigits) { + super(paint, label, allDigits); + } + + public SignedTime (SignedTime signedTime, final String label) { + super(signedTime, label); + } + + @Override + protected void updateWidth(final String time) { + super.updateWidth(time); + if (time.contains("-")) { + mMinusWidth = mPaint.measureText("-"); + mWidth += (mMinusWidth - mEm); + } else { + mMinusWidth = 0; + } + } + + @Override + protected void resetWidth() { + super.resetWidth(); + mMinusWidth = 0; + } + + @Override + public float draw(Canvas canvas, final String time, float x, float y, float yLabel) { + int ii = 0; + if (mMinusWidth != 0f) { + float minusWidth = mMinusWidth / 2; + x += minusWidth; + canvas.drawText(time.substring(ii, ii + 1), x, y, mPaint); + x += minusWidth; + ii++; + } + x = drawTime(canvas, time, ii, x, y); + if (mLabel != null) { + canvas.drawText(mLabel, x, yLabel, mPaintLabel); + } + return x + getLabelWidth(); + } + } public CountingTimerView(Context context) { this(context, null); @@ -87,16 +235,16 @@ public class CountingTimerView extends View { public CountingTimerView(Context context, AttributeSet attrs) { super(context, attrs); - mAndroidClockMonoThin = Typeface.createFromAsset(context.getAssets(),"fonts/AndroidClockMono-Thin.ttf"); - mAndroidClockMonoBold = Typeface.createFromAsset(context.getAssets(),"fonts/AndroidClockMono-Bold.ttf"); - mAndroidClockMonoLight = Typeface.createFromAsset(context.getAssets(),"fonts/AndroidClockMono-Light.ttf"); + mAndroidClockMonoThin = Typeface.createFromAsset( + context.getAssets(), "fonts/AndroidClockMono-Thin.ttf"); + mAndroidClockMonoBold = Typeface.createFromAsset( + context.getAssets(), "fonts/AndroidClockMono-Bold.ttf"); + mAndroidClockMonoLight = Typeface.createFromAsset( + context.getAssets(), "fonts/AndroidClockMono-Light.ttf"); mAccessibilityManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); mRobotoLabel= Typeface.create("sans-serif-condensed", Typeface.BOLD); Resources r = context.getResources(); - mHoursLabel = r.getString(R.string.hours_label).toUpperCase(); - mMinutesLabel = r.getString(R.string.minutes_label).toUpperCase(); - mSecondsLabel = r.getString(R.string.seconds_label).toUpperCase(); mWhiteColor = r.getColor(R.color.clock_white); mDefaultColor = mWhiteColor; mPressedColor = r.getColor(Utils.getPressedColorId()); @@ -104,23 +252,20 @@ public class CountingTimerView extends View { mPaintBig.setAntiAlias(true); mPaintBig.setStyle(Paint.Style.STROKE); - mPaintBig.setTextAlign(Paint.Align.LEFT); + mPaintBig.setTextAlign(Paint.Align.CENTER); mPaintBig.setTypeface(mAndroidClockMonoBold); - float bigFontSize = r.getDimension(R.dimen.big_font_size); - mPaintBig.setTextSize(bigFontSize); - mTextHeight = bigFontSize; + mBigFontSize = r.getDimension(R.dimen.big_font_size); + mSmallFontSize = r.getDimension(R.dimen.small_font_size); mPaintBigThin.setAntiAlias(true); mPaintBigThin.setStyle(Paint.Style.STROKE); - mPaintBigThin.setTextAlign(Paint.Align.LEFT); + mPaintBigThin.setTextAlign(Paint.Align.CENTER); mPaintBigThin.setTypeface(mAndroidClockMonoThin); - mPaintBigThin.setTextSize(r.getDimension(R.dimen.big_font_size)); mPaintMed.setAntiAlias(true); mPaintMed.setStyle(Paint.Style.STROKE); - mPaintMed.setTextAlign(Paint.Align.LEFT); + mPaintMed.setTextAlign(Paint.Align.CENTER); mPaintMed.setTypeface(mAndroidClockMonoLight); - mPaintMed.setTextSize(r.getDimension(R.dimen.small_font_size)); mPaintLabel.setAntiAlias(true); mPaintLabel.setStyle(Paint.Style.STROKE); @@ -128,7 +273,25 @@ public class CountingTimerView extends View { mPaintLabel.setTypeface(mRobotoLabel); mPaintLabel.setTextSize(r.getDimension(R.dimen.label_font_size)); + resetTextSize(); setTextColor(mDefaultColor); + + // allDigits will contain ten digits: "0123456789" in the default locale + final String allDigits = String.format("%010d", 123456789); + mBigHours = new SignedTime(mPaintBig, + r.getString(R.string.hours_label).toUpperCase(), allDigits); + mBigMinutes = new SignedTime(mBigHours, + r.getString(R.string.minutes_label).toUpperCase()); + mBigThinSeconds = new UnsignedTime(mPaintBigThin, + r.getString(R.string.seconds_label).toUpperCase(), allDigits); + mMedHundredths = new Hundredths(mPaintMed, HUNDREDTH_SEPERATOR, allDigits); + } + + protected void resetTextSize() { + mPaintBig.setTextSize(mBigFontSize); + mTextHeight = mBigFontSize; + mPaintBigThin.setTextSize(mBigFontSize); + mPaintMed.setTextSize(mSmallFontSize); } protected void setTextColor(int textColor) { @@ -152,7 +315,7 @@ public class CountingTimerView extends View { seconds = seconds - minutes * 60; hours = minutes / 60; minutes = minutes - hours * 60; - if (hours > 99) { + if (hours > 999) { hours = 0; } // time may less than a second below zero, since we do not show fractions of seconds @@ -160,7 +323,7 @@ public class CountingTimerView extends View { if (hours ==0 && minutes == 0 && seconds == 0) { showNeg = false; } - // TODO: must build to account for localization + if (!showHundredths) { if (!neg && hundreds != 0) { seconds++; @@ -178,6 +341,8 @@ public class CountingTimerView extends View { } } + int oldLength = getDigitsLength(); + if (hours >= 10) { format = showNeg ? NEG_TWO_DIGITS : TWO_DIGITS; mHours = String.format(format, hours); @@ -198,11 +363,18 @@ public class CountingTimerView extends View { mSeconds = String.format(TWO_DIGITS, seconds); if (showHundredths) { - mHunderdths = String.format(TWO_DIGITS, hundreds); + mHundredths = String.format(TWO_DIGITS, hundreds); } else { - mHunderdths = null; + mHundredths = null; + } + + int newLength = getDigitsLength(); + if (oldLength != newLength) { + if (oldLength > newLength) { + resetTextSize(); + } + mRemeasureText = true; } - mRemeasureText = true; if (update) { setContentDescription(getTimeStringForAccessibility((int) hours, (int) minutes, @@ -210,56 +382,47 @@ public class CountingTimerView extends View { invalidate(); } } - private void setTotalTextWidth() { - mTotalTextWidth = 0; - if (mHours != null) { - mHoursWidth = mPaintBig.measureText(mHours); - mTotalTextWidth += mHoursWidth; - mHoursLabelWidth = mPaintLabel.measureText(mHoursLabel); - mTotalTextWidth += mHoursLabelWidth; - } - if (mMinutes != null) { - mMinutesWidth = mPaintBig.measureText(mMinutes); - mTotalTextWidth += mMinutesWidth; - mMinutesLabelWidth = mPaintLabel.measureText(mMinutesLabel); - mTotalTextWidth += mMinutesLabelWidth; - } - if (mSeconds != null) { - mSecondsWidth = mPaintBigThin.measureText(mSeconds); - mTotalTextWidth += mSecondsWidth; - mSecondsLabelWidth = mPaintLabel.measureText(mSecondsLabel); - mTotalTextWidth += mSecondsLabelWidth; - } - if (mHunderdths != null) { - mHundredthsWidth = mPaintMed.measureText(mHunderdths); - mTotalTextWidth += mHundredthsWidth; - mHundredthsSepWidth = mPaintLabel.measureText(HUNDREDTH_SEPERATOR); - mTotalTextWidth += mHundredthsSepWidth; - } - // This is a hack: if the text is too wide, reduce all the paint text sizes + private int getDigitsLength() { + return ((mHours == null) ? 0 : mHours.length()) + + ((mMinutes == null) ? 0 : mMinutes.length()) + + ((mSeconds == null) ? 0 : mSeconds.length()) + + ((mHundredths == null) ? 0 : mHundredths.length()); + } + + private void calcTotalTextWidth() { + mTotalTextWidth = mBigHours.calcTotalWidth(mHours) + mBigMinutes.calcTotalWidth(mMinutes) + + mBigThinSeconds.calcTotalWidth(mSeconds) + + mMedHundredths.calcTotalWidth(mHundredths); + } + + private void setTotalTextWidth() { + calcTotalTextWidth(); // To determine the maximum width, we find the minimum of the height and width (since the // circle we are trying to fit the text into has its radius sized to the smaller of the // two. int width = Math.min(getWidth(), getHeight()); if (width != 0) { - float ratio = mTotalTextWidth / width; - if (ratio > TEXT_SIZE_TO_WIDTH_RATIO) { - float sizeRatio = (TEXT_SIZE_TO_WIDTH_RATIO / ratio); - mPaintBig.setTextSize( mPaintBig.getTextSize() * sizeRatio); - mPaintBigThin.setTextSize( mPaintBigThin.getTextSize() * sizeRatio); - mPaintMed.setTextSize( mPaintMed.getTextSize() * sizeRatio); - mTotalTextWidth *= sizeRatio; - mMinutesWidth *= sizeRatio; - mHoursWidth *= sizeRatio; - mSecondsWidth *= sizeRatio; - mHundredthsWidth *= sizeRatio; - mHundredthsSepWidth *= sizeRatio; + float wantWidth = (int)(TEXT_SIZE_TO_WIDTH_RATIO * width); + // If the text is too wide, reduce all the paint text sizes + while (mTotalTextWidth > wantWidth) { + // Get fixed and variant parts of the total size + float fixedWidths = mBigHours.getLabelWidth() + mBigMinutes.getLabelWidth() + + mBigThinSeconds.getLabelWidth() + mMedHundredths.getLabelWidth(); + float varWidths = mBigHours.getWidth() + mBigMinutes.getWidth() + + mBigThinSeconds.getWidth() + mMedHundredths.getWidth(); + // Avoid divide by zero || sizeRatio == 1 || sizeRatio <= 0 + if (varWidths == 0 || fixedWidths == 0 || fixedWidths >= wantWidth) { + break; + } + // Variant-section reduction + float sizeRatio = (wantWidth - fixedWidths) / varWidths; + mPaintBig.setTextSize(mPaintBig.getTextSize() * sizeRatio); + mPaintBigThin.setTextSize(mPaintBigThin.getTextSize() * sizeRatio); + mPaintMed.setTextSize(mPaintMed.getTextSize() * sizeRatio); //recalculate the new total text width and half text height - mTotalTextWidth = mHoursWidth + mMinutesWidth + mSecondsWidth + - mHundredthsWidth + mHundredthsSepWidth + mHoursLabelWidth + - mMinutesLabelWidth + mSecondsLabelWidth; mTextHeight = mPaintBig.getTextSize(); + calcTotalTextWidth(); } } } @@ -277,7 +440,6 @@ public class CountingTimerView extends View { public void showTime(boolean visible) { mShowTimeStr = visible; invalidate(); - mRemeasureText = true; } public void redTimeStr(boolean red, boolean forceUpdate) { @@ -289,10 +451,17 @@ public class CountingTimerView extends View { } public String getTimeString() { - if (mHours == null) { - return String.format("%s:%s.%s",mMinutes, mSeconds, mHunderdths); + // Though only called from Stopwatch Share, so hundredth are never null, + // protect the future and check for null mHundredths + if (mHundredths == null) { + if (mHours == null) { + return String.format("%s:%s", mMinutes, mSeconds); + } + return String.format("%s:%s:%s", mHours, mMinutes, mSeconds); + } else if (mHours == null) { + return String.format("%s:%s.%s", mMinutes, mSeconds, mHundredths); } - return String.format("%s:%s:%s.%s",mHours, mMinutes, mSeconds, mHunderdths); + return String.format("%s:%s:%s.%s", mHours, mMinutes, mSeconds, mHundredths); } private static String getTimeStringForAccessibility(int hours, int minutes, int seconds, @@ -434,27 +603,18 @@ public class CountingTimerView extends View { mPaintMed.setColor(textColor); if (mHours != null) { - canvas.drawText(mHours, textXstart, textYstart, mPaintBig); - textXstart += mHoursWidth; - canvas.drawText(mHoursLabel, textXstart, labelYStart, mPaintLabel); - textXstart += mHoursLabelWidth; + textXstart = mBigHours.draw(canvas, mHours, textXstart, textYstart, labelYStart); } if (mMinutes != null) { - canvas.drawText(mMinutes, textXstart, textYstart, mPaintBig); - textXstart += mMinutesWidth; - canvas.drawText(mMinutesLabel, textXstart, labelYStart, mPaintLabel); - textXstart += mMinutesLabelWidth; + textXstart = mBigMinutes.draw(canvas, mMinutes, textXstart, textYstart, labelYStart); } if (mSeconds != null) { - canvas.drawText(mSeconds, textXstart, textYstart, mPaintBigThin); - textXstart += mSecondsWidth; - canvas.drawText(mSecondsLabel, textXstart, labelYStart, mPaintLabel); - textXstart += mSecondsLabelWidth; - } - if (mHunderdths != null) { - canvas.drawText(HUNDREDTH_SEPERATOR, textXstart, textYstart, mPaintLabel); - textXstart += mHundredthsSepWidth; - canvas.drawText(mHunderdths, textXstart, textYstart, mPaintMed); + textXstart = mBigThinSeconds.draw(canvas, mSeconds, + textXstart, textYstart, labelYStart); + } + if (mHundredths != null) { + textXstart = mMedHundredths.draw(canvas, mHundredths, + textXstart, textYstart, textYstart); } } diff --git a/src/com/android/deskclock/timer/TimerFragment.java b/src/com/android/deskclock/timer/TimerFragment.java index a2c6de955..b388da33f 100644 --- a/src/com/android/deskclock/timer/TimerFragment.java +++ b/src/com/android/deskclock/timer/TimerFragment.java @@ -31,10 +31,8 @@ import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; -import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.animation.AccelerateInterpolator; @@ -43,18 +41,17 @@ import android.widget.BaseAdapter; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageButton; -import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; -import com.android.deskclock.DeskClock; import com.android.deskclock.CircleButtonsLinearLayout; +import com.android.deskclock.DeskClock; +import com.android.deskclock.DeskClock.OnTapListener; import com.android.deskclock.DeskClockFragment; import com.android.deskclock.LabelDialogFragment; import com.android.deskclock.R; import com.android.deskclock.TimerSetupView; import com.android.deskclock.Utils; -import com.android.deskclock.DeskClock.OnTapListener; import java.util.ArrayList; import java.util.Collections; @@ -117,13 +114,11 @@ public class TimerFragment extends DeskClockFragment class TimersListAdapter extends BaseAdapter { ArrayList<TimerObj> mTimers = new ArrayList<TimerObj> (); - private final LayoutInflater mInflater; Context mContext; SharedPreferences mmPrefs; public TimersListAdapter(Context context, SharedPreferences prefs) { mContext = context; - mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mmPrefs = prefs; } @@ -148,11 +143,11 @@ public class TimerFragment extends DeskClockFragment public void deleteTimer(int id) { for (int i = 0; i < mTimers.size(); i++) { TimerObj t = mTimers.get(i); - + if (t.mTimerId == id) { - if(t.mView != null) { - ((TimerListItem)t.mView).stop(); - } + if (t.mView != null) { + ((TimerListItem) t.mView).stop(); + } t.deleteFromSharedPref(mmPrefs); mTimers.remove(i); notifyDataSetChanged(); @@ -259,7 +254,7 @@ public class TimerFragment extends DeskClockFragment public void addTimer(TimerObj t) { mTimers.add(0, t); - notifyDataSetChanged(); + sort(); } public void onSaveInstanceState(Bundle outState) { @@ -268,12 +263,50 @@ public class TimerFragment extends DeskClockFragment public void onRestoreInstanceState(Bundle outState) { TimerObj.getTimersFromSharedPrefs(mmPrefs, mTimers); - notifyDataSetChanged(); + sort(); } public void saveGlobalState() { TimerObj.putTimersInSharedPrefs(mmPrefs, mTimers); } + + public void sort() { + if (getCount() > 0) { + Collections.sort(mTimers, mTimersCompare); + notifyDataSetChanged(); + } + } + + private final Comparator<TimerObj> mTimersCompare = new Comparator<TimerObj>() { + static final int BUZZING = 0; + static final int IN_USE = 1; + static final int NOT_USED = 2; + + protected int getSection(TimerObj timerObj) { + switch (timerObj.mState) { + case TimerObj.STATE_TIMESUP: + return BUZZING; + case TimerObj.STATE_RUNNING: + case TimerObj.STATE_STOPPED: + return IN_USE; + default: + return NOT_USED; + } + } + + @Override + public int compare(TimerObj o1, TimerObj o2) { + int section1 = getSection(o1); + int section2 = getSection(o2); + if (section1 != section2) { + return (section1 < section2) ? -1 : 1; + } else if (section1 == BUZZING || section1 == IN_USE) { + return (o1.mTimeLeft < o2.mTimeLeft) ? -1 : 1; + } else { + return (o1.mSetupLength < o2.mSetupLength) ? -1 : 1; + } + } + }; } class TimesUpListAdapter extends TimersListAdapter { @@ -305,7 +338,7 @@ public class TimerFragment extends DeskClockFragment Collections.sort(mTimers, new Comparator<TimerObj>() { @Override public int compare(TimerObj o1, TimerObj o2) { - return (int)(o1.mTimeLeft - o2.mTimeLeft); + return (o1.mTimeLeft < o2.mTimeLeft) ? -1 : 1; } }); } @@ -431,6 +464,7 @@ public class TimerFragment extends DeskClockFragment mAdapter.addTimer(t); updateTimersState(t, Timers.START_TIMER); gotoTimersView(); + mTimersList.setSelection(mAdapter.findTimerPositionById(t.mTimerId)); } }); @@ -462,6 +496,9 @@ public class TimerFragment extends DeskClockFragment @Override public void onResume() { + if (getActivity() instanceof DeskClock) { + ((DeskClock)getActivity()).registerPageChangedListener(this); + } super.onResume(); mPrefs.registerOnSharedPreferenceChangeListener(this); @@ -502,6 +539,9 @@ public class TimerFragment extends DeskClockFragment @Override public void onPause() { + if (getActivity() instanceof DeskClock) { + ((DeskClock)getActivity()).unregisterPageChangedListener(this); + } super.onPause(); stopClockTicks(); if (mAdapter != null) { @@ -511,6 +551,13 @@ public class TimerFragment extends DeskClockFragment } @Override + public void onPageChanged(int page) { + if (page == DeskClock.TIMER_TAB_INDEX && mAdapter != null) { + mAdapter.sort(); + } + } + + @Override public void onSaveInstanceState (Bundle outState) { super.onSaveInstanceState(outState); if (mAdapter != null) { diff --git a/src/com/android/deskclock/timer/TimerObj.java b/src/com/android/deskclock/timer/TimerObj.java index f8e779496..5f18d9ea6 100644 --- a/src/com/android/deskclock/timer/TimerObj.java +++ b/src/com/android/deskclock/timer/TimerObj.java @@ -265,12 +265,15 @@ public class TimerObj implements Parcelable { } } - public static void cleanTimersFromSharedPrefs(SharedPreferences prefs) { + public static void resetTimersInSharedPrefs(SharedPreferences prefs) { ArrayList<TimerObj> timers = new ArrayList<TimerObj>(); getTimersFromSharedPrefs(prefs, timers); Iterator<TimerObj> i = timers.iterator(); while(i.hasNext()) { - i.next().deleteFromSharedPref(prefs); + TimerObj t = i.next(); + t.mState = TimerObj.STATE_RESTART; + t.mTimeLeft = t. mOriginalLength = t.mSetupLength; + t.writeToSharedPref(prefs); } } diff --git a/src/com/android/deskclock/timer/TimerView.java b/src/com/android/deskclock/timer/TimerView.java index 5ce38ec9e..310a957cc 100644 --- a/src/com/android/deskclock/timer/TimerView.java +++ b/src/com/android/deskclock/timer/TimerView.java @@ -33,6 +33,7 @@ public class TimerView extends LinearLayout { private ZeroTopPaddingTextView mHoursTens, mMinutesTens; private TextView mSeconds; private final Typeface mAndroidClockMonoThin; + private Typeface mOriginalHoursTypeface; private final int mWhiteColor, mGrayColor; public TimerView(Context context) { @@ -57,15 +58,8 @@ public class TimerView extends LinearLayout { mHoursOnes = (ZeroTopPaddingTextView)findViewById(R.id.hours_ones); mMinutesOnes = (ZeroTopPaddingTextView)findViewById(R.id.minutes_ones); mSeconds = (TextView)findViewById(R.id.seconds); - // If we have hours tens, we are in the alarm time picker, set the hours font to thin - // to prevent the need to set the top paddings (see b/7407383). - if (mHoursTens != null) { - mHoursTens.setTypeface(mAndroidClockMonoThin); - mHoursTens.updatePadding(); - if (mHoursOnes != null) { - mHoursOnes.setTypeface(mAndroidClockMonoThin); - mHoursOnes.updatePadding(); - } + if (mHoursOnes != null) { + mOriginalHoursTypeface = mHoursOnes.getTypeface(); } // Set the lowest time unit with thin font (excluding hundredths) if (mSeconds != null) { @@ -91,21 +85,29 @@ public class TimerView extends LinearLayout { mHoursTens.setVisibility(View.INVISIBLE); } else if (hoursTensDigit == -1) { mHoursTens.setText("-"); + mHoursTens.setTypeface(mAndroidClockMonoThin); mHoursTens.setTextColor(mGrayColor); + mHoursTens.updatePadding(); mHoursTens.setVisibility(View.VISIBLE); } else { mHoursTens.setText(String.format("%d",hoursTensDigit)); + mHoursTens.setTypeface(mOriginalHoursTypeface); mHoursTens.setTextColor(mWhiteColor); + mHoursTens.updatePadding(); mHoursTens.setVisibility(View.VISIBLE); } } if (mHoursOnes != null) { if (hoursOnesDigit == -1) { mHoursOnes.setText("-"); + mHoursOnes.setTypeface(mAndroidClockMonoThin); mHoursOnes.setTextColor(mGrayColor); + mHoursOnes.updatePadding(); } else { mHoursOnes.setText(String.format("%d",hoursOnesDigit)); + mHoursOnes.setTypeface(mOriginalHoursTypeface); mHoursOnes.setTextColor(mWhiteColor); + mHoursOnes.updatePadding(); } } if (mMinutesTens != null) { diff --git a/src/com/android/deskclock/worldclock/Cities.java b/src/com/android/deskclock/worldclock/Cities.java index c91eaeb52..dbd017d82 100644 --- a/src/com/android/deskclock/worldclock/Cities.java +++ b/src/com/android/deskclock/worldclock/Cities.java @@ -28,46 +28,45 @@ public class Cities { public static final String WORLDCLOCK_UPDATE_INTENT = "com.android.deskclock.worldclock.update"; private static final String NUMBER_OF_CITIES = "number_of_cities"; - public static void saveCitiesToSharedPrefs( SharedPreferences prefs, HashMap<String, CityObj> cities) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(NUMBER_OF_CITIES, cities.size()); - Collection<CityObj> col = cities.values(); - Iterator<CityObj> i = col.iterator(); - int count = 0; - while(i.hasNext()) { - CityObj c = i.next(); - c.saveCityToSharedPrefs(editor, count); - count ++; - } - editor.apply(); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt(NUMBER_OF_CITIES, cities.size()); + Collection<CityObj> col = cities.values(); + Iterator<CityObj> i = col.iterator(); + int count = 0; + while (i.hasNext()) { + CityObj c = i.next(); + c.saveCityToSharedPrefs(editor, count); + count++; + } + editor.apply(); } public static HashMap<String, CityObj> readCitiesFromSharedPrefs(SharedPreferences prefs) { - int size = prefs.getInt(NUMBER_OF_CITIES, -1); - HashMap<String, CityObj> c = new HashMap<String, CityObj> (); - if (size > 0) { - for (int i = 0; i < size; i++) { - CityObj o = new CityObj(prefs, i); - if (o.mCityName != null && o.mTimeZone != null) { - c.put(o.mCityId, o); - } + int size = prefs.getInt(NUMBER_OF_CITIES, -1); + HashMap<String, CityObj> c = new HashMap<String, CityObj>(); + if (size > 0) { + for (int i = 0; i < size; i++) { + CityObj o = new CityObj(prefs, i); + if (o.mCityName != null && o.mTimeZone != null) { + c.put(o.mCityId, o); } } - return c; + } + return c; } private static void dumpCities(SharedPreferences prefs, String title) { int size = prefs.getInt(NUMBER_OF_CITIES, -1); - Log.d("Cities","Selected Cities List " + title); - Log.d("Cities","Number of cities " + size); - HashMap<String, CityObj> c = new HashMap<String, CityObj> (); + Log.d("Cities", "Selected Cities List " + title); + Log.d("Cities", "Number of cities " + size); + HashMap<String, CityObj> c = new HashMap<String, CityObj>(); if (size > 0) { for (int i = 0; i < size; i++) { CityObj o = new CityObj(prefs, i); if (o.mCityName != null && o.mTimeZone != null) { - Log.d("Cities","Name " + o.mCityName + " tz " + o.mTimeZone); + Log.d("Cities", "Name " + o.mCityName + " tz " + o.mTimeZone); } } } diff --git a/src/com/android/deskclock/worldclock/CitiesActivity.java b/src/com/android/deskclock/worldclock/CitiesActivity.java index ffabc76fb..02423b5a1 100644 --- a/src/com/android/deskclock/worldclock/CitiesActivity.java +++ b/src/com/android/deskclock/worldclock/CitiesActivity.java @@ -21,7 +21,6 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.format.DateFormat; @@ -40,16 +39,13 @@ import android.widget.TextView; import com.android.deskclock.Alarms; import com.android.deskclock.DeskClock; -import com.android.deskclock.Log; import com.android.deskclock.R; import com.android.deskclock.SettingsActivity; import com.android.deskclock.Utils; import java.text.Collator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; -import java.util.Comparator; import java.util.HashMap; import java.util.TimeZone; @@ -68,8 +64,6 @@ public class CitiesActivity extends Activity implements OnCheckedChangeListener, private CityAdapter mAdapter; private HashMap<String, CityObj> mUserSelectedCities; private Calendar mCalendar; - private final Collator mCollator = Collator.getInstance(); - /*** * Adapter for a list of cities with the respected time zone. @@ -98,12 +92,12 @@ public class CitiesActivity extends Activity implements OnCheckedChangeListener, @Override public int getCount() { - return mAllTheCitiesList.length; + return (mAllTheCitiesList != null) ? mAllTheCitiesList.length : 0; } @Override public Object getItem(int p) { - if (p >=0 && p < mAllTheCitiesList.length) { + if (mAllTheCitiesList != null && p >=0 && p < mAllTheCitiesList.length) { return mAllTheCitiesList [p]; } return null; @@ -116,12 +110,12 @@ public class CitiesActivity extends Activity implements OnCheckedChangeListener, @Override public boolean isEnabled(int p) { - return ((CityObj)mAllTheCitiesList[p]).mCityId != null; + return mAllTheCitiesList != null && ((CityObj)mAllTheCitiesList[p]).mCityId != null; } @Override public View getView(int position, View view, ViewGroup parent) { - if (position < 0 || position >= mAllTheCitiesList.length) { + if (mAllTheCitiesList == null || position < 0 || position >= mAllTheCitiesList.length) { return null; } CityObj c = (CityObj)mAllTheCitiesList [position]; @@ -157,27 +151,10 @@ public class CitiesActivity extends Activity implements OnCheckedChangeListener, } private void loadCitiesDataBase(Context c) { - Resources r = c.getResources(); - // Read strings array of name,timezone, id - // make sure the list are the same length - String [] cities = r.getStringArray(R.array.cities_names); - String [] timezones = r.getStringArray(R.array.cities_tz); - String [] ids = r.getStringArray(R.array.cities_id); - if (cities.length != timezones.length || ids.length != cities.length) { - Log.wtf("City lists sizes are not the same, cannot use the data"); + CityObj[] tempList = Utils.loadCitiesDataBase(c); + if (tempList == null) { return; - } - CityObj[] tempList = new CityObj [cities.length]; - for (int i = 0; i < cities.length; i++) { - tempList[i] = new CityObj(cities[i], timezones[i], ids[i]); - } - // Sort alphabetically - Arrays.sort(tempList, new Comparator<CityObj> () { - @Override - public int compare(CityObj c1, CityObj c2) { - return mCollator.compare(c1.mCityName, c2.mCityName); - } - }); + } //Create section indexer and add headers to the cities list String val = null; ArrayList<String> sections = new ArrayList<String> (); @@ -207,18 +184,21 @@ public class CitiesActivity extends Activity implements OnCheckedChangeListener, @Override public int getPositionForSection(int section) { - return (Integer) mSectionPositions[section]; + return (mSectionPositions != null) ? (Integer) mSectionPositions[section] : 0; } @Override public int getSectionForPosition(int p) { - for (int i = 0; i < mSectionPositions.length - 1; i++) { - if (p >= (Integer)mSectionPositions[i] && p < (Integer)mSectionPositions[i + 1]) { - return i; + if (mSectionPositions != null) { + for (int i = 0; i < mSectionPositions.length - 1; i++) { + if (p >= (Integer) mSectionPositions[i] + && p < (Integer) mSectionPositions[i + 1]) { + return i; + } + } + if (p >= (Integer)mSectionPositions[mSectionPositions.length - 1]) { + return mSectionPositions.length - 1; } - } - if (p >= (Integer)mSectionPositions[mSectionPositions.length - 1]) { - return mSectionPositions.length - 1; } return 0; } diff --git a/src/com/android/deskclock/worldclock/WorldClockAdapter.java b/src/com/android/deskclock/worldclock/WorldClockAdapter.java index c76407d60..ac94d481c 100644 --- a/src/com/android/deskclock/worldclock/WorldClockAdapter.java +++ b/src/com/android/deskclock/worldclock/WorldClockAdapter.java @@ -25,30 +25,34 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; +import com.android.deskclock.AnalogClock; +import com.android.deskclock.DigitalClock; +import com.android.deskclock.R; +import com.android.deskclock.SettingsActivity; +import com.android.deskclock.Utils; + import java.text.Collator; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.Locale; import java.util.TimeZone; -import com.android.deskclock.AnalogClock; -import com.android.deskclock.DigitalClock; -import com.android.deskclock.R; -import com.android.deskclock.SettingsActivity; - public class WorldClockAdapter extends BaseAdapter { protected Object [] mCitiesList; private final LayoutInflater mInflater; private final Context mContext; private String mClockStyle; private final Collator mCollator = Collator.getInstance(); + protected HashMap<String, CityObj> mCitiesDb = new HashMap<String, CityObj>(); public WorldClockAdapter(Context context) { super(); mContext = context; loadData(context); + loadCitiesDb(context); mInflater = LayoutInflater.from(context); } @@ -66,6 +70,19 @@ public class WorldClockAdapter extends BaseAdapter { mCitiesList = addHomeCity(); } + public void loadCitiesDb(Context context) { + mCitiesDb.clear(); + // Read the cities DB so that the names and timezones will be taken from the DB + // and not from the selected list so that change of locale or changes in the DB will + // be reflected. + CityObj[] cities = Utils.loadCitiesDataBase(context); + if (cities != null) { + for (int i = 0; i < cities.length; i ++) { + mCitiesDb.put(cities[i].mCityId, cities [i]); + } + } + } + /*** * Adds the home city as the first item of the adapter if the feature is on and the device time * zone is different from the home time zone that was set by the user. @@ -220,11 +237,16 @@ public class WorldClockAdapter extends BaseAdapter { aclock.setVisibility(View.GONE); dclock.setTimeZone(cityObj.mTimeZone); } - name.setText(cityObj.mCityName); + CityObj cityInDb = mCitiesDb.get(cityObj.mCityId); + // Home city or city not in DB , use data from the save selected cities list + name.setText(Utils.getCityName(cityObj, cityInDb)); + final Calendar now = Calendar.getInstance(); now.setTimeZone(TimeZone.getDefault()); int myDayOfWeek = now.get(Calendar.DAY_OF_WEEK); - now.setTimeZone(TimeZone.getTimeZone(cityObj.mTimeZone)); + // Get timezone from cities DB if available + String cityTZ = (cityInDb != null) ? cityInDb.mTimeZone : cityObj.mTimeZone; + now.setTimeZone(TimeZone.getTimeZone(cityTZ)); int cityDayOfWeek = now.get(Calendar.DAY_OF_WEEK); if (myDayOfWeek != cityDayOfWeek) { dayOfWeek.setText(mContext.getString(R.string.world_day_of_week_label, |