Utils.java revision a27a886892fe3ec5edbc63c0b58e0a988623011a
1146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/* 2146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 3146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 4146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * you may not use this file except in compliance with the License. 6146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * You may obtain a copy of the License at 7146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 8146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 10146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * See the License for the specific language governing permissions and 14146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * limitations under the License. 15146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 16146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 17146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpackage com.android.calendar; 18146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 19a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErikimport static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME; 20e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan 21d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport com.android.calendar.CalendarController.ViewType; 22d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan 23d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport android.app.Activity; 24146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context; 25146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Intent; 26e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chanimport android.content.SharedPreferences; 275b2a907fa3a983f74bb48da86846e351c2a464d0Isaac Katzenelsonimport android.content.res.Configuration; 28ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.database.Cursor; 29a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErikimport android.database.MatrixCursor; 301ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.net.Uri; 31d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport android.os.Bundle; 32eb10fa8bee049e0052b5cb53dcfbdaccef9f2740Erikimport android.text.TextUtils; 3329190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawaimport android.text.format.DateUtils; 34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time; 351ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.util.Log; 36636269c7220a2b12e090cab43a91eb34922eb61fAndy McFaddenimport com.android.calendar.CalendarUtils.TimeZoneUtils; 37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 3882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelsonimport java.util.ArrayList; 3956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashiimport java.util.Calendar; 401427657d0bf7e69b831aa495828f67b45b69fd99Erikimport java.util.Formatter; 4182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelsonimport java.util.Iterator; 421ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport java.util.List; 43ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport java.util.Map; 4456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi 45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class Utils { 463dc5e908a825b879978ba523d9099dc2255da9a5Erik private static final boolean DEBUG = true; 473dc5e908a825b879978ba523d9099dc2255da9a5Erik private static final String TAG = "CalUtils"; 48bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan // Set to 0 until we have UI to perform undo 49bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan public static final long UNDO_DELAY = 0; 50bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan 5179f228124de7d98146ca526d743436f6419e2365Erik // For recurring events which instances of the series are being modified 5279f228124de7d98146ca526d743436f6419e2365Erik public static final int MODIFY_UNINITIALIZED = 0; 5379f228124de7d98146ca526d743436f6419e2365Erik public static final int MODIFY_SELECTED = 1; 5479f228124de7d98146ca526d743436f6419e2365Erik public static final int MODIFY_ALL_FOLLOWING = 2; 5579f228124de7d98146ca526d743436f6419e2365Erik public static final int MODIFY_ALL = 3; 5679f228124de7d98146ca526d743436f6419e2365Erik 577b92da258a480284dcc15a518ea570072329a31dErik // When the edit event view finishes it passes back the appropriate exit 587b92da258a480284dcc15a518ea570072329a31dErik // code. 597b92da258a480284dcc15a518ea570072329a31dErik public static final int DONE_REVERT = 1 << 0; 607b92da258a480284dcc15a518ea570072329a31dErik public static final int DONE_SAVE = 1 << 1; 617b92da258a480284dcc15a518ea570072329a31dErik public static final int DONE_DELETE = 1 << 2; 627b92da258a480284dcc15a518ea570072329a31dErik // And should re run with DONE_EXIT if it should also leave the view, just 637b92da258a480284dcc15a518ea570072329a31dErik // exiting is identical to reverting 647b92da258a480284dcc15a518ea570072329a31dErik public static final int DONE_EXIT = 1 << 0; 6579f228124de7d98146ca526d743436f6419e2365Erik 66ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan protected static final String OPEN_EMAIL_MARKER = " <"; 67ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan protected static final String CLOSE_EMAIL_MARKER = ">"; 68ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan 69d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW"; 70d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan public static final String INTENT_KEY_VIEW_TYPE = "VIEW"; 71d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY"; 72275232dae58bb24e3360a779ada9d24601a99bcfErik 73981874e61ecf29a96a77601a3172b2503b6537eeErik public static final int MONDAY_BEFORE_JULIAN_EPOCH = Time.EPOCH_JULIAN_DAY - 3; 74981874e61ecf29a96a77601a3172b2503b6537eeErik 75a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik // The name of the shared preferences file. This name must be maintained for 76a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik // historical 77a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik // reasons, as it's what PreferenceManager assigned the first time the file 78a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik // was created. 79a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences"; 8035d1362a75eac7cebbe9de23d08fea08c4aac817Erik 81a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik private static final TimeZoneUtils mTZUtils = new TimeZoneUtils(SHARED_PREFS_NAME); 82b60218a31d948ea0a549daf6464063d20b48421fMichael Chan private static boolean mAllowWeekForDetailView = false; 83ca4786769151f97069980443ce43d9c4f867ac5bErik private static long mTardis = 0; 84d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan 85d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan public static int getViewTypeFromIntentAndSharedPref(Activity activity) { 86dd95df57c8c5a58a85c4c0effad5652dec14f621Erik Intent intent = activity.getIntent(); 87dd95df57c8c5a58a85c4c0effad5652dec14f621Erik Bundle extras = intent.getExtras(); 884b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(activity); 89d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan 907b92da258a480284dcc15a518ea570072329a31dErik if (TextUtils.equals(intent.getAction(), Intent.ACTION_EDIT)) { 91dd95df57c8c5a58a85c4c0effad5652dec14f621Erik return ViewType.EDIT; 92dd95df57c8c5a58a85c4c0effad5652dec14f621Erik } 93d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan if (extras != null) { 94d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) { 95d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan // This is the "detail" view which is either agenda or day view 964b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa return prefs.getInt(GeneralPreferences.KEY_DETAILED_VIEW, 974b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa GeneralPreferences.DEFAULT_DETAILED_VIEW); 98d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) { 99d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan // Not sure who uses this. This logic came from LaunchActivity 100d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan return ViewType.DAY; 101d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan } 102d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan } 103d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan 104d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan // Default to the last view 1057b92da258a480284dcc15a518ea570072329a31dErik return prefs.getInt( 1067b92da258a480284dcc15a518ea570072329a31dErik GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW); 107d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan } 108ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan 109235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik /** 110064beb957ae443760118023a40fd7001eb11c1a1RoboErik * Gets the intent action for telling the widget to update. 111064beb957ae443760118023a40fd7001eb11c1a1RoboErik */ 112064beb957ae443760118023a40fd7001eb11c1a1RoboErik public static String getWidgetUpdateAction(Context context) { 113064beb957ae443760118023a40fd7001eb11c1a1RoboErik return context.getPackageName() + ".APPWIDGET_UPDATE"; 114064beb957ae443760118023a40fd7001eb11c1a1RoboErik } 115064beb957ae443760118023a40fd7001eb11c1a1RoboErik 116064beb957ae443760118023a40fd7001eb11c1a1RoboErik /** 117064beb957ae443760118023a40fd7001eb11c1a1RoboErik * Gets the intent action for telling the widget to update. 118064beb957ae443760118023a40fd7001eb11c1a1RoboErik */ 119064beb957ae443760118023a40fd7001eb11c1a1RoboErik public static String getWidgetScheduledUpdateAction(Context context) { 120064beb957ae443760118023a40fd7001eb11c1a1RoboErik return context.getPackageName() + ".APPWIDGET_SCHEDULED_UPDATE"; 121064beb957ae443760118023a40fd7001eb11c1a1RoboErik } 122064beb957ae443760118023a40fd7001eb11c1a1RoboErik 123064beb957ae443760118023a40fd7001eb11c1a1RoboErik /** 124064beb957ae443760118023a40fd7001eb11c1a1RoboErik * Gets the intent action for telling the widget to update. 125064beb957ae443760118023a40fd7001eb11c1a1RoboErik */ 126064beb957ae443760118023a40fd7001eb11c1a1RoboErik public static String getSearchAuthority(Context context) { 127064beb957ae443760118023a40fd7001eb11c1a1RoboErik return context.getPackageName() + ".CalendarRecentSuggestionsProvider"; 128064beb957ae443760118023a40fd7001eb11c1a1RoboErik } 129064beb957ae443760118023a40fd7001eb11c1a1RoboErik 130064beb957ae443760118023a40fd7001eb11c1a1RoboErik /** 1317b92da258a480284dcc15a518ea570072329a31dErik * Writes a new home time zone to the db. Updates the home time zone in the 1327b92da258a480284dcc15a518ea570072329a31dErik * db asynchronously and updates the local cache. Sending a time zone of 1337b92da258a480284dcc15a518ea570072329a31dErik * **tbd** will cause it to be set to the device's time zone. null or empty 1347b92da258a480284dcc15a518ea570072329a31dErik * tz will be ignored. 1353dc5e908a825b879978ba523d9099dc2255da9a5Erik * 1363dc5e908a825b879978ba523d9099dc2255da9a5Erik * @param context The calling activity 1373dc5e908a825b879978ba523d9099dc2255da9a5Erik * @param timeZone The time zone to set Calendar to, or **tbd** 1383dc5e908a825b879978ba523d9099dc2255da9a5Erik */ 1393dc5e908a825b879978ba523d9099dc2255da9a5Erik public static void setTimeZone(Context context, String timeZone) { 140a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik mTZUtils.setTimeZone(context, timeZone); 1413dc5e908a825b879978ba523d9099dc2255da9a5Erik } 1423dc5e908a825b879978ba523d9099dc2255da9a5Erik 1433dc5e908a825b879978ba523d9099dc2255da9a5Erik /** 1447b92da258a480284dcc15a518ea570072329a31dErik * Gets the time zone that Calendar should be displayed in This is a helper 1457b92da258a480284dcc15a518ea570072329a31dErik * method to get the appropriate time zone for Calendar. If this is the 1467b92da258a480284dcc15a518ea570072329a31dErik * first time this method has been called it will initiate an asynchronous 1477b92da258a480284dcc15a518ea570072329a31dErik * query to verify that the data in preferences is correct. The callback 1487b92da258a480284dcc15a518ea570072329a31dErik * supplied will only be called if this query returns a value other than 1497b92da258a480284dcc15a518ea570072329a31dErik * what is stored in preferences and should cause the calling activity to 1507b92da258a480284dcc15a518ea570072329a31dErik * refresh anything that depends on calling this method. 151235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik * 152235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik * @param context The calling activity 1537b92da258a480284dcc15a518ea570072329a31dErik * @param callback The runnable that should execute if a query returns new 1547b92da258a480284dcc15a518ea570072329a31dErik * values 1557b92da258a480284dcc15a518ea570072329a31dErik * @return The string value representing the time zone Calendar should 1567b92da258a480284dcc15a518ea570072329a31dErik * display 157235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik */ 158235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik public static String getTimeZone(Context context, Runnable callback) { 159a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik return mTZUtils.getTimeZone(context, callback); 16045efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan } 16145efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan 1621427657d0bf7e69b831aa495828f67b45b69fd99Erik /** 1631427657d0bf7e69b831aa495828f67b45b69fd99Erik * Formats a date or a time range according to the local conventions. 1641427657d0bf7e69b831aa495828f67b45b69fd99Erik * 1651427657d0bf7e69b831aa495828f67b45b69fd99Erik * @param context the context is required only if the time is shown 1661427657d0bf7e69b831aa495828f67b45b69fd99Erik * @param startMillis the start time in UTC milliseconds 1671427657d0bf7e69b831aa495828f67b45b69fd99Erik * @param endMillis the end time in UTC milliseconds 16829190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawa * @param flags a bit mask of options See {@link DateUtils#formatDateRange(Context, Formatter, 16929190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawa * long, long, int, String) formatDateRange} 1701427657d0bf7e69b831aa495828f67b45b69fd99Erik * @return a string containing the formatted date/time range. 1711427657d0bf7e69b831aa495828f67b45b69fd99Erik */ 1727b92da258a480284dcc15a518ea570072329a31dErik public static String formatDateRange( 1737b92da258a480284dcc15a518ea570072329a31dErik Context context, long startMillis, long endMillis, int flags) { 174a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik return mTZUtils.formatDateRange(context, startMillis, endMillis, flags); 175a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik } 176a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik 177a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik public static String getSharedPreference(Context context, String key, String defaultValue) { 178a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 179a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik return prefs.getString(key, defaultValue); 1801427657d0bf7e69b831aa495828f67b45b69fd99Erik } 1811427657d0bf7e69b831aa495828f67b45b69fd99Erik 182d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan public static int getSharedPreference(Context context, String key, int defaultValue) { 1834b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 184d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan return prefs.getInt(key, defaultValue); 185d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan } 186d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan 187ca4786769151f97069980443ce43d9c4f867ac5bErik public static boolean getSharedPreference(Context context, String key, boolean defaultValue) { 188ca4786769151f97069980443ce43d9c4f867ac5bErik SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 189ca4786769151f97069980443ce43d9c4f867ac5bErik return prefs.getBoolean(key, defaultValue); 190ca4786769151f97069980443ce43d9c4f867ac5bErik } 191ca4786769151f97069980443ce43d9c4f867ac5bErik 192f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang /** 193f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang * Asynchronously sets the preference with the given key to the given value 194f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang * 195f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang * @param context the context to use to get preferences from 196f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang * @param key the key of the preference to set 197f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang * @param value the value to set 198f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang */ 199fbce65e53c7a111955f638db5bf8bee35381e5b7Erik public static void setSharedPreference(Context context, String key, String value) { 2004b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 20124fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick prefs.edit().putString(key, value).apply(); 20245efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan } 20345efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan 204ca4786769151f97069980443ce43d9c4f867ac5bErik protected static void tardis() { 205ca4786769151f97069980443ce43d9c4f867ac5bErik mTardis = System.currentTimeMillis(); 206ca4786769151f97069980443ce43d9c4f867ac5bErik } 207ca4786769151f97069980443ce43d9c4f867ac5bErik 208ca4786769151f97069980443ce43d9c4f867ac5bErik protected static long getTardis() { 209ca4786769151f97069980443ce43d9c4f867ac5bErik return mTardis; 210ca4786769151f97069980443ce43d9c4f867ac5bErik } 211ca4786769151f97069980443ce43d9c4f867ac5bErik 2123dc5e908a825b879978ba523d9099dc2255da9a5Erik static void setSharedPreference(Context context, String key, boolean value) { 2134b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 2143dc5e908a825b879978ba523d9099dc2255da9a5Erik SharedPreferences.Editor editor = prefs.edit(); 2153dc5e908a825b879978ba523d9099dc2255da9a5Erik editor.putBoolean(key, value); 216275232dae58bb24e3360a779ada9d24601a99bcfErik editor.apply(); 2173dc5e908a825b879978ba523d9099dc2255da9a5Erik } 2183dc5e908a825b879978ba523d9099dc2255da9a5Erik 219d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan static void setSharedPreference(Context context, String key, int value) { 220d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 221d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan SharedPreferences.Editor editor = prefs.edit(); 222d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan editor.putInt(key, value); 223d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan editor.apply(); 224d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan } 225d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan 226d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan /** 227d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan * Save default agenda/day/week/month view for next time 228d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan * 229d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan * @param context 230d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan * @param viewId {@link CalendarController.ViewType} 231d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan */ 232e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan static void setDefaultView(Context context, int viewId) { 2334b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 234e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan SharedPreferences.Editor editor = prefs.edit(); 235f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang 236b60218a31d948ea0a549daf6464063d20b48421fMichael Chan boolean validDetailView = false; 237b60218a31d948ea0a549daf6464063d20b48421fMichael Chan if (mAllowWeekForDetailView && viewId == CalendarController.ViewType.WEEK) { 238b60218a31d948ea0a549daf6464063d20b48421fMichael Chan validDetailView = true; 239b60218a31d948ea0a549daf6464063d20b48421fMichael Chan } else { 240b60218a31d948ea0a549daf6464063d20b48421fMichael Chan validDetailView = viewId == CalendarController.ViewType.AGENDA 241b60218a31d948ea0a549daf6464063d20b48421fMichael Chan || viewId == CalendarController.ViewType.DAY; 242b60218a31d948ea0a549daf6464063d20b48421fMichael Chan } 243b60218a31d948ea0a549daf6464063d20b48421fMichael Chan 244b60218a31d948ea0a549daf6464063d20b48421fMichael Chan if (validDetailView) { 245b60218a31d948ea0a549daf6464063d20b48421fMichael Chan // Record the detail start view 2464b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa editor.putInt(GeneralPreferences.KEY_DETAILED_VIEW, viewId); 247e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan } 248e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan 249e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan // Record the (new) start view 2504b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa editor.putInt(GeneralPreferences.KEY_START_VIEW, viewId); 25124fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick editor.apply(); 252e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan } 253e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan 254a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik public static MatrixCursor matrixCursorFromCursor(Cursor cursor) { 255a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); 256a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik int numColumns = cursor.getColumnCount(); 257a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik String data[] = new String[numColumns]; 258a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik cursor.moveToPosition(-1); 259a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik while (cursor.moveToNext()) { 260a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik for (int i = 0; i < numColumns; i++) { 261a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik data[i] = cursor.getString(i); 262a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 263a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik newCursor.addRow(data); 264a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 265a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return newCursor; 266a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 267a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 268a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik /** 269a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik * Compares two cursors to see if they contain the same data. 270a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik * 2717b92da258a480284dcc15a518ea570072329a31dErik * @return Returns true of the cursors contain the same data and are not 2727b92da258a480284dcc15a518ea570072329a31dErik * null, false otherwise 273a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik */ 274a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik public static boolean compareCursors(Cursor c1, Cursor c2) { 2757b92da258a480284dcc15a518ea570072329a31dErik if (c1 == null || c2 == null) { 276a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return false; 277a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 278a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 279a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik int numColumns = c1.getColumnCount(); 280a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik if (numColumns != c2.getColumnCount()) { 281a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return false; 282a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 283a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 284a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik if (c1.getCount() != c2.getCount()) { 285a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return false; 286a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 287a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 288a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik c1.moveToPosition(-1); 289a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik c2.moveToPosition(-1); 2907b92da258a480284dcc15a518ea570072329a31dErik while (c1.moveToNext() && c2.moveToNext()) { 2917b92da258a480284dcc15a518ea570072329a31dErik for (int i = 0; i < numColumns; i++) { 2927b92da258a480284dcc15a518ea570072329a31dErik if (!TextUtils.equals(c1.getString(i), c2.getString(i))) { 293a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return false; 294a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 295a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 296a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 297a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 298a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik return true; 299a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik } 300a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik 301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * If the given intent specifies a time (in milliseconds since the epoch), 303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * then that time is returned. Otherwise, the current time is returned. 304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public static final long timeFromIntentInMillis(Intent intent) { 3067b92da258a480284dcc15a518ea570072329a31dErik // If the time was specified, then use that. Otherwise, use the current 3077b92da258a480284dcc15a518ea570072329a31dErik // time. 3081ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik Uri data = intent.getData(); 309a27a886892fe3ec5edbc63c0b58e0a988623011aRoboErik long millis = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, -1); 3101ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik if (millis == -1 && data != null && data.isHierarchical()) { 3111ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik List<String> path = data.getPathSegments(); 3127b92da258a480284dcc15a518ea570072329a31dErik if (path.size() == 2 && path.get(0).equals("time")) { 3131ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik try { 3141ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik millis = Long.valueOf(data.getLastPathSegment()); 3151ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik } catch (NumberFormatException e) { 3167b92da258a480284dcc15a518ea570072329a31dErik Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " 3177b92da258a480284dcc15a518ea570072329a31dErik + "found. Using current time."); 3181ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik } 3191ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik } 3201ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik } 32176727b7a9cf780f200414548b9d454bf9a701e3eErik if (millis <= 0) { 322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project millis = System.currentTimeMillis(); 323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return millis; 325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 3287b92da258a480284dcc15a518ea570072329a31dErik * Formats the given Time object so that it gives the month and year (for 3297b92da258a480284dcc15a518ea570072329a31dErik * example, "September 2007"). 330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @param time the time to format 332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * @return the string containing the weekday and the date 333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 334ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan public static String formatMonthYear(Context context, Time time) { 335cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY 336cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik | DateUtils.FORMAT_SHOW_YEAR; 337cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik long millis = time.toMillis(true); 338cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik return formatDateRange(context, millis, millis, flags); 339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project /** 3424c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * Returns a list joined together by the provided delimiter, for example, 3434c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * ["a", "b", "c"] could be joined into "a,b,c" 3444c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * 3454c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * @param things the things to join together 3464c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * @param delim the delimiter to use 3474c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang * @return a string contained the things joined together 3484c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang */ 3494c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang public static String join(List<?> things, String delim) { 3504c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang StringBuilder builder = new StringBuilder(); 3514c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang boolean first = true; 3524c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang for (Object thing : things) { 3534c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang if (first) { 3544c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang first = false; 3554c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang } else { 3564c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang builder.append(delim); 3574c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang } 3584c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang builder.append(thing.toString()); 3594c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang } 3604c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang return builder.toString(); 3614c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang } 3624c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang 3634c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang /** 364981874e61ecf29a96a77601a3172b2503b6537eeErik * Returns the week since {@link Time#EPOCH_JULIAN_DAY} (Jan 1, 1970) 365981874e61ecf29a96a77601a3172b2503b6537eeErik * adjusted for first day of week. 366981874e61ecf29a96a77601a3172b2503b6537eeErik * 367981874e61ecf29a96a77601a3172b2503b6537eeErik * This takes a julian day and the week start day and calculates which 368981874e61ecf29a96a77601a3172b2503b6537eeErik * week since {@link Time#EPOCH_JULIAN_DAY} that day occurs in, starting 369981874e61ecf29a96a77601a3172b2503b6537eeErik * at 0. *Do not* use this to compute the ISO week number for the year. 370981874e61ecf29a96a77601a3172b2503b6537eeErik * 371981874e61ecf29a96a77601a3172b2503b6537eeErik * @param julianDay The julian day to calculate the week number for 372981874e61ecf29a96a77601a3172b2503b6537eeErik * @param firstDayOfWeek Which week day is the first day of the week, 373981874e61ecf29a96a77601a3172b2503b6537eeErik * see {@link Time#SUNDAY} 374981874e61ecf29a96a77601a3172b2503b6537eeErik * @return Weeks since the epoch 375981874e61ecf29a96a77601a3172b2503b6537eeErik */ 376981874e61ecf29a96a77601a3172b2503b6537eeErik public static int getWeeksSinceEpochFromJulianDay(int julianDay, int firstDayOfWeek) { 377981874e61ecf29a96a77601a3172b2503b6537eeErik int diff = Time.THURSDAY - firstDayOfWeek; 378981874e61ecf29a96a77601a3172b2503b6537eeErik if (diff < 0) { 379981874e61ecf29a96a77601a3172b2503b6537eeErik diff += 7; 380981874e61ecf29a96a77601a3172b2503b6537eeErik } 381981874e61ecf29a96a77601a3172b2503b6537eeErik int refDay = Time.EPOCH_JULIAN_DAY - diff; 382981874e61ecf29a96a77601a3172b2503b6537eeErik return (julianDay - refDay) / 7; 383981874e61ecf29a96a77601a3172b2503b6537eeErik } 384981874e61ecf29a96a77601a3172b2503b6537eeErik 385981874e61ecf29a96a77601a3172b2503b6537eeErik /** 386981874e61ecf29a96a77601a3172b2503b6537eeErik * Takes a number of weeks since the epoch and calculates the Julian day of 387981874e61ecf29a96a77601a3172b2503b6537eeErik * the Monday for that week. 388981874e61ecf29a96a77601a3172b2503b6537eeErik * 389981874e61ecf29a96a77601a3172b2503b6537eeErik * This assumes that the week containing the {@link Time#EPOCH_JULIAN_DAY} 390981874e61ecf29a96a77601a3172b2503b6537eeErik * is considered week 0. It returns the Julian day for the Monday 391981874e61ecf29a96a77601a3172b2503b6537eeErik * {@code week} weeks after the Monday of the week containing the epoch. 392981874e61ecf29a96a77601a3172b2503b6537eeErik * 393981874e61ecf29a96a77601a3172b2503b6537eeErik * @param week Number of weeks since the epoch 394981874e61ecf29a96a77601a3172b2503b6537eeErik * @return The julian day for the Monday of the given week since the epoch 395981874e61ecf29a96a77601a3172b2503b6537eeErik */ 396981874e61ecf29a96a77601a3172b2503b6537eeErik public static int getJulianMondayFromWeeksSinceEpoch(int week) { 397981874e61ecf29a96a77601a3172b2503b6537eeErik return MONDAY_BEFORE_JULIAN_EPOCH + week * 7; 398981874e61ecf29a96a77601a3172b2503b6537eeErik } 399981874e61ecf29a96a77601a3172b2503b6537eeErik 400981874e61ecf29a96a77601a3172b2503b6537eeErik /** 40156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * Get first day of week as android.text.format.Time constant. 4027b92da258a480284dcc15a518ea570072329a31dErik * 40356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @return the first day of week in android.text.format.Time 40456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi */ 4058e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang public static int getFirstDayOfWeek(Context context) { 4064b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 4077b92da258a480284dcc15a518ea570072329a31dErik String pref = prefs.getString( 4087b92da258a480284dcc15a518ea570072329a31dErik GeneralPreferences.KEY_WEEK_START_DAY, GeneralPreferences.WEEK_START_DEFAULT); 4098e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang 4108e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang int startDay; 4114b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa if (GeneralPreferences.WEEK_START_DEFAULT.equals(pref)) { 4128e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang startDay = Calendar.getInstance().getFirstDayOfWeek(); 4138e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang } else { 4148e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang startDay = Integer.parseInt(pref); 4158e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang } 4168e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang 41756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi if (startDay == Calendar.SATURDAY) { 41856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi return Time.SATURDAY; 41956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } else if (startDay == Calendar.MONDAY) { 42056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi return Time.MONDAY; 42156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } else { 42256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi return Time.SUNDAY; 42356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } 42456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } 42556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi 42656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi /** 427d644b0df14ae6e204369b3454d16976fba32f15cDaisuke Miyakawa * @return true when week number should be shown. 428981874e61ecf29a96a77601a3172b2503b6537eeErik */ 429981874e61ecf29a96a77601a3172b2503b6537eeErik public static boolean getShowWeekNumber(Context context) { 430d644b0df14ae6e204369b3454d16976fba32f15cDaisuke Miyakawa final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 431981874e61ecf29a96a77601a3172b2503b6537eeErik return prefs.getBoolean( 432981874e61ecf29a96a77601a3172b2503b6537eeErik GeneralPreferences.KEY_SHOW_WEEK_NUM, GeneralPreferences.DEFAULT_SHOW_WEEK_NUM); 433981874e61ecf29a96a77601a3172b2503b6537eeErik } 434981874e61ecf29a96a77601a3172b2503b6537eeErik 435981874e61ecf29a96a77601a3172b2503b6537eeErik /** 43640bcd101b212c9863c3110c05a487a7ae6ebc3caErik * @return true when declined events should be hidden. 43740bcd101b212c9863c3110c05a487a7ae6ebc3caErik */ 43840bcd101b212c9863c3110c05a487a7ae6ebc3caErik public static boolean getHideDeclinedEvents(Context context) { 43940bcd101b212c9863c3110c05a487a7ae6ebc3caErik final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 44040bcd101b212c9863c3110c05a487a7ae6ebc3caErik return prefs.getBoolean(GeneralPreferences.KEY_HIDE_DECLINED, false); 44140bcd101b212c9863c3110c05a487a7ae6ebc3caErik } 44240bcd101b212c9863c3110c05a487a7ae6ebc3caErik 44391b01ed605e36fc5a7a924c226597a62c789b50dErik public static int getDaysPerWeek(Context context) { 44491b01ed605e36fc5a7a924c226597a62c789b50dErik final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context); 44591b01ed605e36fc5a7a924c226597a62c789b50dErik return prefs.getInt(GeneralPreferences.KEY_DAYS_PER_WEEK, 7); 44691b01ed605e36fc5a7a924c226597a62c789b50dErik } 44791b01ed605e36fc5a7a924c226597a62c789b50dErik 44840bcd101b212c9863c3110c05a487a7ae6ebc3caErik /** 44956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * Determine whether the column position is Saturday or not. 4507b92da258a480284dcc15a518ea570072329a31dErik * 45156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @param column the column position 45256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @param firstDayOfWeek the first day of week in android.text.format.Time 45356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @return true if the column is Saturday position 45456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi */ 45556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi public static boolean isSaturday(int column, int firstDayOfWeek) { 45656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi return (firstDayOfWeek == Time.SUNDAY && column == 6) 4577b92da258a480284dcc15a518ea570072329a31dErik || (firstDayOfWeek == Time.MONDAY && column == 5) 4587b92da258a480284dcc15a518ea570072329a31dErik || (firstDayOfWeek == Time.SATURDAY && column == 0); 45956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } 46056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi 46156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi /** 46256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * Determine whether the column position is Sunday or not. 4637b92da258a480284dcc15a518ea570072329a31dErik * 46456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @param column the column position 46556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @param firstDayOfWeek the first day of week in android.text.format.Time 46656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi * @return true if the column is Sunday position 46756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi */ 46856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi public static boolean isSunday(int column, int firstDayOfWeek) { 46956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi return (firstDayOfWeek == Time.SUNDAY && column == 0) 4707b92da258a480284dcc15a518ea570072329a31dErik || (firstDayOfWeek == Time.MONDAY && column == 6) 4717b92da258a480284dcc15a518ea570072329a31dErik || (firstDayOfWeek == Time.SATURDAY && column == 1); 47256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi } 473ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan 474ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan /** 4759da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik * Convert given UTC time into current local time. This assumes it is for an 4769da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik * allday event and will adjust the time to be on a midnight boundary. 4773ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * 4783ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * @param recycle Time object to recycle, otherwise null. 4793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang * @param utcTime Time to convert, in UTC. 4809da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik * @param tz The time zone to convert this time to. 4813ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang */ 4829da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik public static long convertAlldayUtcToLocal(Time recycle, long utcTime, String tz) { 4833ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang if (recycle == null) { 4843ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang recycle = new Time(); 4853ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 4863ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang recycle.timezone = Time.TIMEZONE_UTC; 4873ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang recycle.set(utcTime); 4889da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik recycle.timezone = tz; 4899da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik return recycle.normalize(true); 4909da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik } 4919da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik 4929da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik public static long convertAlldayLocalToUTC(Time recycle, long localTime, String tz) { 4939da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik if (recycle == null) { 4949da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik recycle = new Time(); 4959da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik } 4969da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik recycle.timezone = tz; 4979da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik recycle.set(localTime); 4989da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik recycle.timezone = Time.TIMEZONE_UTC; 4993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang return recycle.normalize(true); 5003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang } 5013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang 5023ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang /** 503ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan * Scan through a cursor of calendars and check if names are duplicated. 5047b92da258a480284dcc15a518ea570072329a31dErik * This travels a cursor containing calendar display names and fills in the 5057b92da258a480284dcc15a518ea570072329a31dErik * provided map with whether or not each name is repeated. 506ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan * 507ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan * @param isDuplicateName The map to put the duplicate check results in. 508ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan * @param cursor The query of calendars to check 509ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan * @param nameIndex The column of the query that contains the display name 510ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan */ 5117b92da258a480284dcc15a518ea570072329a31dErik public static void checkForDuplicateNames( 5127b92da258a480284dcc15a518ea570072329a31dErik Map<String, Boolean> isDuplicateName, Cursor cursor, int nameIndex) { 513ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan isDuplicateName.clear(); 514ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan cursor.moveToPosition(-1); 515ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan while (cursor.moveToNext()) { 516ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan String displayName = cursor.getString(nameIndex); 517ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan // Set it to true if we've seen this name before, false otherwise 518ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan if (displayName != null) { 519ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName)); 520ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan } 521ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan } 522ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan } 5239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang 5249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang /** 5259138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang * Null-safe object comparison 5267b92da258a480284dcc15a518ea570072329a31dErik * 5279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang * @param s1 5289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang * @param s2 5299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang * @return 5309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang */ 5319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang public static boolean equals(Object o1, Object o2) { 5329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang return o1 == null ? o2 == null : o1.equals(o2); 5339138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang } 534b60218a31d948ea0a549daf6464063d20b48421fMichael Chan 53563cd053150e00fde045b019dbe0f48b8a9ed3559Erik public static void setAllowWeekForDetailView(boolean allowWeekView) { 536b60218a31d948ea0a549daf6464063d20b48421fMichael Chan mAllowWeekForDetailView = allowWeekView; 537b60218a31d948ea0a549daf6464063d20b48421fMichael Chan } 53863cd053150e00fde045b019dbe0f48b8a9ed3559Erik 53963cd053150e00fde045b019dbe0f48b8a9ed3559Erik public static boolean getAllowWeekForDetailView() { 54063cd053150e00fde045b019dbe0f48b8a9ed3559Erik return mAllowWeekForDetailView; 54163cd053150e00fde045b019dbe0f48b8a9ed3559Erik } 5420b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson 5430b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson public static boolean isMultiPaneConfiguration (Context c) { 5440b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson return (c.getResources().getConfiguration().screenLayout & 5450b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson Configuration.SCREENLAYOUT_SIZE_XLARGE) != 0; 5460b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson } 547ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson 548ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson public static boolean getConfigBool(Context c, int key) { 549ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson return c.getResources().getBoolean(key); 550ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson } 55182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 55282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 55371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson /** 55472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * This is a helper class for the createBusyBitSegments method 55572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The class contains information about a specific time that corresponds to either a start 55672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * of an event or an end of an event (or both): 55772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * 1. The time itself 55872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * 2 .The number of event starts and ends (number of starts - number of ends) 55972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson */ 56082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 56172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson private static class BusyBitsEventTime { 56282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 56372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public static final int EVENT_START = 1; 56472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public static final int EVENT_END = -1; 565c18dd7aea8c8ee06dd34f268ea9e0e9e7c235b7fIsaac Katzenelson 56672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public int mTime; // in minutes 56772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Number of events that start and end in this time (+1 for each start, 56872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // -1 for each end) 56972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public int mStartEndChanges; 57072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 57172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public BusyBitsEventTime(int t, int c) { 57272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson mTime = t; 57372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson mStartEndChanges = c; 574c18dd7aea8c8ee06dd34f268ea9e0e9e7c235b7fIsaac Katzenelson } 57572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 57672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public void addStart() { 57772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson mStartEndChanges++; 578c18dd7aea8c8ee06dd34f268ea9e0e9e7c235b7fIsaac Katzenelson } 579c18dd7aea8c8ee06dd34f268ea9e0e9e7c235b7fIsaac Katzenelson 58072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson public void addEnd() { 58172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson mStartEndChanges--; 58272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 58372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 58472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 58572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson /** 58672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * Corrects segments that are overlapping. 58771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * The function makes sure the last segment inserted do not overlap with segments in the 58871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * segments arrays. It will compare the last inserted segment to last segment in both the 58971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * busy array and conflicting array and make corrections to segments if necessary. 59072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The function assumes an overlap could be only 1 pixel. 59172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The function removes segments if necessary 59272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * Segment size is from start to end (inclusive) 59372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * 59471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @param segments segments an array of 2 float arrays. The first array will contain the 59571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * coordinates for drawing busy segments, the second will contain the coordinates for 59671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * drawing conflicting segments. The first cell in each array contains the number of 59771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * used cell so this method can be called again without overriding data, 59871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @param arrayIndex - index of the segments array that got the last segment 59971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @param prevSegmentInserted - an indicator of the type of the previous segment inserted. This 60071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * 60171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @return boolean telling the calling functions whether to add the last segment or not. 60271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * The calling function should first insert a new segment to the array, call this 60371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * function and when getting a "true" value in the return value, update the counter of 60471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * the array to indicate a new segment (Add 4 to the counter in cell 0). 60572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson */ 60672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 60771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int START_PIXEL_Y = 1; // index of pixel locations in a coordinates set 60871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int END_PIXEL_Y = 3; 60971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int BUSY_ARRAY_INDEX = 0; 61071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int CONFLICT_ARRAY_INDEX = 1; 61171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int COUNTER_INDEX = 0; 61272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 61371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int NO_PREV_INSERTED = 0; // possible status of previous segment insertion 61471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int BUSY_PREV_INSERTED = 1; 61571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson static final int CONFLICT_PREV_INSERTED = 2; 61672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 61772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 61871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson public static boolean correctOverlappingSegment(float[][] segments, 61971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int arrayIndex, int prevSegmentInserted) { 62071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 62171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (prevSegmentInserted == NO_PREV_INSERTED) { 62271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // First segment - add it 62371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 62472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 62571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 62671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Previous insert and this one are to the busy array 62771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (prevSegmentInserted == BUSY_PREV_INSERTED && arrayIndex == BUSY_ARRAY_INDEX) { 62871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 62971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Index of last and previously inserted segment 63071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iLast = 1 + (int) segments[BUSY_ARRAY_INDEX][COUNTER_INDEX]; 63171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iPrev = 1 + (int) segments[BUSY_ARRAY_INDEX][COUNTER_INDEX] - 4; 63271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 63371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments do not overlap - add the new one 63471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[BUSY_ARRAY_INDEX][iPrev + END_PIXEL_Y] < 63571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iLast + START_PIXEL_Y]) { 63671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 63771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 63871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 63971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments overlap - merge them 64071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iPrev + END_PIXEL_Y] = 64171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iLast + END_PIXEL_Y]; 64271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return false; 64372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 64472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 64571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Previous insert was to the busy array and this one is to the conflict array 64671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (prevSegmentInserted == BUSY_PREV_INSERTED && arrayIndex == CONFLICT_ARRAY_INDEX) { 64771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 64871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Index of last and previously inserted segment 64971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iLast = 1 + (int) segments[CONFLICT_ARRAY_INDEX][COUNTER_INDEX]; 65071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iPrev = 1 + (int) segments[BUSY_ARRAY_INDEX][COUNTER_INDEX] - 4; 65171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 65271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments do not overlap - add the new one 65371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[BUSY_ARRAY_INDEX][iPrev + END_PIXEL_Y] < 65471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[CONFLICT_ARRAY_INDEX][iLast + START_PIXEL_Y]) { 65571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 65672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 65771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 65871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments overlap - truncate the end of the last busy segment 65971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // if it disappears , remove it 66071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iPrev + END_PIXEL_Y]--; 66171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[BUSY_ARRAY_INDEX][iPrev + END_PIXEL_Y] < 66271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iPrev + START_PIXEL_Y]) { 66371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX] [COUNTER_INDEX] -= 4; 66472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 66571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 66671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 66771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Previous insert was to the conflict array and this one is to the busy array 66871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (prevSegmentInserted == CONFLICT_PREV_INSERTED && arrayIndex == BUSY_ARRAY_INDEX) { 66971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 67071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Index of last and previously inserted segment 67171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iLast = 1 + (int) segments[BUSY_ARRAY_INDEX][COUNTER_INDEX]; 67271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iPrev = 1 + (int) segments[CONFLICT_ARRAY_INDEX][COUNTER_INDEX] - 4; 67371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 67471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments do not overlap - add the new one 67571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[CONFLICT_ARRAY_INDEX][iPrev + END_PIXEL_Y] < 67671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iLast + START_PIXEL_Y]) { 67771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 67872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 67971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 68071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments overlap - truncate the new busy segment , if it disappears , do not 68171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // insert it 68271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iLast + START_PIXEL_Y]++; 68371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[BUSY_ARRAY_INDEX][iLast + START_PIXEL_Y] > 68471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[BUSY_ARRAY_INDEX][iLast + END_PIXEL_Y]) { 68571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return false; 68671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 68771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 68871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 68972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 69071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Previous insert and this one are to the conflict array 69171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (prevSegmentInserted == CONFLICT_PREV_INSERTED && arrayIndex == CONFLICT_ARRAY_INDEX) { 69271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 69371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Index of last and previously inserted segment 69471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iLast = 1 + (int) segments[CONFLICT_ARRAY_INDEX][COUNTER_INDEX]; 69571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iPrev = 1 + (int) segments[CONFLICT_ARRAY_INDEX][COUNTER_INDEX] - 4; 69682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 69771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments do not overlap - add the new one 69871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (segments[CONFLICT_ARRAY_INDEX][iPrev + END_PIXEL_Y] < 69971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[CONFLICT_ARRAY_INDEX][iLast + START_PIXEL_Y]) { 70071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return true; 70171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 70271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 70371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Segments overlap - merge them 70471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[CONFLICT_ARRAY_INDEX][iPrev + END_PIXEL_Y] = 70571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments[CONFLICT_ARRAY_INDEX][iLast + END_PIXEL_Y]; 70671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return false; 70771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 70871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Unknown state , complain 70971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson Log.wtf(TAG, "Unkown state in correctOverlappingSegment: prevSegmentInserted = " + 71071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted + " arrayIndex = " + arrayIndex); 71171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return false; 71271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 71372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 71472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson /** 71572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * Converts a list of events to a list of busy segments to draw. 71672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * Assumes list is ordered according to start time of events 71772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The function processes events of a specific day only or part of that day 71872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * 71972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The algorithm goes over all the events and creates an ordered list of times. 72072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * Each item on the list corresponds to a time where an event started,ended or both. 72172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The item has a count of how many events started and how many events ended at that time. 72272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * In the second stage, the algorithm go over the list of times and finds what change happened 72371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * at each time. A change can be a switch between either of the free time/busy time/conflicting 72472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * time. Every time a change happens, the algorithm creates a segment (in pixels) to be 72571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * displayed with the relevant status (free/busy/conflicting). 72672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * The algorithm also checks if segments overlap and truncates one of them if needed. 72772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * 72872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param startPixel defines the start of the draw area 72972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param endPixel defines the end of the draw area 73071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @param xPixel the middle X position of the draw area 73172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param startTimeMinute start time (in minutes) of the time frame to be displayed as busy bits 73272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param endTimeMinute end time (in minutes) of the time frame to be displayed as busy bits 73372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param julianDay the day of the time frame 73472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * @param daysEvents - a list of events that took place in the specified day (including 73572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * recurring events, events that start before the day and/or end after 73672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson * the day 73771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * @param segments an array of 2 float arrays. The first array will contain the coordinates 73871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * for drawing busy segments, the second will contain the coordinates for drawing 73971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * conflicting segments. The first cell in each array contains the number of used cell 74071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * so this method can be called again without overriding data, 74171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson * 74272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson */ 74372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 74471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson public static void createBusyBitSegments(int startPixel, int endPixel, 74571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int xPixel, int startTimeMinute, int endTimeMinute, int julianDay, 74671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson ArrayList<Event> daysEvents, float [] [] segments) { 74772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 74872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // No events or illegal parameters , do nothing 74972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 75072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (daysEvents == null || daysEvents.size() == 0 || startPixel >= endPixel || 75172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson startTimeMinute < 0 || startTimeMinute > 24 * 60 || endTimeMinute < 0 || 75271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson endTimeMinute > 24 * 60 || startTimeMinute >= endTimeMinute || 75371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson segments == null || segments [0] == null || segments [1] == null) { 75472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Log.wtf(TAG, "Illegal parameter in createBusyBitSegments, " + 75572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson "daysEvents = " + daysEvents + " , " + 75672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson "startPixel = " + startPixel + " , " + 75772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson "endPixel = " + endPixel + " , " + 75872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson "startTimeMinute = " + startTimeMinute + " , " + 75971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson "endTimeMinute = " + endTimeMinute + " , " + 76071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson "segments" + segments); 76171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return; 76272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 76372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 76472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Go over all events and create a sorted list of times that include all 76572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // the start and end times of all events. 76672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 76772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson ArrayList<BusyBitsEventTime> times = new ArrayList<BusyBitsEventTime>(); 76872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 76972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Iterator<Event> iter = daysEvents.iterator(); 77072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Pointer to the search start in the "times" list. It prevents searching from the beginning 77172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // of the list for each event. It is updated every time a new start time is inserted into 77272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // the times list, since the events are time ordered, there is no point on searching before 77372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // the last start time that was inserted 77472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int initialSearchIndex = 0; 77582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson while (iter.hasNext()) { 77682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson Event event = iter.next(); 77782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 77872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Take into account the start and end day. This is important for events that span 77972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // multiple days. 78072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int eStart = event.startTime - (julianDay - event.startDay) * 24 * 60; 78172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int eEnd = event.endTime + (event.endDay - julianDay) * 24 * 60; 78282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 78372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Skip all day events, and events that are not in the time frame 78472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (event.drawAsAllday() || eStart >= endTimeMinute || eEnd <= startTimeMinute) { 78582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson continue; 78682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 78782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 788c18dd7aea8c8ee06dd34f268ea9e0e9e7c235b7fIsaac Katzenelson // If event spans before or after start or end time , truncate it 78972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // because we care only about the time span that is passed to the function 79072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (eStart < startTimeMinute) { 79172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson eStart = startTimeMinute; 79272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 79372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (eEnd > endTimeMinute) { 79472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson eEnd = endTimeMinute; 79582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 79672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Skip events that are zero length 79772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (eStart == eEnd) { 79872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson continue; 79982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 80082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 80172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // First event , just put it in the "times" list 80272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (times.size() == 0) { 80372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime es = new BusyBitsEventTime(eStart, BusyBitsEventTime.EVENT_START); 80472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime ee = new BusyBitsEventTime(eEnd, BusyBitsEventTime.EVENT_END); 80572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(es); 80672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(ee); 80782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson continue; 80882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 80982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 81072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Insert start and end times of event in "times" list. 81172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Loop through the "times" list and put the event start and ends times in the correct 81272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // place. 81372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson boolean startInserted = false; 81472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson boolean endInserted = false; 81572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int i = initialSearchIndex; // Skip times that are before the event time 81672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Two pointers for looping through the "times" list. Current item and next item. 81772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int t1, t2; 81872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson do { 81972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson t1 = times.get(i).mTime; 82072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson t2 = times.get(i + 1).mTime; 82172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (!startInserted) { 82272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Start time equals an existing item in the "times" list, just update the 82372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // starts count of the specific item 82472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (eStart == t1) { 82572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.get(i).addStart(); 82672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson initialSearchIndex = i; 82772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson startInserted = true; 82872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } else if (eStart == t2) { 82972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.get(i + 1).addStart(); 83072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson initialSearchIndex = i + 1; 83172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson startInserted = true; 83272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } else if (eStart > t1 && eStart < t2) { 83372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // The start time is between the times of the current item and next item: 83472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // insert a new start time in between the items. 83572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime e = new BusyBitsEventTime(eStart, 83672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime.EVENT_START); 83772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(i + 1, e); 83872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson initialSearchIndex = i + 1; 83972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson t2 = eStart; 84072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson startInserted = true; 84172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 84282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 84372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (!endInserted) { 84472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // End time equals an existing item in the "times" list, just update the 84572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // ends count of the specific item 84672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (eEnd == t1) { 84772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.get(i).addEnd(); 84872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson endInserted = true; 84972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } else if (eEnd == t2) { 85072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.get(i + 1).addEnd(); 85172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson endInserted = true; 85272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } else if (eEnd > t1 && eEnd < t2) { 85372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // The end time is between the times of the current item and next item: 85472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // insert a new end time in between the items. 85572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime e = new BusyBitsEventTime(eEnd, 85672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime.EVENT_END); 85772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(i + 1, e); 85872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson t2 = eEnd; 85972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson endInserted = true; 86072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 86172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 86272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson i++; 86372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } while (!endInserted && i + 1 < times.size()); 86472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 86572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Deal with the last event if not inserted in the list 86672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (!startInserted) { 86772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime e = new BusyBitsEventTime(eStart, BusyBitsEventTime.EVENT_START); 86872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(e); 86972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson initialSearchIndex = times.size() - 1; 87072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 87172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (!endInserted) { 87272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime e = new BusyBitsEventTime(eEnd, BusyBitsEventTime.EVENT_END); 87372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson times.add(e); 87482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 87582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 87682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson 87772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // No events , return 87872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (times.size() == 0) { 87971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return; 88072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 88172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 88271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Loop through the created "times" list and find busy time segments and conflicting 88371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // segments. In the loop, keep the status of time (free/busy/conflicting) and the time 88472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // of when last status started. When there is a change in the status, create a segment with 88572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // the previous status from the time of the last status started until the time of the 88672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // current change. 88771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // The loop keeps a count of how many events are conflicting. Zero means free time, one 88871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // means a busy time and more than one means conflicting time. The count is updated by 88972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // the number of starts and ends from the items in the "times" list. A change is a switch 89071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // from free/busy/conflicting status to a different one. 89172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 89272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 89372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int segmentStartTime = 0; // default start time 89471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int conflictingCount = 0; // assume starting with free time 89572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int pixelSize = endPixel - startPixel; 89672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson int timeFrame = endTimeMinute - startTimeMinute; 89771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int prevSegmentInserted = NO_PREV_INSERTED; 89871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 89971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson 90071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Arrays are preallocated by the calling code, the first cell in the 90171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // array is the number 90271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // of already occupied cells. 90371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson float[] busySegments = segments[BUSY_ARRAY_INDEX]; 90471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson float[] conflictSegments = segments[CONFLICT_ARRAY_INDEX]; 90572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 90672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Iterator<BusyBitsEventTime> tIter = times.iterator(); 90772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson while (tIter.hasNext()) { 90872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson BusyBitsEventTime t = tIter.next(); 90971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Get the new count of conflicting events 91071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int newCount = conflictingCount + t.mStartEndChanges; 91172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson 91271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // No need for a new segment because the free/busy/conflicting 91371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // status didn't change 91471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (conflictingCount == newCount || (conflictingCount >= 2 && newCount >= 2)) { 91571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictingCount = newCount; 91672a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson continue; 91772a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 91871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (conflictingCount == 0 && newCount == 1) { 91972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // A busy time started - start a new segment 92072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (segmentStartTime != 0) { 92172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Unknown status, blow up 92272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Log.wtf(TAG, "Unknown state in createBusyBitSegments, segmentStartTime = " + 92372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime + ", nolc = " + newCount); 92472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 92572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = t.mTime; 92671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } else if (conflictingCount == 0 && newCount >= 2) { 92771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // An conflicting time started - start a new segment 92872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson if (segmentStartTime != 0) { 92972a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Unknown status, blow up 93072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Log.wtf(TAG, "Unknown state in createBusyBitSegments, segmentStartTime = " + 93172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime + ", nolc = " + newCount); 93272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 93372a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = t.mTime; 93471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } else if (conflictingCount == 1 && newCount >= 2) { 93571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // A busy time ended and conflicting segment started, 93671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Save busy segment and start conflicting segment 93771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iBusy = 1 + (int) busySegments[COUNTER_INDEX]; 93871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = xPixel; 93971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = (segmentStartTime - startTimeMinute) * 94071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 94171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = xPixel; 94271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = (t.mTime - startTimeMinute) * 94371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 94471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Update the segments counter only after overlap correction 94571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (correctOverlappingSegment(segments, BUSY_ARRAY_INDEX, prevSegmentInserted)) { 94671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[COUNTER_INDEX] += 4; 94771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 94872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = t.mTime; 94971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted = BUSY_PREV_INSERTED; 95071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } else if (conflictingCount >= 2 && newCount == 1) { 95171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // A conflicting time ended and busy segment started. 95271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Save conflicting segment and start busy segment 95371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iConflicting = 1 + (int) conflictSegments[COUNTER_INDEX]; 95471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = xPixel; 95571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = (segmentStartTime - startTimeMinute) * 95671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 95771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = xPixel; 95871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = (t.mTime - startTimeMinute) * 95971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 96071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Update the segments counter only after overlap correction 96171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (correctOverlappingSegment(segments, CONFLICT_ARRAY_INDEX, 96271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted)) { 96371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[COUNTER_INDEX] += 4; 96471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 96572a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = t.mTime; 96671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted = CONFLICT_PREV_INSERTED; 96771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } else if (conflictingCount >= 2 && newCount == 0) { 96871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // An conflicting segment ended, and a free time segment started 96971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Save conflicting segment 97071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iConflicting = 1 + (int) conflictSegments[COUNTER_INDEX]; 97171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = xPixel; 97271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = (segmentStartTime - startTimeMinute) * 97371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 97471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = xPixel; 97571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[iConflicting++] = (t.mTime - startTimeMinute) * 97671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 97771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Update the segments counter only after overlap correction 97871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (correctOverlappingSegment(segments, CONFLICT_ARRAY_INDEX, 97971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted)) { 98071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictSegments[COUNTER_INDEX] += 4; 98171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 98272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = 0; 98371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted = CONFLICT_PREV_INSERTED; 98471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } else if (conflictingCount == 1 && newCount == 0) { 98571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // A busy segment ended, and a free time segment started, save 98671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // busy segment 98771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson int iBusy = 1 + (int) busySegments[COUNTER_INDEX]; 98871b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = xPixel; 98971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = (segmentStartTime - startTimeMinute) * 99071b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 99171b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = xPixel; 99271b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[iBusy++] = (t.mTime - startTimeMinute) * 99371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson pixelSize / timeFrame + startPixel; 99471b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson // Update the segments counter only after overlap correction 99571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson if (correctOverlappingSegment(segments, BUSY_ARRAY_INDEX, prevSegmentInserted)) { 99671b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson busySegments[COUNTER_INDEX] += 4; 99771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson } 99872a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson segmentStartTime = 0; 99971b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson prevSegmentInserted = BUSY_PREV_INSERTED; 100072a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } else { 100172a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson // Unknown status, blow up 100272a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson Log.wtf(TAG, "Unknown state in createBusyBitSegments: time = " + t.mTime + 100371b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson " , olc = " + conflictingCount + " nolc = " + newCount); 100472a9459e1f4cec02ad9e8dbdf824d66920b762eeIsaac Katzenelson } 100571b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson conflictingCount = newCount; // Update count 100682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 100771b9ce3a20ebaff8f7e40fc0e5ec2a388bcc394cIsaac Katzenelson return; 100882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson } 1009146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project} 1010