15862a85e17e81866ca82a9905577931947fbd44eMarc Blank/* 25862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Copyright (C) 2010 The Android Open Source Project 35862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 45862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 55862a85e17e81866ca82a9905577931947fbd44eMarc Blank * you may not use this file except in compliance with the License. 65862a85e17e81866ca82a9905577931947fbd44eMarc Blank * You may obtain a copy of the License at 75862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 85862a85e17e81866ca82a9905577931947fbd44eMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 95862a85e17e81866ca82a9905577931947fbd44eMarc Blank * 105862a85e17e81866ca82a9905577931947fbd44eMarc Blank * Unless required by applicable law or agreed to in writing, software 115862a85e17e81866ca82a9905577931947fbd44eMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 125862a85e17e81866ca82a9905577931947fbd44eMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135862a85e17e81866ca82a9905577931947fbd44eMarc Blank * See the License for the specific language governing permissions and 145862a85e17e81866ca82a9905577931947fbd44eMarc Blank * limitations under the License. 155862a85e17e81866ca82a9905577931947fbd44eMarc Blank */ 165862a85e17e81866ca82a9905577931947fbd44eMarc Blank 175862a85e17e81866ca82a9905577931947fbd44eMarc Blankpackage com.android.exchange.utility; 185862a85e17e81866ca82a9905577931947fbd44eMarc Blank 193f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.content.ContentValues; 203f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.content.Entity; 213f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.content.res.Resources; 223f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.provider.CalendarContract.Attendees; 233f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.provider.CalendarContract.Events; 243f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.test.suitebuilder.annotation.MediumTest; 253f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blankimport android.util.Log; 263f8e329b8d638d02e0b48ad504b18690cefc68e9Marc Blank 27c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.mail.Address; 287372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.Account; 29c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.Attachment; 30c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.Message; 31c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.utility.Utility; 32c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.exchange.R; 33f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport com.android.exchange.adapter.CalendarSyncAdapter; 34c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.exchange.adapter.CalendarSyncAdapter.EasCalendarSyncParser; 35f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport com.android.exchange.adapter.Parser; 36f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport com.android.exchange.adapter.Serializer; 37f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport com.android.exchange.adapter.SyncAdapterTestCase; 38f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport com.android.exchange.adapter.Tags; 395c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 401c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blankimport java.io.BufferedReader; 41f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankimport java.io.ByteArrayInputStream; 421c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blankimport java.io.IOException; 431c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blankimport java.io.StringReader; 449ca8918b82221dd441293973ffb84d565a52993aMarc Blankimport java.text.DateFormat; 451c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blankimport java.util.ArrayList; 46c10a3beef4f048292e6a4ceb31527c5123801517Marc Blankimport java.util.Calendar; 47820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blankimport java.util.Date; 48c10a3beef4f048292e6a4ceb31527c5123801517Marc Blankimport java.util.GregorianCalendar; 491c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blankimport java.util.HashMap; 505862a85e17e81866ca82a9905577931947fbd44eMarc Blankimport java.util.TimeZone; 515862a85e17e81866ca82a9905577931947fbd44eMarc Blank 52377230593dca7cb01483bfaf93959e5821f5f028Marc Blank/** 53377230593dca7cb01483bfaf93959e5821f5f028Marc Blank * Tests of EAS Calendar Utilities 54377230593dca7cb01483bfaf93959e5821f5f028Marc Blank * You can run this entire test case with: 55c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank * runtest -c com.android.exchange.utility.CalendarUtilitiesTests exchange 56377230593dca7cb01483bfaf93959e5821f5f028Marc Blank * 57377230593dca7cb01483bfaf93959e5821f5f028Marc Blank * Please see RFC2445 for RRULE definition 58377230593dca7cb01483bfaf93959e5821f5f028Marc Blank * http://www.ietf.org/rfc/rfc2445.txt 59377230593dca7cb01483bfaf93959e5821f5f028Marc Blank */ 60604a1cf6f2401d78f57edcfb702d560d9c80dd14Marc Blank@MediumTest 61f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blankpublic class CalendarUtilitiesTests extends SyncAdapterTestCase<CalendarSyncAdapter> { 625862a85e17e81866ca82a9905577931947fbd44eMarc Blank 635862a85e17e81866ca82a9905577931947fbd44eMarc Blank // Some prebuilt time zones, Base64 encoded (as they arrive from EAS) 64377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // More time zones to be added over time 65377230593dca7cb01483bfaf93959e5821f5f028Marc Blank 66377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // Not all time zones are appropriate for testing. For example, ISRAEL_STANDARD_TIME cannot be 67377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // used because DST is determined from year to year in a non-standard way (related to the lunar 68377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // calendar); therefore, the test would only work during the year in which it was created 6979268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank 7079268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank // This time zone has no DST 7179268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank private static final String ASIA_CALCUTTA_TIME = 725862a85e17e81866ca82a9905577931947fbd44eMarc Blank "tv7//0kAbgBkAGkAYQAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 735862a85e17e81866ca82a9905577931947fbd44eMarc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEkAbgBkAGkAYQAgAEQAYQB5AGwAaQBnAGgAdAAgAFQAaQBtAGUA" + 745862a85e17e81866ca82a9905577931947fbd44eMarc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 7579268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank 7679268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank // This time zone is equivalent to PST and uses DST 7779268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank private static final String AMERICA_DAWSON_TIME = 785862a85e17e81866ca82a9905577931947fbd44eMarc Blank "4AEAAFAAYQBjAGkAZgBpAGMAIABTAHQAYQBuAGQAYQByAGQAIABUAGkAbQBlAAAAAAAAAAAAAAAAAAAAAAAA" + 795862a85e17e81866ca82a9905577931947fbd44eMarc Blank "AAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAFAAYQBjAGkAZgBpAGMAIABEAGEAeQBsAGkAZwBoAHQAIABUAGkA" + 805862a85e17e81866ca82a9905577931947fbd44eMarc Blank "bQBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w=="; 815862a85e17e81866ca82a9905577931947fbd44eMarc Blank 8279268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank // Test a southern hemisphere time zone w/ DST 8379268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank private static final String AUSTRALIA_ACT_TIME = 8479268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank "qP3//0EAVQBTACAARQBhAHMAdABlAHIAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAA" + 8579268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank "AAAAAAAAAAQAAAABAAMAAAAAAAAAAAAAAEEAVQBTACAARQBhAHMAdABlAHIAbgAgAEQAYQB5AGwAaQBnAGgA" + 8679268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank "dAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAoAAAABAAIAAAAAAAAAxP///w=="; 8779268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank 88270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank // Test a timezone with GMT bias but bogus DST parameters (there is no equivalent time zone 89270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank // in the database) 90270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank private static final String GMT_UNKNOWN_DAYLIGHT_TIME = 91270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank "AAAAACgARwBNAFQAKwAwADAAOgAwADAAKQAgAFQAaQBtAGUAIABaAG8AbgBlAAAAAAAAAAAAAAAAAAAAAAAA" + 92270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank "AAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAACgARwBNAFQAKwAwADAAOgAwADAAKQAgAFQAaQBtAGUAIABaAG8A" + 93270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank "bgBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAEAAAAAAAAAxP///w=="; 94270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 955bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank // This time zone has no DST, but earlier, buggy code retrieved a TZ WITH DST 965bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank private static final String ARIZONA_TIME = 975bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank "pAEAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAA" + 985bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAEQAYQB5AGwAaQBnAGgA" + 995bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank "dAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 1005bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank 1014868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank private static final String HAWAII_TIME = 1024868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank "WAIAAEgAYQB3AGEAaQBpAGEAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAA" + 1034868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAYQB3AGEAaQBpAGEAbgAgAEQAYQB5AGwAaQBnAGgAdAAgAFQA" + 1044868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank "aQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; 1054868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank 1062c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank // This is time zone sent by Exchange 2007, apparently; the start time of DST for the eastern 1072c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank // time zone (EST) is off by two hours, which we should correct in our new "lenient" code 1082c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank private static final String LENIENT_EASTERN_TIME = 1092c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank "LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 1102c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank "AAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 1112c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAAAAAAAAAAAxP///w=="; 1122c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank 1137b873db28bda10f98f3782b7b161cb66117034d7Marc Blank // This string specifies "Europe/London" in the name, but otherwise is somewhat bogus 1147b873db28bda10f98f3782b7b161cb66117034d7Marc Blank // in that it has unknown time zone dates with a 0 bias (GMT). (From a Zimbra server user) 1157b873db28bda10f98f3782b7b161cb66117034d7Marc Blank private static final String EUROPE_LONDON_TIME_BY_NAME = 1167b873db28bda10f98f3782b7b161cb66117034d7Marc Blank "AAAAAEV1cm9wZS9Mb25kb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 1177b873db28bda10f98f3782b7b161cb66117034d7Marc Blank "AAAAAAAAAAoAAQAFAAIAAAAAAAAAAAAAAEV1cm9wZS9Mb25kb24AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 1187b873db28bda10f98f3782b7b161cb66117034d7Marc Blank "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQAFAAEAAAAAAAAAxP///w=="; 1197b873db28bda10f98f3782b7b161cb66117034d7Marc Blank 1209ca8918b82221dd441293973ffb84d565a52993aMarc Blank private static final String ORGANIZER = "organizer@server.com"; 1219ca8918b82221dd441293973ffb84d565a52993aMarc Blank private static final String ATTENDEE = "attendee@server.com"; 1229ca8918b82221dd441293973ffb84d565a52993aMarc Blank 1235862a85e17e81866ca82a9905577931947fbd44eMarc Blank public void testGetSet() { 1245862a85e17e81866ca82a9905577931947fbd44eMarc Blank byte[] bytes = new byte[] {0, 1, 2, 3, 4, 5, 6, 7}; 1255862a85e17e81866ca82a9905577931947fbd44eMarc Blank 1265862a85e17e81866ca82a9905577931947fbd44eMarc Blank // First, check that getWord/Long are properly little endian 1275862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0x0100, CalendarUtilities.getWord(bytes, 0)); 1285862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0x03020100, CalendarUtilities.getLong(bytes, 0)); 1295862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0x07060504, CalendarUtilities.getLong(bytes, 4)); 1305862a85e17e81866ca82a9905577931947fbd44eMarc Blank 1315862a85e17e81866ca82a9905577931947fbd44eMarc Blank // Set some words and longs 1325862a85e17e81866ca82a9905577931947fbd44eMarc Blank CalendarUtilities.setWord(bytes, 0, 0xDEAD); 1335862a85e17e81866ca82a9905577931947fbd44eMarc Blank CalendarUtilities.setLong(bytes, 2, 0xBEEFBEEF); 1345862a85e17e81866ca82a9905577931947fbd44eMarc Blank CalendarUtilities.setWord(bytes, 6, 0xCEDE); 1355862a85e17e81866ca82a9905577931947fbd44eMarc Blank 1365862a85e17e81866ca82a9905577931947fbd44eMarc Blank // Retrieve them 1375862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0xDEAD, CalendarUtilities.getWord(bytes, 0)); 1385862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0xBEEFBEEF, CalendarUtilities.getLong(bytes, 2)); 1395862a85e17e81866ca82a9905577931947fbd44eMarc Blank assertEquals(0xCEDE, CalendarUtilities.getWord(bytes, 6)); 1405862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 1415862a85e17e81866ca82a9905577931947fbd44eMarc Blank 1425862a85e17e81866ca82a9905577931947fbd44eMarc Blank public void testParseTimeZoneEndToEnd() { 14379268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank TimeZone tz = CalendarUtilities.tziStringToTimeZone(AMERICA_DAWSON_TIME); 14479268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank assertEquals("America/Dawson", tz.getID()); 14579268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank tz = CalendarUtilities.tziStringToTimeZone(ASIA_CALCUTTA_TIME); 14679268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank assertEquals("Asia/Calcutta", tz.getID()); 14779268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank tz = CalendarUtilities.tziStringToTimeZone(AUSTRALIA_ACT_TIME); 14879268e63dbda6ebc94d20e72e2bb1c245ee64678Marc Blank assertEquals("Australia/ACT", tz.getID()); 1492c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank 1507b873db28bda10f98f3782b7b161cb66117034d7Marc Blank tz = CalendarUtilities.tziStringToTimeZone(EUROPE_LONDON_TIME_BY_NAME); 1517b873db28bda10f98f3782b7b161cb66117034d7Marc Blank assertEquals("Europe/London", tz.getID()); 1527b873db28bda10f98f3782b7b161cb66117034d7Marc Blank 1532c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank // Test peculiar MS sent EST data with and without lenient precision; send standard 1542c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank // precision + 1 (i.e. 1ms) to make sure the code doesn't automatically flip to lenient 1552c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank // when the tz isn't found 1562c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank tz = CalendarUtilities.tziStringToTimeZoneImpl(LENIENT_EASTERN_TIME, 1572c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank CalendarUtilities.STANDARD_DST_PRECISION+1); 1582c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank assertEquals("America/Atikokan", tz.getID()); 1592c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank tz = CalendarUtilities.tziStringToTimeZoneImpl(LENIENT_EASTERN_TIME, 1602c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank CalendarUtilities.LENIENT_DST_PRECISION); 1612c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank assertEquals("America/Detroit", tz.getID()); 1622c7d44b182654120a98921cbc864be2d135c8fdaMarc Blank 163270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank tz = CalendarUtilities.tziStringToTimeZone(GMT_UNKNOWN_DAYLIGHT_TIME); 164270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank int bias = tz.getOffset(System.currentTimeMillis()); 165270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank assertEquals(0, bias); 1664868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank // Make sure non-DST TZ's work properly when the tested zone is the default zone 1674868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank TimeZone.setDefault(TimeZone.getTimeZone("America/Phoenix")); 1685bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank tz = CalendarUtilities.tziStringToTimeZone(ARIZONA_TIME); 1695bb2c4930c27c5385ff1baf033d1f1a97d770d14Marc Blank assertEquals("America/Phoenix", tz.getID()); 1704868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank TimeZone.setDefault(TimeZone.getTimeZone("Pacific/Honolulu")); 1714868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank tz = CalendarUtilities.tziStringToTimeZone(HAWAII_TIME); 1724868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank assertEquals("Pacific/Honolulu", tz.getID()); 1734868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank // Make sure non-DST TZ's get the proper offset and DST status otherwise 1744868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank CalendarUtilities.clearTimeZoneCache(); 1754868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank TimeZone azTime = TimeZone.getTimeZone("America/Phoenix"); 1764868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); 1774868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank tz = CalendarUtilities.tziStringToTimeZone(ARIZONA_TIME); 1784868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank assertFalse("America/Phoenix".equals(tz.getID())); 1794868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank assertFalse(tz.useDaylightTime()); 1804868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank // It doesn't matter what time is passed in, since neither TZ has dst 1814868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank long now = System.currentTimeMillis(); 1824868e0f09b58104741a5593f6097589ac62c6ce3Marc Blank assertEquals(azTime.getOffset(now), tz.getOffset(now)); 1835862a85e17e81866ca82a9905577931947fbd44eMarc Blank } 1845862a85e17e81866ca82a9905577931947fbd44eMarc Blank 185f35b67cef20189c12a1a387dedf200eb30089725Marc Blank public void testGenerateEasDayOfWeek() { 186b129a5f1b340ae6362397685c407099ceae8d9e9Marc Blank String byDay = "TU,WE,SA"; 187377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // TU = 4, WE = 8; SA = 64; 188f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("76", CalendarUtilities.generateEasDayOfWeek(byDay)); 189377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // MO = 2, TU = 4; WE = 8; TH = 16; FR = 32 190b129a5f1b340ae6362397685c407099ceae8d9e9Marc Blank byDay = "MO,TU,WE,TH,FR"; 191f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("62", CalendarUtilities.generateEasDayOfWeek(byDay)); 192377230593dca7cb01483bfaf93959e5821f5f028Marc Blank // SU = 1 193f35b67cef20189c12a1a387dedf200eb30089725Marc Blank byDay = "SU"; 194f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("1", CalendarUtilities.generateEasDayOfWeek(byDay)); 195f35b67cef20189c12a1a387dedf200eb30089725Marc Blank } 196f35b67cef20189c12a1a387dedf200eb30089725Marc Blank 197f35b67cef20189c12a1a387dedf200eb30089725Marc Blank public void testTokenFromRrule() { 198f35b67cef20189c12a1a387dedf200eb30089725Marc Blank String rrule = "FREQ=DAILY;INTERVAL=1;BYDAY=WE,TH,SA;BYMONTHDAY=17"; 199f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("DAILY", CalendarUtilities.tokenFromRrule(rrule, "FREQ=")); 200f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("1", CalendarUtilities.tokenFromRrule(rrule, "INTERVAL=")); 201f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertEquals("17", CalendarUtilities.tokenFromRrule(rrule, "BYMONTHDAY=")); 202b129a5f1b340ae6362397685c407099ceae8d9e9Marc Blank assertEquals("WE,TH,SA", CalendarUtilities.tokenFromRrule(rrule, "BYDAY=")); 203f35b67cef20189c12a1a387dedf200eb30089725Marc Blank assertNull(CalendarUtilities.tokenFromRrule(rrule, "UNTIL=")); 204f35b67cef20189c12a1a387dedf200eb30089725Marc Blank } 205f35b67cef20189c12a1a387dedf200eb30089725Marc Blank 20621c3c670ff6b932a4ecbeda230bb160178bdd957Marc Blank public void testRecurrenceUntilToEasUntil() { 20760df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); 20860df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank // Case where local time crosses into next day in GMT 20960df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank assertEquals("20110730T000000Z", 21060df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank CalendarUtilities.recurrenceUntilToEasUntil("20110731T025959Z")); 21160df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank // Case where local time does not cross into next day in GMT 21260df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank assertEquals("20110730T000000Z", 21360df2ad267f1ad7aed45b583adcd1a5bb2a006b0Marc Blank CalendarUtilities.recurrenceUntilToEasUntil("20110730T235959Z")); 21421c3c670ff6b932a4ecbeda230bb160178bdd957Marc Blank } 21521c3c670ff6b932a4ecbeda230bb160178bdd957Marc Blank 216c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank public void testParseEmailDateTimeToMillis(String date) { 217c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank // Format for email date strings is 2010-02-23T16:00:00.000Z 218c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank String dateString = "2010-02-23T15:16:17.000Z"; 2198e26c42accbaf72eff6694173496aba0e6aa37f6Mihai Preda long dateTime = Utility.parseEmailDateTimeToMillis(dateString); 220c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank GregorianCalendar cal = new GregorianCalendar(); 221c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank cal.setTimeInMillis(dateTime); 222c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank cal.setTimeZone(TimeZone.getTimeZone("GMT")); 223c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.YEAR), 2010); 224c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.MONTH), 1); // 0 based 225c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.DAY_OF_MONTH), 23); 226c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.HOUR_OF_DAY), 16); 227c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.MINUTE), 16); 228c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.SECOND), 17); 229c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank } 230c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank 231c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank public void testParseDateTimeToMillis(String date) { 232c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank // Format for calendar date strings is 20100223T160000000Z 233c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank String dateString = "20100223T151617000Z"; 2348e26c42accbaf72eff6694173496aba0e6aa37f6Mihai Preda long dateTime = Utility.parseDateTimeToMillis(dateString); 235c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank GregorianCalendar cal = new GregorianCalendar(); 236c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank cal.setTimeInMillis(dateTime); 237c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank cal.setTimeZone(TimeZone.getTimeZone("GMT")); 238c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.YEAR), 2010); 239c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.MONTH), 1); // 0 based 240c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.DAY_OF_MONTH), 23); 241c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.HOUR_OF_DAY), 16); 242c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.MINUTE), 16); 243c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank assertEquals(cal.get(Calendar.SECOND), 17); 244c10a3beef4f048292e6a4ceb31527c5123801517Marc Blank } 24521c3c670ff6b932a4ecbeda230bb160178bdd957Marc Blank 2461c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank private Entity setupTestEventEntity(String organizer, String attendee, String title) { 2475c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Create an Entity for an Event 2485c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank ContentValues entityValues = new ContentValues(); 2495c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank Entity entity = new Entity(entityValues); 2505c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2515c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Set up values for the Event 2525c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank String location = "Meeting Location"; 2535c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2545c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Fill in times, location, title, and organizer 2555c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put("DTSTAMP", 2565c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank CalendarUtilities.convertEmailDateTimeToCalendarDateTime("2010-04-05T14:30:51Z")); 2575c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put(Events.DTSTART, 2588e26c42accbaf72eff6694173496aba0e6aa37f6Mihai Preda Utility.parseEmailDateTimeToMillis("2010-04-12T18:30:00Z")); 2595c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put(Events.DTEND, 2608e26c42accbaf72eff6694173496aba0e6aa37f6Mihai Preda Utility.parseEmailDateTimeToMillis("2010-04-12T19:30:00Z")); 2615c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put(Events.EVENT_LOCATION, location); 2625c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put(Events.TITLE, title); 2635c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entityValues.put(Events.ORGANIZER, organizer); 26404c880a6b5ad041f172d4b1eeecc06d6a06e4141RoboErik entityValues.put(Events.SYNC_DATA2, "31415926535"); 2655c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2665c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Add the attendee 2675c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank ContentValues attendeeValues = new ContentValues(); 2685c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank attendeeValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); 2695c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank attendeeValues.put(Attendees.ATTENDEE_EMAIL, attendee); 2705c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entity.addSubValue(Attendees.CONTENT_URI, attendeeValues); 2715c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2725c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Add the organizer 2735c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank ContentValues organizerValues = new ContentValues(); 2745c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank organizerValues.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ORGANIZER); 2755c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank organizerValues.put(Attendees.ATTENDEE_EMAIL, organizer); 2765c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank entity.addSubValue(Attendees.CONTENT_URI, organizerValues); 2771c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank return entity; 2781c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 2795c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 280dafc866120dac68fabbddcc9943e3995894c5244Marc Blank private Entity setupTestExceptionEntity(String organizer, String attendee, String title) { 281dafc866120dac68fabbddcc9943e3995894c5244Marc Blank Entity entity = setupTestEventEntity(organizer, attendee, title); 282dafc866120dac68fabbddcc9943e3995894c5244Marc Blank ContentValues entityValues = entity.getEntityValues(); 2839e86eb14c6e1f7d7730f8ca6953fdfd95fe2b143RoboErik entityValues.put(Events.ORIGINAL_SYNC_ID, 69); 284dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // The exception will be on April 26th 285dafc866120dac68fabbddcc9943e3995894c5244Marc Blank entityValues.put(Events.ORIGINAL_INSTANCE_TIME, 286dafc866120dac68fabbddcc9943e3995894c5244Marc Blank Utility.parseEmailDateTimeToMillis("2010-04-26T18:30:00Z")); 287dafc866120dac68fabbddcc9943e3995894c5244Marc Blank return entity; 288dafc866120dac68fabbddcc9943e3995894c5244Marc Blank } 289dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 2901c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank public void testCreateMessageForEntity_Reply() { 2911c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Set up the "event" 2921c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String title = "Discuss Unit Tests"; 2939ca8918b82221dd441293973ffb84d565a52993aMarc Blank Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 2945c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2951c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Create a dummy account for the attendee 2961c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank Account account = new Account(); 2979ca8918b82221dd441293973ffb84d565a52993aMarc Blank account.mEmailAddress = ATTENDEE; 2985c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 2991c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // The uid is required, but can be anything 3001c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String uid = "31415926535"; 3011c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 3025c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Create the outgoing message 3035c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 3045c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank Message.FLAG_OUTGOING_MEETING_ACCEPT, uid, account); 3055c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 3065c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // First, we should have a message 3075c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank assertNotNull(msg); 3085c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 3095c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // Now check some of the fields of the message 3109ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertEquals(Address.pack(new Address[] {new Address(ORGANIZER)}), msg.mTo); 31100702b7e577ff2b7b1ae3f6dceefc615ba9cba72Marc Blank Resources resources = getContext().getResources(); 31200702b7e577ff2b7b1ae3f6dceefc615ba9cba72Marc Blank String accept = resources.getString(R.string.meeting_accepted, title); 313820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals(accept, msg.mSubject); 31400702b7e577ff2b7b1ae3f6dceefc615ba9cba72Marc Blank assertNotNull(msg.mText); 31500702b7e577ff2b7b1ae3f6dceefc615ba9cba72Marc Blank assertTrue(msg.mText.contains(resources.getString(R.string.meeting_where, ""))); 3165c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 3175c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // And make sure we have an attachment 3185c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank assertNotNull(msg.mAttachments); 3195c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank assertEquals(1, msg.mAttachments.size()); 3205c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank Attachment att = msg.mAttachments.get(0); 3215c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank // And that the attachment has the correct elements 3225c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank assertEquals("invite.ics", att.mFileName); 323b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 324b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 3255c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank assertEquals("text/calendar; method=REPLY", att.mMimeType); 326e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki assertNotNull(att.mContentBytes); 327e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki assertEquals(att.mSize, att.mContentBytes.length); 3285c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 3295c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank //TODO Check the contents of the attachment using an iCalendar parser 3305c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank } 3315c6e14ab2f2e4c5dfc97cdeaedcc105159a9f29cMarc Blank 332c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank public void testCreateMessageForEntity_Invite_AllDay() throws IOException { 333c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // Set up the "event" 334c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank String title = "Discuss Unit Tests"; 335c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 33689bee1e3d03b439f4084bc9962bb3cbffd0b878aMarc Blank ContentValues entityValues = entity.getEntityValues(); 33789bee1e3d03b439f4084bc9962bb3cbffd0b878aMarc Blank entityValues.put(Events.ALL_DAY, 1); 33889bee1e3d03b439f4084bc9962bb3cbffd0b878aMarc Blank entityValues.put(Events.DURATION, "P1D"); 33989bee1e3d03b439f4084bc9962bb3cbffd0b878aMarc Blank entityValues.remove(Events.DTEND); 340c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 341c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // Create a dummy account for the attendee 342c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank Account account = new Account(); 343c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank account.mEmailAddress = ORGANIZER; 344c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 345c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // The uid is required, but can be anything 346c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank String uid = "31415926535"; 347c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 348c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // Create the outgoing message 349c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 350c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 351c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 352c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // First, we should have a message 353c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(msg); 354c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 355c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // Now check some of the fields of the message 356c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 35746e18bd76629be0835a5d5e6c839b6daac6cdfdcMarc Blank assertEquals(title, msg.mSubject); 358c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 359c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // And make sure we have an attachment 360c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(msg.mAttachments); 361c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(1, msg.mAttachments.size()); 362c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank Attachment att = msg.mAttachments.get(0); 363c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // And that the attachment has the correct elements 364c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("invite.ics", att.mFileName); 365c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 366c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 367c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("text/calendar; method=REQUEST", att.mMimeType); 368c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(att.mContentBytes); 369c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(att.mSize, att.mContentBytes.length); 370c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 371c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // We'll check the contents of the ics file here 372c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank BlockHash vcalendar = parseIcsContent(att.mContentBytes); 373c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(vcalendar); 374c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 375c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // We should have a VCALENDAR with a REQUEST method 376c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("VCALENDAR", vcalendar.name); 377c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("REQUEST", vcalendar.get("METHOD")); 378c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 379c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // We should have one block under VCALENDAR 380c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(1, vcalendar.blocks.size()); 381c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank BlockHash vevent = vcalendar.blocks.get(0); 382c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // It's a VEVENT with the following fields 383c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("VEVENT", vevent.name); 384c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("Meeting Location", vevent.get("LOCATION")); 385c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("0", vevent.get("SEQUENCE")); 386c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 387c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(uid, vevent.get("UID")); 388c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("MAILTO:" + ATTENDEE, 389c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 390c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 391c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // These next two fields should have a date only 392c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("20100412", vevent.get("DTSTART;VALUE=DATE")); 39389bee1e3d03b439f4084bc9962bb3cbffd0b878aMarc Blank assertEquals("20100413", vevent.get("DTEND;VALUE=DATE")); 394c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // This should be set to TRUE for all-day events 395c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals("TRUE", vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 396c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank } 397c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 3981c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank public void testCreateMessageForEntity_Invite() throws IOException { 3991c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Set up the "event" 4001c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String title = "Discuss Unit Tests"; 4019ca8918b82221dd441293973ffb84d565a52993aMarc Blank Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 4021c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4031c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Create a dummy account for the attendee 4041c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank Account account = new Account(); 4059ca8918b82221dd441293973ffb84d565a52993aMarc Blank account.mEmailAddress = ORGANIZER; 4061c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4071c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // The uid is required, but can be anything 4081c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String uid = "31415926535"; 4091c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4101c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Create the outgoing message 4111c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 4121c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 4131c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4141c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // First, we should have a message 4151c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertNotNull(msg); 4161c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4171c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Now check some of the fields of the message 4189ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 41946e18bd76629be0835a5d5e6c839b6daac6cdfdcMarc Blank assertEquals(title, msg.mSubject); 4201c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4211c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // And make sure we have an attachment 4221c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertNotNull(msg.mAttachments); 4231c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals(1, msg.mAttachments.size()); 4241c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank Attachment att = msg.mAttachments.get(0); 4251c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // And that the attachment has the correct elements 4261c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("invite.ics", att.mFileName); 427b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 428b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 4291c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("text/calendar; method=REQUEST", att.mMimeType); 430e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki assertNotNull(att.mContentBytes); 431e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki assertEquals(att.mSize, att.mContentBytes.length); 4321c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4331c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // We'll check the contents of the ics file here 434e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki BlockHash vcalendar = parseIcsContent(att.mContentBytes); 4351c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertNotNull(vcalendar); 4361c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4371c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // We should have a VCALENDAR with a REQUEST method 4381c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("VCALENDAR", vcalendar.name); 4391c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("REQUEST", vcalendar.get("METHOD")); 4401c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 4411c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // We should have one block under VCALENDAR 4421c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals(1, vcalendar.blocks.size()); 4431c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank BlockHash vevent = vcalendar.blocks.get(0); 4441c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // It's a VEVENT with the following fields 4451c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("VEVENT", vevent.name); 4461c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("Meeting Location", vevent.get("LOCATION")); 4471c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("0", vevent.get("SEQUENCE")); 4481c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 4491c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank assertEquals(uid, vevent.get("UID")); 4509ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertEquals("MAILTO:" + ATTENDEE, 4511c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 452c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank 453c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // These next two fields should exist (without the VALUE=DATE suffix) 454c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(vevent.get("DTSTART")); 455c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNotNull(vevent.get("DTEND")); 456c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNull(vevent.get("DTSTART;VALUE=DATE")); 457c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNull(vevent.get("DTEND;VALUE=DATE")); 458c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank // This shouldn't exist for this event 459c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertNull(vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 4601c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 4611c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 46267010d38cb168666b34431c96f331f36507e1f03Marc Blank public void testCreateMessageForEntity_Recurring() throws IOException { 46367010d38cb168666b34431c96f331f36507e1f03Marc Blank // Set up the "event" 46467010d38cb168666b34431c96f331f36507e1f03Marc Blank String title = "Discuss Unit Tests"; 46567010d38cb168666b34431c96f331f36507e1f03Marc Blank Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 46667010d38cb168666b34431c96f331f36507e1f03Marc Blank // Set up a RRULE for this event 46767010d38cb168666b34431c96f331f36507e1f03Marc Blank entity.getEntityValues().put(Events.RRULE, "FREQ=DAILY"); 46867010d38cb168666b34431c96f331f36507e1f03Marc Blank 46967010d38cb168666b34431c96f331f36507e1f03Marc Blank // Create a dummy account for the attendee 47067010d38cb168666b34431c96f331f36507e1f03Marc Blank Account account = new Account(); 47167010d38cb168666b34431c96f331f36507e1f03Marc Blank account.mEmailAddress = ORGANIZER; 47267010d38cb168666b34431c96f331f36507e1f03Marc Blank 47367010d38cb168666b34431c96f331f36507e1f03Marc Blank // The uid is required, but can be anything 47467010d38cb168666b34431c96f331f36507e1f03Marc Blank String uid = "31415926535"; 47567010d38cb168666b34431c96f331f36507e1f03Marc Blank 47667010d38cb168666b34431c96f331f36507e1f03Marc Blank // Create the outgoing message 47767010d38cb168666b34431c96f331f36507e1f03Marc Blank Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 47867010d38cb168666b34431c96f331f36507e1f03Marc Blank Message.FLAG_OUTGOING_MEETING_INVITE, uid, account); 47967010d38cb168666b34431c96f331f36507e1f03Marc Blank 48067010d38cb168666b34431c96f331f36507e1f03Marc Blank // First, we should have a message 48167010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(msg); 48267010d38cb168666b34431c96f331f36507e1f03Marc Blank 48367010d38cb168666b34431c96f331f36507e1f03Marc Blank // Now check some of the fields of the message 48467010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 48567010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(title, msg.mSubject); 48667010d38cb168666b34431c96f331f36507e1f03Marc Blank 48767010d38cb168666b34431c96f331f36507e1f03Marc Blank // And make sure we have an attachment 48867010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(msg.mAttachments); 48967010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(1, msg.mAttachments.size()); 49067010d38cb168666b34431c96f331f36507e1f03Marc Blank Attachment att = msg.mAttachments.get(0); 49167010d38cb168666b34431c96f331f36507e1f03Marc Blank // And that the attachment has the correct elements 49267010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("invite.ics", att.mFileName); 49367010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 49467010d38cb168666b34431c96f331f36507e1f03Marc Blank att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 49567010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("text/calendar; method=REQUEST", att.mMimeType); 49667010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(att.mContentBytes); 49767010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(att.mSize, att.mContentBytes.length); 49867010d38cb168666b34431c96f331f36507e1f03Marc Blank 49967010d38cb168666b34431c96f331f36507e1f03Marc Blank // We'll check the contents of the ics file here 50067010d38cb168666b34431c96f331f36507e1f03Marc Blank BlockHash vcalendar = parseIcsContent(att.mContentBytes); 50167010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(vcalendar); 50267010d38cb168666b34431c96f331f36507e1f03Marc Blank 50367010d38cb168666b34431c96f331f36507e1f03Marc Blank // We should have a VCALENDAR with a REQUEST method 50467010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("VCALENDAR", vcalendar.name); 50567010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("REQUEST", vcalendar.get("METHOD")); 50667010d38cb168666b34431c96f331f36507e1f03Marc Blank 50767010d38cb168666b34431c96f331f36507e1f03Marc Blank // We should have two blocks under VCALENDAR (VTIMEZONE and VEVENT) 50867010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(2, vcalendar.blocks.size()); 50967010d38cb168666b34431c96f331f36507e1f03Marc Blank 51067010d38cb168666b34431c96f331f36507e1f03Marc Blank // This is the time zone that should be used 51167010d38cb168666b34431c96f331f36507e1f03Marc Blank TimeZone timeZone = TimeZone.getDefault(); 51267010d38cb168666b34431c96f331f36507e1f03Marc Blank 51367010d38cb168666b34431c96f331f36507e1f03Marc Blank BlockHash vtimezone = vcalendar.blocks.get(0); 51467010d38cb168666b34431c96f331f36507e1f03Marc Blank // It should be a VTIMEZONE for timeZone 51567010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("VTIMEZONE", vtimezone.name); 51667010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(timeZone.getID(), vtimezone.get("TZID")); 51767010d38cb168666b34431c96f331f36507e1f03Marc Blank 51867010d38cb168666b34431c96f331f36507e1f03Marc Blank BlockHash vevent = vcalendar.blocks.get(1); 51967010d38cb168666b34431c96f331f36507e1f03Marc Blank // It's a VEVENT with the following fields 52067010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("VEVENT", vevent.name); 52167010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("Meeting Location", vevent.get("LOCATION")); 52267010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("0", vevent.get("SEQUENCE")); 52367010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 52467010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals(uid, vevent.get("UID")); 52567010d38cb168666b34431c96f331f36507e1f03Marc Blank assertEquals("MAILTO:" + ATTENDEE, 52667010d38cb168666b34431c96f331f36507e1f03Marc Blank vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE")); 52767010d38cb168666b34431c96f331f36507e1f03Marc Blank 52867010d38cb168666b34431c96f331f36507e1f03Marc Blank // We should have DTSTART/DTEND with time zone 52967010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(vevent.get("DTSTART;TZID=" + timeZone.getID())); 53067010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNotNull(vevent.get("DTEND;TZID=" + timeZone.getID())); 53167010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNull(vevent.get("DTSTART")); 53267010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNull(vevent.get("DTEND")); 53367010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNull(vevent.get("DTSTART;VALUE=DATE")); 53467010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNull(vevent.get("DTEND;VALUE=DATE")); 53567010d38cb168666b34431c96f331f36507e1f03Marc Blank // This shouldn't exist for this event 53667010d38cb168666b34431c96f331f36507e1f03Marc Blank assertNull(vevent.get("X-MICROSOFT-CDO-ALLDAYEVENT")); 53767010d38cb168666b34431c96f331f36507e1f03Marc Blank } 53867010d38cb168666b34431c96f331f36507e1f03Marc Blank 539dafc866120dac68fabbddcc9943e3995894c5244Marc Blank public void testCreateMessageForEntity_Exception_Cancel() throws IOException { 540dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // Set up the "exception"... 541dafc866120dac68fabbddcc9943e3995894c5244Marc Blank String title = "Discuss Unit Tests"; 5429ca8918b82221dd441293973ffb84d565a52993aMarc Blank Entity entity = setupTestExceptionEntity(ORGANIZER, ATTENDEE, title); 543dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 544dafc866120dac68fabbddcc9943e3995894c5244Marc Blank ContentValues entityValues = entity.getEntityValues(); 545dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // Mark the Exception as dirty 5469e86eb14c6e1f7d7730f8ca6953fdfd95fe2b143RoboErik entityValues.put(Events.DIRTY, 1); 547dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // And mark it canceled 548dafc866120dac68fabbddcc9943e3995894c5244Marc Blank entityValues.put(Events.STATUS, Events.STATUS_CANCELED); 549dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 550dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // Create a dummy account for the attendee 551dafc866120dac68fabbddcc9943e3995894c5244Marc Blank Account account = new Account(); 5529ca8918b82221dd441293973ffb84d565a52993aMarc Blank account.mEmailAddress = ORGANIZER; 553dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 554dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // The uid is required, but can be anything 555dafc866120dac68fabbddcc9943e3995894c5244Marc Blank String uid = "31415926535"; 556dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 557dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // Create the outgoing message 558dafc866120dac68fabbddcc9943e3995894c5244Marc Blank Message msg = CalendarUtilities.createMessageForEntity(mContext, entity, 559bf1de871b7ec63c93694ba022282e8789e69f201Marc Blank Message.FLAG_OUTGOING_MEETING_CANCEL, uid, account); 560dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 561dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // First, we should have a message 562dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertNotNull(msg); 563dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 564dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // Now check some of the fields of the message 5659ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertEquals(Address.pack(new Address[] {new Address(ATTENDEE)}), msg.mTo); 566bf1de871b7ec63c93694ba022282e8789e69f201Marc Blank String cancel = getContext().getResources().getString(R.string.meeting_canceled, title); 567bf1de871b7ec63c93694ba022282e8789e69f201Marc Blank assertEquals(cancel, msg.mSubject); 568dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 569dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // And make sure we have an attachment 570dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertNotNull(msg.mAttachments); 571dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals(1, msg.mAttachments.size()); 572dafc866120dac68fabbddcc9943e3995894c5244Marc Blank Attachment att = msg.mAttachments.get(0); 573dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // And that the attachment has the correct elements 574dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("invite.ics", att.mFileName); 575b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank assertEquals(Attachment.FLAG_ICS_ALTERNATIVE_PART, 576b4d217e5170ae397d741e95308d98e80d0c2f637Marc Blank att.mFlags & Attachment.FLAG_ICS_ALTERNATIVE_PART); 577f58e3ba6e6e246a804e6908c831a43b46a61bc07Marc Blank assertEquals("text/calendar; method=CANCEL", att.mMimeType); 578e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki assertNotNull(att.mContentBytes); 579dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 580dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // We'll check the contents of the ics file here 581e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki BlockHash vcalendar = parseIcsContent(att.mContentBytes); 582dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertNotNull(vcalendar); 583dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 584f58e3ba6e6e246a804e6908c831a43b46a61bc07Marc Blank // We should have a VCALENDAR with a CANCEL method 585dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("VCALENDAR", vcalendar.name); 586f58e3ba6e6e246a804e6908c831a43b46a61bc07Marc Blank assertEquals("CANCEL", vcalendar.get("METHOD")); 587dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 588dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // This is the time zone that should be used 589dafc866120dac68fabbddcc9943e3995894c5244Marc Blank TimeZone timeZone = TimeZone.getDefault(); 590dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 591dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // We should have two blocks under VCALENDAR (VTIMEZONE and VEVENT) 592dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals(2, vcalendar.blocks.size()); 593dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 594dafc866120dac68fabbddcc9943e3995894c5244Marc Blank BlockHash vtimezone = vcalendar.blocks.get(0); 595dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // It should be a VTIMEZONE for timeZone 596dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("VTIMEZONE", vtimezone.name); 597dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals(timeZone.getID(), vtimezone.get("TZID")); 598dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 599dafc866120dac68fabbddcc9943e3995894c5244Marc Blank BlockHash vevent = vcalendar.blocks.get(1); 600dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // It's a VEVENT with the following fields 601dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("VEVENT", vevent.name); 602dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("Meeting Location", vevent.get("LOCATION")); 603dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("0", vevent.get("SEQUENCE")); 604dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals("Discuss Unit Tests", vevent.get("SUMMARY")); 605dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertEquals(uid, vevent.get("UID")); 6069ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertEquals("MAILTO:" + ATTENDEE, 607bf1de871b7ec63c93694ba022282e8789e69f201Marc Blank vevent.get("ATTENDEE;ROLE=REQ-PARTICIPANT")); 608dafc866120dac68fabbddcc9943e3995894c5244Marc Blank long originalTime = entityValues.getAsLong(Events.ORIGINAL_INSTANCE_TIME); 609dafc866120dac68fabbddcc9943e3995894c5244Marc Blank assertNotSame(0, originalTime); 610dafc866120dac68fabbddcc9943e3995894c5244Marc Blank // For an exception, RECURRENCE-ID is critical 611c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank assertEquals(CalendarUtilities.millisToEasDateTime(originalTime, timeZone, 612c1b63a27ed05bed70f74cf33fe08f8bd1f0d745fMarc Blank true /*withTime*/), vevent.get("RECURRENCE-ID" + ";TZID=" + timeZone.getID())); 613dafc866120dac68fabbddcc9943e3995894c5244Marc Blank } 614dafc866120dac68fabbddcc9943e3995894c5244Marc Blank 615820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank public void testUtcOffsetString() { 616820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals(CalendarUtilities.utcOffsetString(540), "+0900"); 617820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals(CalendarUtilities.utcOffsetString(-480), "-0800"); 618820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals(CalendarUtilities.utcOffsetString(0), "+0000"); 619820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank } 6201c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 621820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank public void testFindTransitionDate() { 622820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // We'll find some transitions and make sure that we're properly in or out of daylight time 623820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // on either side of the transition. 624820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Use CST for testing (any other will do as well, as long as it has DST) 625820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank TimeZone tz = TimeZone.getTimeZone("US/Central"); 626ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank // Confirm that this time zone uses DST 627ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank assertTrue(tz.useDaylightTime()); 628820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Get a calendar at January 1st of the current year 629820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank GregorianCalendar calendar = new GregorianCalendar(tz); 630820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank calendar.set(CalendarUtilities.sCurrentYear, Calendar.JANUARY, 1); 631820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Get start and end times at start and end of year 632820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank long startTime = calendar.getTimeInMillis(); 633820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank long endTime = startTime + (365*CalendarUtilities.DAYS); 634820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Find the first transition 635820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank GregorianCalendar transitionCalendar = 636820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank CalendarUtilities.findTransitionDate(tz, startTime, endTime, false); 637820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank long transitionTime = transitionCalendar.getTimeInMillis(); 638820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Before should be in standard time; after in daylight time 639820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank Date beforeDate = new Date(transitionTime - CalendarUtilities.HOURS); 640820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank Date afterDate = new Date(transitionTime + CalendarUtilities.HOURS); 641820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertFalse(tz.inDaylightTime(beforeDate)); 642820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertTrue(tz.inDaylightTime(afterDate)); 643820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 644820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Find the next one... 645820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank transitionCalendar = CalendarUtilities.findTransitionDate(tz, transitionTime + 646820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank CalendarUtilities.DAYS, endTime, true); 647820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank transitionTime = transitionCalendar.getTimeInMillis(); 648820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // This time, Before should be in daylight time; after in standard time 649820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank beforeDate = new Date(transitionTime - CalendarUtilities.HOURS); 650820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank afterDate = new Date(transitionTime + CalendarUtilities.HOURS); 651820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertTrue(tz.inDaylightTime(beforeDate)); 652820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertFalse(tz.inDaylightTime(afterDate)); 653820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 654ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank // Kinshasa has no daylight savings time 655ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank tz = TimeZone.getTimeZone("Africa/Kinshasa"); 656ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank // Confirm that there's no DST for this time zone 657ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank assertFalse(tz.useDaylightTime()); 658820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Get a calendar at January 1st of the current year 659820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank calendar = new GregorianCalendar(tz); 660820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank calendar.set(CalendarUtilities.sCurrentYear, Calendar.JANUARY, 1); 661820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Get start and end times at start and end of year 662820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank startTime = calendar.getTimeInMillis(); 663820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank endTime = startTime + (365*CalendarUtilities.DAYS); 664820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Find the first transition 665820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank transitionCalendar = CalendarUtilities.findTransitionDate(tz, startTime, endTime, false); 666820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // There had better not be one 667820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertNull(transitionCalendar); 668820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank } 669377230593dca7cb01483bfaf93959e5821f5f028Marc Blank 670820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank public void testRruleFromRecurrence() { 671820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Every Monday for 2 weeks 672820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank String rrule = CalendarUtilities.rruleFromRecurrence( 673820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 1 /*Weekly*/, 2 /*Occurrences*/, 1 /*Interval*/, 2 /*Monday*/, 0, 0, 0, null); 674f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank assertEquals("FREQ=WEEKLY;COUNT=2;INTERVAL=1;BYDAY=MO", rrule); 675820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Every Tuesday and Friday 676820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 677820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 1 /*Weekly*/, 0 /*Occurrences*/, 0 /*Interval*/, 36 /*Tue&Fri*/, 0, 0, 0, null); 678820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals("FREQ=WEEKLY;BYDAY=TU,FR", rrule); 679820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // The last Saturday of the month 680820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 681f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank 1 /*Weekly*/, 0, 0, 64 /*Sat*/, 0, 5 /*Last*/, 0, null); 682f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank assertEquals("FREQ=WEEKLY;BYDAY=-1SA", rrule); 683820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // The third Wednesday and Thursday of the month 684820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 685f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank 1 /*Weekly*/, 0, 0, 24 /*Wed&Thu*/, 0, 3 /*3rd*/, 0, null); 686f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank assertEquals("FREQ=WEEKLY;BYDAY=3WE,3TH", rrule); 687f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 688f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank 3 /*Monthly/Day*/, 0, 0, 127 /*LastDay*/, 0, 0, 0, null); 689f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank assertEquals("FREQ=MONTHLY;BYMONTHDAY=-1", rrule); 690f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 691f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank 3 /*Monthly/Day*/, 0, 0, 62 /*M-F*/, 0, 5 /*Last week*/, 0, null); 692f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank assertEquals("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1", rrule); 693820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // The 14th of the every month 694820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 695820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 2 /*Monthly/Date*/, 0, 0, 0, 14 /*14th*/, 0, 0, null); 696820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals("FREQ=MONTHLY;BYMONTHDAY=14", rrule); 697820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // Every 31st of October 698820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 699820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 5 /*Yearly/Date*/, 0, 0, 0, 31 /*31st*/, 0, 10 /*October*/, null); 700820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals("FREQ=YEARLY;BYMONTHDAY=31;BYMONTH=10", rrule); 701820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank // The first Tuesday of June 702820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank rrule = CalendarUtilities.rruleFromRecurrence( 703820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 6 /*Yearly/Month/DayOfWeek*/, 0, 0, 4 /*Tue*/, 0, 1 /*1st*/, 6 /*June*/, null); 704820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank assertEquals("FREQ=YEARLY;BYDAY=1TU;BYMONTH=6", rrule); 705820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank } 706820dbc5ff3497fdd98fdb1cc42c1d298f9c1f199Marc Blank 7071c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank /** 708f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * Given a CalendarSyncAdapter and an RRULE, serialize the RRULE via recurrentFromRrule and 709f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * then parse the result. Assert that the resulting RRULE is the same as the original. 710f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * @param adapter a CalendarSyncAdapter 711f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * @param rrule an RRULE string that will be tested 712f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * @throws IOException 713f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank */ 714f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank private void testSingleRecurrenceFromRrule(CalendarSyncAdapter adapter, String rrule) 715f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank throws IOException { 716f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank Serializer s = new Serializer(); 717f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank CalendarUtilities.recurrenceFromRrule(rrule, 0, s); 718f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank s.done(); 719f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank EasCalendarSyncParser parser = adapter.new EasCalendarSyncParser( 720f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank new ByteArrayInputStream(s.toByteArray()), adapter); 721f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank // The first element should be the outer CALENDAR_RECURRENCE tag 722f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank assertEquals(Tags.CALENDAR_RECURRENCE, parser.nextTag(Parser.START_DOCUMENT)); 723f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank assertEquals(rrule, parser.recurrenceParser()); 724f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank } 725f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank 726f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank /** 727f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * Round-trip test of RRULE handling; we serialize an RRULE and then parse the result; the 728f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank * result should be identical to the original RRULE 729f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank */ 730f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank public void testRecurrenceFromRrule() throws IOException { 731f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank // A test sync adapter we can use throughout the test 732f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank CalendarSyncAdapter adapter = getTestSyncAdapter(CalendarSyncAdapter.class); 733f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank 734f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;COUNT=2;INTERVAL=1;BYDAY=MO"); 735f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=TU,FR"); 736f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=-1SA"); 737f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=WEEKLY;BYDAY=3WE,3TH"); 738f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"); 739f352bc9f29cacc61b195069e48d5c8b868660694Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=MONTHLY;BYMONTHDAY=17"); 740f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=YEARLY;BYMONTHDAY=31;BYMONTH=10"); 741f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank testSingleRecurrenceFromRrule(adapter, "FREQ=YEARLY;BYDAY=1TU;BYMONTH=6"); 742f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank } 743f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank 744f72b4bc0ea714067ae528e63c916f0237d2202e6Marc Blank /** 7451c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * For debugging purposes, to help keep track of parsing errors. 7461c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank */ 7471c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank private class UnterminatedBlockException extends IOException { 7481c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank private static final long serialVersionUID = 1L; 7491c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank UnterminatedBlockException(String name) { 7501c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank super(name); 7511c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 7521c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 7531c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 7541c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank /** 7551c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * A lightweight representation of block object containing a hash of individual values and an 7561c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * array of inner blocks. The object is build by pulling elements from a BufferedReader. 7571c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * NOTE: Multiple values of a given field are not supported. We'd see this with ATTENDEEs, for 7581c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * example, and possibly RDATEs in VTIMEZONEs without an RRULE; these cases will be handled 7591c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank * at a later time. 7601c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank */ 7611c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank private class BlockHash { 7621c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String name; 7631c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank HashMap<String, String> hash = new HashMap<String, String>(); 7641c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank ArrayList<BlockHash> blocks = new ArrayList<BlockHash>(); 7651c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 7661c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank BlockHash (String _name, BufferedReader reader) throws IOException { 7671c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank name = _name; 7681c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String lastField = null; 7691c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String lastValue = null; 7701c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank while (true) { 7711c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Get a line; we're done if it's null 7721c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String line = reader.readLine(); 7731c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (line == null) { 7741c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank throw new UnterminatedBlockException(name); 7751c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 7761c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank int length = line.length(); 7771c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (length == 0) { 7781c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // We shouldn't ever see an empty line 7791c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank throw new IllegalArgumentException(); 7801c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 781bc0c8c1523fc0bc42eb82dba6c2977492e441c03Makoto Onuki // A line starting with tab is a continuation 782bc0c8c1523fc0bc42eb82dba6c2977492e441c03Makoto Onuki if (line.charAt(0) == '\t') { 7831c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Remember the line and length 7841c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank lastValue = line.substring(1); 7851c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Save the concatenation of old and new values 7861c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank hash.put(lastField, hash.get(lastField) + lastValue); 7871c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank continue; 7881c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 7891c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Find the field delimiter 7901c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank int pos = line.indexOf(':'); 7911c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // If not found, or at EOL, this is a bad ics 7921c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (pos < 0 || pos >= length) { 7931c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank throw new IllegalArgumentException(); 7941c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 7951c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Remember the field, value, and length 7961c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank lastField = line.substring(0, pos); 7971c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank lastValue = line.substring(pos + 1); 7981c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (lastField.equals("BEGIN")) { 7991c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank blocks.add(new BlockHash(lastValue, reader)); 8001c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank continue; 8011c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } else if (lastField.equals("END")) { 8021c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (!lastValue.equals(name)) { 8031c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank throw new UnterminatedBlockException(name); 8041c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8051c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank break; 8061c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8071c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 8081c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank // Save it away and continue 8091c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank hash.put(lastField, lastValue); 8101c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8111c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8121c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 8131c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String get(String field) { 8141c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank return hash.get(field); 8151c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8161c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8171c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 818e54b75dc4f638e594e9b97e3b4ed8829fbc9b521Makoto Onuki private BlockHash parseIcsContent(byte[] bytes) throws IOException { 819d38b4e9c1893a6c4ac70c08c5211629da3840cb2Makoto Onuki BufferedReader reader = new BufferedReader(new StringReader(Utility.fromUtf8(bytes))); 8201c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank String line = reader.readLine(); 8211c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank if (!line.equals("BEGIN:VCALENDAR")) { 8221c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank throw new IllegalArgumentException(); 8231c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8241c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank return new BlockHash("VCALENDAR", reader); 8251c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank } 8261c9dfc1ce8d40b4a09fb6baf2fd9ed9c482b8900Marc Blank 8279ca8918b82221dd441293973ffb84d565a52993aMarc Blank public void testBuildMessageTextFromEntityValues() { 8289ca8918b82221dd441293973ffb84d565a52993aMarc Blank // Set up a test event 8299ca8918b82221dd441293973ffb84d565a52993aMarc Blank String title = "Event Title"; 8309ca8918b82221dd441293973ffb84d565a52993aMarc Blank Entity entity = setupTestEventEntity(ORGANIZER, ATTENDEE, title); 8319ca8918b82221dd441293973ffb84d565a52993aMarc Blank ContentValues entityValues = entity.getEntityValues(); 8329ca8918b82221dd441293973ffb84d565a52993aMarc Blank 8339ca8918b82221dd441293973ffb84d565a52993aMarc Blank // Save this away; we'll use it a few times below 8349ca8918b82221dd441293973ffb84d565a52993aMarc Blank Resources resources = mContext.getResources(); 8359ca8918b82221dd441293973ffb84d565a52993aMarc Blank Date date = new Date(entityValues.getAsLong(Events.DTSTART)); 8369ca8918b82221dd441293973ffb84d565a52993aMarc Blank String dateTimeString = DateFormat.getDateTimeInstance().format(date); 8379ca8918b82221dd441293973ffb84d565a52993aMarc Blank 8389ca8918b82221dd441293973ffb84d565a52993aMarc Blank // Get the text for this message 8399ca8918b82221dd441293973ffb84d565a52993aMarc Blank StringBuilder sb = new StringBuilder(); 8409ca8918b82221dd441293973ffb84d565a52993aMarc Blank CalendarUtilities.buildMessageTextFromEntityValues(mContext, entityValues, sb); 8419ca8918b82221dd441293973ffb84d565a52993aMarc Blank String text = sb.toString(); 8429ca8918b82221dd441293973ffb84d565a52993aMarc Blank // We'll just check the when and where 8439ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertTrue(text.contains(resources.getString(R.string.meeting_when, dateTimeString))); 8449ca8918b82221dd441293973ffb84d565a52993aMarc Blank String location = entityValues.getAsString(Events.EVENT_LOCATION); 8459ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertTrue(text.contains(resources.getString(R.string.meeting_where, location))); 8469ca8918b82221dd441293973ffb84d565a52993aMarc Blank 8479ca8918b82221dd441293973ffb84d565a52993aMarc Blank // Make this event recurring 8489ca8918b82221dd441293973ffb84d565a52993aMarc Blank entity.getEntityValues().put(Events.RRULE, "FREQ=WEEKLY;BYDAY=MO"); 8499ca8918b82221dd441293973ffb84d565a52993aMarc Blank sb = new StringBuilder(); 8509ca8918b82221dd441293973ffb84d565a52993aMarc Blank CalendarUtilities.buildMessageTextFromEntityValues(mContext, entityValues, sb); 8519ca8918b82221dd441293973ffb84d565a52993aMarc Blank text = sb.toString(); 8529ca8918b82221dd441293973ffb84d565a52993aMarc Blank assertTrue(text.contains(resources.getString(R.string.meeting_recurring, dateTimeString))); 8539ca8918b82221dd441293973ffb84d565a52993aMarc Blank } 8549ca8918b82221dd441293973ffb84d565a52993aMarc Blank 855879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank /** 856879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank * Sanity test for time zone generation. Most important, make sure that we can run through 857879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank * all of the time zones without generating an exception. Second, make sure that we're finding 858879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank * rules for at least 90% of time zones that use daylight time (empirically, it's more like 859879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank * 95%). Log those without rules. 860879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank * @throws IOException 861879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank */ 862879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank public void testTimeZoneToVTimezone() throws IOException { 863879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank SimpleIcsWriter writer = new SimpleIcsWriter(); 864879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank int rule = 0; 865879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank int nodst = 0; 866879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank int norule = 0; 867879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank ArrayList<String> norulelist = new ArrayList<String>(); 868879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank for (String tzs: TimeZone.getAvailableIDs()) { 869879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank TimeZone tz = TimeZone.getTimeZone(tzs); 870879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank writer = new SimpleIcsWriter(); 871879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank CalendarUtilities.timeZoneToVTimezone(tz, writer); 872879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank String vc = writer.toString(); 873879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank boolean hasRule = vc.indexOf("RRULE") > 0; 874879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank if (hasRule) { 875879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank rule++; 876879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } else if (tz.useDaylightTime()) { 877879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank norule++; 878879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank norulelist.add(tz.getID()); 879879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } else { 880879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank nodst++; 881879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } 882879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } 883879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank Log.d("TimeZoneGeneration", 884879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank "Rule: " + rule + ", No DST: " + nodst + ", No rule: " + norule); 885879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank for (String nr: norulelist) { 886879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank Log.d("TimeZoneGeneration", "No rule: " + nr); 887879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } 888ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank // This is an empirical sanity test; we shouldn't have too many time zones with DST and 889ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank // without a rule. 890ee8c9a284b160f353e3bd918aafbc7ed528bfc4cMarc Blank assertTrue(norule < rule/8); 891879b4d7bd28de1c8bb8c8aba9c1ab17936d300aaMarc Blank } 892b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank 893b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank public void testGetUidFromGlobalObjId() { 894b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank // This is a "foreign" uid (from some vCalendar client) 895b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank String globalObjId = "BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAA" + 896b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank "HZDYWwtVWlkAQAAADI3NjU1NmRkLTg1MzAtNGZiZS1iMzE0LThiM2JlYTYwMjE0OQA="; 897b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank String uid = CalendarUtilities.getUidFromGlobalObjId(globalObjId); 898b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank assertEquals(uid, "276556dd-8530-4fbe-b314-8b3bea602149"); 899b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank // This is a native EAS uid 900b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank globalObjId = 901b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank "BAAAAIIA4AB0xbcQGoLgCAAAAADACTu7KbPKAQAAAAAAAAAAEAAAAObgsG6HVt1Fmy+7GlLbGhY="; 902b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank uid = CalendarUtilities.getUidFromGlobalObjId(globalObjId); 903b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank assertEquals(uid, "040000008200E00074C5B7101A82E00800000000C0093BBB29B3CA" + 904b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank "01000000000000000010000000E6E0B06E8756DD459B2FBB1A52DB1A16"); 905b94d16528fc9c7f5dbb5c75c059f76cee2070c09Marc Blank } 906dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank 907dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank public void testSelfAttendeeStatusFromBusyStatus() { 908dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(Attendees.ATTENDEE_STATUS_ACCEPTED, 909edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.attendeeStatusFromBusyStatus( 910dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank CalendarUtilities.BUSY_STATUS_BUSY)); 911dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(Attendees.ATTENDEE_STATUS_TENTATIVE, 912edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.attendeeStatusFromBusyStatus( 913dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank CalendarUtilities.BUSY_STATUS_TENTATIVE)); 914dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(Attendees.ATTENDEE_STATUS_NONE, 915edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.attendeeStatusFromBusyStatus( 916dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank CalendarUtilities.BUSY_STATUS_FREE)); 917dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(Attendees.ATTENDEE_STATUS_NONE, 918edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.attendeeStatusFromBusyStatus( 919e51fedc3c055588a69da56d0b818ea12ed8f706fMarc Blank CalendarUtilities.BUSY_STATUS_OUT_OF_OFFICE)); 920dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank } 921dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank 922dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank public void testBusyStatusFromSelfStatus() { 923dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 924edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.busyStatusFromAttendeeStatus( 925dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank Attendees.ATTENDEE_STATUS_DECLINED)); 926e51fedc3c055588a69da56d0b818ea12ed8f706fMarc Blank assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 927edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.busyStatusFromAttendeeStatus( 928dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank Attendees.ATTENDEE_STATUS_NONE)); 929e51fedc3c055588a69da56d0b818ea12ed8f706fMarc Blank assertEquals(CalendarUtilities.BUSY_STATUS_FREE, 930edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.busyStatusFromAttendeeStatus( 931dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank Attendees.ATTENDEE_STATUS_INVITED)); 932dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(CalendarUtilities.BUSY_STATUS_TENTATIVE, 933edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.busyStatusFromAttendeeStatus( 934dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank Attendees.ATTENDEE_STATUS_TENTATIVE)); 935dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank assertEquals(CalendarUtilities.BUSY_STATUS_BUSY, 936edcfd554728a27a7678306ea7432bd8676ec6990Marc Blank CalendarUtilities.busyStatusFromAttendeeStatus( 937dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank Attendees.ATTENDEE_STATUS_ACCEPTED)); 938dc27937dda50f991de9e12b98b80ee6aa3fe348eMarc Blank } 939270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 940270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank public void testGetUtcAllDayCalendarTime() { 941270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank GregorianCalendar correctUtc = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 942270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank correctUtc.set(2011, 2, 10, 0, 0, 0); 943270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long correctUtcTime = correctUtc.getTimeInMillis(); 944270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 945270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank TimeZone localTimeZone = TimeZone.getTimeZone("GMT-0700"); 946270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank GregorianCalendar localCalendar = new GregorianCalendar(localTimeZone); 947270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localCalendar.set(2011, 2, 10, 12, 23, 34); 948270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long localTimeMillis = localCalendar.getTimeInMillis(); 949270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long convertedUtcTime = 950270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank CalendarUtilities.getUtcAllDayCalendarTime(localTimeMillis, localTimeZone); 951270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank // Milliseconds aren't zeroed out and may not be the same 952270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank assertEquals(convertedUtcTime/1000, correctUtcTime/1000); 953270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 954270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localTimeZone = TimeZone.getTimeZone("GMT+0700"); 955270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localCalendar = new GregorianCalendar(localTimeZone); 956270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localCalendar.set(2011, 2, 10, 12, 23, 34); 957270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localTimeMillis = localCalendar.getTimeInMillis(); 958270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank convertedUtcTime = 959270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank CalendarUtilities.getUtcAllDayCalendarTime(localTimeMillis, localTimeZone); 960270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank assertEquals(convertedUtcTime/1000, correctUtcTime/1000); 961270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank } 962270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 963270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank public void testGetLocalAllDayCalendarTime() { 964270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank TimeZone utcTimeZone = TimeZone.getTimeZone("UTC"); 965270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank TimeZone localTimeZone = TimeZone.getTimeZone("GMT-0700"); 966270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank GregorianCalendar correctLocal = new GregorianCalendar(localTimeZone); 967270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank correctLocal.set(2011, 2, 10, 0, 0, 0); 968270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long correctLocalTime = correctLocal.getTimeInMillis(); 969270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 970270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank GregorianCalendar utcCalendar = new GregorianCalendar(utcTimeZone); 971270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank utcCalendar.set(2011, 2, 10, 12, 23, 34); 972270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long utcTimeMillis = utcCalendar.getTimeInMillis(); 973270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank long convertedLocalTime = 974270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank CalendarUtilities.getLocalAllDayCalendarTime(utcTimeMillis, localTimeZone); 975270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank // Milliseconds aren't zeroed out and may not be the same 976270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank assertEquals(convertedLocalTime/1000, correctLocalTime/1000); 977270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 978270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank localTimeZone = TimeZone.getTimeZone("GMT+0700"); 979270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank correctLocal = new GregorianCalendar(localTimeZone); 980270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank correctLocal.set(2011, 2, 10, 0, 0, 0); 981270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank correctLocalTime = correctLocal.getTimeInMillis(); 982270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank 983270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank utcCalendar = new GregorianCalendar(utcTimeZone); 984270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank utcCalendar.set(2011, 2, 10, 12, 23, 34); 985270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank utcTimeMillis = utcCalendar.getTimeInMillis(); 986270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank convertedLocalTime = 987270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank CalendarUtilities.getLocalAllDayCalendarTime(utcTimeMillis, localTimeZone); 988270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank // Milliseconds aren't zeroed out and may not be the same 989270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank assertEquals(convertedLocalTime/1000, correctLocalTime/1000); 990270a17e49669e0bfc7bd2a6303a684a7acd1266dMarc Blank } 991393208ab154d18a876842777781ab153d34a0281Marc Blank 992393208ab154d18a876842777781ab153d34a0281Marc Blank public void testGetIntegerValueAsBoolean() { 993393208ab154d18a876842777781ab153d34a0281Marc Blank ContentValues cv = new ContentValues(); 994393208ab154d18a876842777781ab153d34a0281Marc Blank cv.put("A", 1); 995393208ab154d18a876842777781ab153d34a0281Marc Blank cv.put("B", 69); 996393208ab154d18a876842777781ab153d34a0281Marc Blank cv.put("C", 0); 997393208ab154d18a876842777781ab153d34a0281Marc Blank assertTrue(CalendarUtilities.getIntegerValueAsBoolean(cv, "A")); 998393208ab154d18a876842777781ab153d34a0281Marc Blank assertTrue(CalendarUtilities.getIntegerValueAsBoolean(cv, "B")); 999393208ab154d18a876842777781ab153d34a0281Marc Blank assertFalse(CalendarUtilities.getIntegerValueAsBoolean(cv, "C")); 1000393208ab154d18a876842777781ab153d34a0281Marc Blank assertFalse(CalendarUtilities.getIntegerValueAsBoolean(cv, "D")); 1001393208ab154d18a876842777781ab153d34a0281Marc Blank } 10025862a85e17e81866ca82a9905577931947fbd44eMarc Blank} 1003455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank 1004455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // TODO Planned unit tests 1005455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // findNextTransition 1006455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // recurrenceFromRrule 1007455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // timeZoneToTziStringImpl 1008455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // getDSTCalendars 1009455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // millisToVCalendarTime 1010455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // millisToEasDateTime 1011455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // getTrueTransitionMinute 1012455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank // getTrueTransitionHour 1013455f8969854ec1f0ba163ae70cb02e10fb515564Marc Blank 1014