1083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta/* 2083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * Copyright (C) 2013 The Android Open Source Project 3083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * 4083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * you may not use this file except in compliance with the License. 6083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * You may obtain a copy of the License at 7083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * 8083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * 10083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * See the License for the specific language governing permissions and 14083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * limitations under the License. 15083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta */ 16083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 17083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptapackage android.text.format; 18083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 19083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport java.util.Calendar; 20eb3c5459eb893061779b102236a81069efdbef73Deepanshu Guptaimport java.util.TimeZone; 21083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport java.util.UnknownFormatConversionException; 22083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport java.util.regex.Pattern; 23083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 24083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutLog; 25083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport com.android.layoutlib.bridge.Bridge; 26083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 27083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 28083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta/** 29083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * Delegate used to provide new implementation for native methods of {@link Time} 30083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * 31083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * Through the layoutlib_create tool, some native methods of Time have been replaced by calls to 32083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta * methods of the same name in this delegate class. 33083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta */ 34083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Guptapublic class Time_Delegate { 35083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 36083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // Regex to match odd number of '%'. 37083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta private static final Pattern p = Pattern.compile("(?<!%)(%%)*%(?!%)"); 38083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 39eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // Format used by toString() 40eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta private static final String FORMAT = "%1$tY%1$tm%1$tdT%1$tH%1$tM%1$tS<%1$tZ>"; 41eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 42eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 43eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static long normalize(Time thisTime, boolean ignoreDst) { 44eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta long millis = toMillis(thisTime, ignoreDst); 45eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta set(thisTime, millis); 46eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return millis; 47eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 48eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 49eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 50eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static void switchTimezone(Time thisTime, String timezone) { 51eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Calendar c = timeToCalendar(thisTime); 52eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta c.setTimeZone(TimeZone.getTimeZone(timezone)); 53eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta calendarToTime(c, thisTime); 54eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 55eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 56eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 57eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static int nativeCompare(Time a, Time b) { 58eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return timeToCalendar(a).compareTo(timeToCalendar(b)); 59eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 60eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 61083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta @LayoutlibDelegate 62083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta /*package*/ static String format1(Time thisTime, String format) { 63083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 64083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta try { 65083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // Change the format by adding changing '%' to "%1$t". This is required to tell the 66083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // formatter which argument to use from the argument list. '%%' is left as is. In the 67083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // replacement string, $0 refers to matched pattern. \\1 means '1', written this way to 68083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // separate it from 0. \\$ means '$', written this way to suppress the special meaning 69083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta // of $. 70083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta return String.format( 71083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta p.matcher(format).replaceAll("$0\\1\\$t"), 72eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta timeToCalendar(thisTime)); 73083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta } catch (UnknownFormatConversionException e) { 74083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta Bridge.getLog().fidelityWarning(LayoutLog.TAG_STRFTIME, "Unrecognized format", e, format); 75083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta return format; 76083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta } 77083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta } 78083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 79eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /** 80eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta * Return the current time in YYYYMMDDTHHMMSS<tz> format 81eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta */ 82eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 83eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static String toString(Time thisTime) { 84eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Calendar c = timeToCalendar(thisTime); 85eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return String.format(FORMAT, c); 86eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 87eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 88eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 89eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static boolean nativeParse(Time thisTime, String s) { 90eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 91eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta "android.text.format.Time.parse() not supported.", null); 92eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return false; 93eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 94eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 95eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 96eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static boolean nativeParse3339(Time thisTime, String s) { 97eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 98eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta "android.text.format.Time.parse3339() not supported.", null); 99eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return false; 100eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 101eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 102eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 103eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static void setToNow(Time thisTime) { 104eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta calendarToTime(getCalendarInstance(thisTime), thisTime); 105eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 106eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 107eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 108eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static long toMillis(Time thisTime, boolean ignoreDst) { 109eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // TODO: Respect ignoreDst. 110eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return timeToCalendar(thisTime).getTimeInMillis(); 111eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 112eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 113eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 114eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static void set(Time thisTime, long millis) { 115eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Calendar c = getCalendarInstance(thisTime); 116eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta c.setTimeInMillis(millis); 117eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta calendarToTime(c,thisTime); 118eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 119eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 120eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta @LayoutlibDelegate 121eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /*package*/ static String format2445(Time thisTime) { 122eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, 123eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta "android.text.format.Time.format2445() not supported.", null); 124eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return ""; 125eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 126eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 127eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // ---- private helper methods ---- 128eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 129eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta private static Calendar timeToCalendar(Time time) { 130eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta Calendar calendar = getCalendarInstance(time); 131083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta calendar.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second); 132083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta return calendar; 133083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta } 134083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta 135eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta private static void calendarToTime(Calendar c, Time time) { 136eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.timezone = c.getTimeZone().getID(); 137eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.set(c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY), 138eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta c.get(Calendar.DATE), c.get(Calendar.MONTH), c.get(Calendar.YEAR)); 139eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.weekDay = c.get(Calendar.DAY_OF_WEEK); 140eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.yearDay = c.get(Calendar.DAY_OF_YEAR); 141eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.isDst = c.getTimeZone().inDaylightTime(c.getTime()) ? 1 : 0; 142eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // gmtoff is in seconds and TimeZone.getOffset() returns milliseconds. 143eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta time.gmtoff = c.getTimeZone().getOffset(c.getTimeInMillis()) / DateUtils.SECOND_IN_MILLIS; 144eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 145eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta 146eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta /** 147eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta * Return a calendar instance with the correct timezone. 148eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta * 149eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta * @param time Time to obtain the timezone from. 150eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta */ 151eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta private static Calendar getCalendarInstance(Time time) { 152eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // TODO: Check platform code to make sure the behavior is same for null/invalid timezone. 153eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta if (time == null || time.timezone == null) { 154eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // Default to local timezone. 155eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return Calendar.getInstance(); 156eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 157eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta // If timezone is invalid, use GMT. 158eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta return Calendar.getInstance(TimeZone.getTimeZone(time.timezone)); 159eb3c5459eb893061779b102236a81069efdbef73Deepanshu Gupta } 160083e3caf66c21f7cc9511db479726c38d90e2d2fDeepanshu Gupta} 161