Utils.java revision 24fac46d6b87ce21d5e6a4b1c0fdcaa83d408997
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.calendar; 18 19import static android.provider.Calendar.EVENT_BEGIN_TIME; 20 21import com.android.calendar.CalendarController.ViewType; 22 23import android.app.Activity; 24import android.content.Context; 25import android.content.Intent; 26import android.content.SharedPreferences; 27import android.content.SharedPreferences.Editor; 28import android.database.Cursor; 29import android.database.MatrixCursor; 30import android.graphics.drawable.Drawable; 31import android.graphics.drawable.GradientDrawable; 32import android.net.Uri; 33import android.os.AsyncTask; 34import android.os.Bundle; 35import android.text.TextUtils; 36import android.text.format.Time; 37import android.util.Log; 38 39import java.util.Calendar; 40import java.util.List; 41import java.util.Map; 42import java.util.TimeZone; 43 44public class Utils { 45 // Set to 0 until we have UI to perform undo 46 public static final long UNDO_DELAY = 0; 47 48 // For recurring events which instances of the series are being modified 49 public static final int MODIFY_UNINITIALIZED = 0; 50 public static final int MODIFY_SELECTED = 1; 51 public static final int MODIFY_ALL_FOLLOWING = 2; 52 public static final int MODIFY_ALL = 3; 53 54 // When the edit event view finishes it passes back the appropriate exit code. 55 public static final int DONE_REVERT = 0; 56 public static final int DONE_SAVE = 1; 57 public static final int DONE_DELETE = 2; 58 59 private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF; 60 private static final int HIGH_ALPHA = 255 << 24; 61 private static final int MED_ALPHA = 180 << 24; 62 private static final int LOW_ALPHA = 150 << 24; 63 64 protected static final String OPEN_EMAIL_MARKER = " <"; 65 protected static final String CLOSE_EMAIL_MARKER = ">"; 66 67 /* The corner should be rounded on the top right and bottom right */ 68 private static final float[] CORNERS = new float[] {0, 0, 5, 5, 5, 5, 0, 0}; 69 70 public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW"; 71 public static final String INTENT_KEY_VIEW_TYPE = "VIEW"; 72 public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY"; 73 74 public static int getViewTypeFromIntentAndSharedPref(Activity activity) { 75 Bundle extras = activity.getIntent().getExtras(); 76 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(activity); 77 78 if (extras != null) { 79 if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) { 80 // This is the "detail" view which is either agenda or day view 81 return prefs.getInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW, 82 CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW); 83 } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) { 84 // Not sure who uses this. This logic came from LaunchActivity 85 return ViewType.DAY; 86 } 87 } 88 89 // Default to the last view 90 return prefs.getInt(CalendarPreferenceActivity.KEY_START_VIEW, 91 CalendarPreferenceActivity.DEFAULT_START_VIEW); 92 } 93 94 public static String getSharedPreference(Context context, String key, String defaultValue) { 95 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context); 96 return prefs.getString(key, defaultValue); 97 } 98 99 public static int getSharedPreference(Context context, String key, int defaultValue) { 100 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context); 101 return prefs.getInt(key, defaultValue); 102 } 103 104 /** 105 * Asynchronously sets the preference with the given key to the given value 106 * 107 * @param context the context to use to get preferences from 108 * @param key the key of the preference to set 109 * @param value the value to set 110 */ 111 public static void setSharedPreference(Context context, String key, String value) { 112 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context); 113 prefs.edit().putString(key, value).apply(); 114 } 115 116 /** 117 * Save default agenda/day/week/month view for next time 118 * 119 * @param context 120 * @param viewId {@link CalendarController.ViewType} 121 */ 122 static void setDefaultView(Context context, int viewId) { 123 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context); 124 SharedPreferences.Editor editor = prefs.edit(); 125 126 if (viewId == CalendarController.ViewType.AGENDA 127 || viewId == CalendarController.ViewType.DAY) { 128 // Record the (new) detail start view only for Agenda and Day 129 editor.putInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW, viewId); 130 } 131 132 // Record the (new) start view 133 editor.putInt(CalendarPreferenceActivity.KEY_START_VIEW, viewId); 134 editor.apply(); 135 } 136 137 public static MatrixCursor matrixCursorFromCursor(Cursor cursor) { 138 MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 139 int numColumns = cursor.getColumnCount(); 140 String data[] = new String[numColumns]; 141 cursor.moveToPosition(-1); 142 while (cursor.moveToNext()) { 143 for (int i = 0; i < numColumns; i++) { 144 data[i] = cursor.getString(i); 145 } 146 newCursor.addRow(data); 147 } 148 return newCursor; 149 } 150 151 /** 152 * Compares two cursors to see if they contain the same data. 153 * 154 * @return Returns true of the cursors contain the same data and are not null, false 155 * otherwise 156 */ 157 public static boolean compareCursors(Cursor c1, Cursor c2) { 158 if(c1 == null || c2 == null) { 159 return false; 160 } 161 162 int numColumns = c1.getColumnCount(); 163 if (numColumns != c2.getColumnCount()) { 164 return false; 165 } 166 167 if (c1.getCount() != c2.getCount()) { 168 return false; 169 } 170 171 c1.moveToPosition(-1); 172 c2.moveToPosition(-1); 173 while(c1.moveToNext() && c2.moveToNext()) { 174 for(int i = 0; i < numColumns; i++) { 175 if(!TextUtils.equals(c1.getString(i), c2.getString(i))) { 176 return false; 177 } 178 } 179 } 180 181 return true; 182 } 183 184 /** 185 * If the given intent specifies a time (in milliseconds since the epoch), 186 * then that time is returned. Otherwise, the current time is returned. 187 */ 188 public static final long timeFromIntentInMillis(Intent intent) { 189 // If the time was specified, then use that. Otherwise, use the current time. 190 Uri data = intent.getData(); 191 long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1); 192 if (millis == -1 && data != null && data.isHierarchical()) { 193 List<String> path = data.getPathSegments(); 194 if(path.size() == 2 && path.get(0).equals("time")) { 195 try { 196 millis = Long.valueOf(data.getLastPathSegment()); 197 } catch (NumberFormatException e) { 198 Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " + 199 "found. Using current time."); 200 } 201 } 202 } 203 if (millis <= 0) { 204 millis = System.currentTimeMillis(); 205 } 206 return millis; 207 } 208 209 public static Drawable getColorChip(int color) { 210 /* 211 * We want the color chip to have a nice gradient using 212 * the color of the calendar. To do this we use a GradientDrawable. 213 * The color supplied has an alpha of FF so we first do: 214 * color & 0x00FFFFFF 215 * to clear the alpha. Then we add our alpha to it. 216 * We use 3 colors to get a step effect where it starts off very 217 * light and quickly becomes dark and then a slow transition to 218 * be even darker. 219 */ 220 color &= CLEAR_ALPHA_MASK; 221 int startColor = color | HIGH_ALPHA; 222 int middleColor = color | MED_ALPHA; 223 int endColor = color | LOW_ALPHA; 224 int[] colors = new int[] {startColor, middleColor, endColor}; 225 GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors); 226 d.setCornerRadii(CORNERS); 227 return d; 228 } 229 230 /** 231 * Formats the given Time object so that it gives the month and year 232 * (for example, "September 2007"). 233 * 234 * @param time the time to format 235 * @return the string containing the weekday and the date 236 */ 237 public static String formatMonthYear(Context context, Time time) { 238 return time.format(context.getResources().getString(R.string.month_year)); 239 } 240 241 /** 242 * Returns a list joined together by the provided delimiter, for example, 243 * ["a", "b", "c"] could be joined into "a,b,c" 244 * 245 * @param things the things to join together 246 * @param delim the delimiter to use 247 * @return a string contained the things joined together 248 */ 249 public static String join(List<?> things, String delim) { 250 StringBuilder builder = new StringBuilder(); 251 boolean first = true; 252 for (Object thing : things) { 253 if (first) { 254 first = false; 255 } else { 256 builder.append(delim); 257 } 258 builder.append(thing.toString()); 259 } 260 return builder.toString(); 261 } 262 263 /** 264 * Get first day of week as android.text.format.Time constant. 265 * @return the first day of week in android.text.format.Time 266 */ 267 public static int getFirstDayOfWeek(Context context) { 268 SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context); 269 String pref = prefs.getString(CalendarPreferenceActivity.KEY_WEEK_START_DAY, 270 CalendarPreferenceActivity.WEEK_START_DEFAULT); 271 272 int startDay; 273 if (CalendarPreferenceActivity.WEEK_START_DEFAULT.equals(pref)) { 274 startDay = Calendar.getInstance().getFirstDayOfWeek(); 275 } else { 276 startDay = Integer.parseInt(pref); 277 } 278 279 if (startDay == Calendar.SATURDAY) { 280 return Time.SATURDAY; 281 } else if (startDay == Calendar.MONDAY) { 282 return Time.MONDAY; 283 } else { 284 return Time.SUNDAY; 285 } 286 } 287 288 /** 289 * Determine whether the column position is Saturday or not. 290 * @param column the column position 291 * @param firstDayOfWeek the first day of week in android.text.format.Time 292 * @return true if the column is Saturday position 293 */ 294 public static boolean isSaturday(int column, int firstDayOfWeek) { 295 return (firstDayOfWeek == Time.SUNDAY && column == 6) 296 || (firstDayOfWeek == Time.MONDAY && column == 5) 297 || (firstDayOfWeek == Time.SATURDAY && column == 0); 298 } 299 300 /** 301 * Determine whether the column position is Sunday or not. 302 * @param column the column position 303 * @param firstDayOfWeek the first day of week in android.text.format.Time 304 * @return true if the column is Sunday position 305 */ 306 public static boolean isSunday(int column, int firstDayOfWeek) { 307 return (firstDayOfWeek == Time.SUNDAY && column == 0) 308 || (firstDayOfWeek == Time.MONDAY && column == 6) 309 || (firstDayOfWeek == Time.SATURDAY && column == 1); 310 } 311 312 /** 313 * Convert given UTC time into current local time. 314 * 315 * @param recycle Time object to recycle, otherwise null. 316 * @param utcTime Time to convert, in UTC. 317 */ 318 public static long convertUtcToLocal(Time recycle, long utcTime) { 319 if (recycle == null) { 320 recycle = new Time(); 321 } 322 recycle.timezone = Time.TIMEZONE_UTC; 323 recycle.set(utcTime); 324 recycle.timezone = TimeZone.getDefault().getID(); 325 return recycle.normalize(true); 326 } 327 328 /** 329 * Scan through a cursor of calendars and check if names are duplicated. 330 * 331 * This travels a cursor containing calendar display names and fills in the provided map with 332 * whether or not each name is repeated. 333 * @param isDuplicateName The map to put the duplicate check results in. 334 * @param cursor The query of calendars to check 335 * @param nameIndex The column of the query that contains the display name 336 */ 337 public static void checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor, 338 int nameIndex) { 339 isDuplicateName.clear(); 340 cursor.moveToPosition(-1); 341 while (cursor.moveToNext()) { 342 String displayName = cursor.getString(nameIndex); 343 // Set it to true if we've seen this name before, false otherwise 344 if (displayName != null) { 345 isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName)); 346 } 347 } 348 } 349 350 /** 351 * Null-safe object comparison 352 * @param s1 353 * @param s2 354 * @return 355 */ 356 public static boolean equals(Object o1, Object o2) { 357 return o1 == null ? o2 == null : o1.equals(o2); 358 } 359} 360