1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.icu; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 21 import dalvik.annotation.compat.VersionCodes; 22 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 import java.text.DateFormat; 26 import java.util.Formatter; 27 28 /** 29 * This class is only kept for @UnsupportedAppUsage, and should not be used by libcore / frameworks. 30 * 31 * @hide 32 */ 33 public final class DateIntervalFormat { 34 35 private static final int FORMAT_SHOW_TIME = 0x00001; 36 private static final int FORMAT_12HOUR = 0x00040; 37 private static final int FORMAT_24HOUR = 0x00080; 38 DateIntervalFormat()39 private DateIntervalFormat() { 40 } 41 42 /** 43 * Do not use this method because it's only kept for app backward compatibility. 44 * To format a date range, please use {@link android.icu.text.DateIntervalFormat} instead. 45 * 46 * @implNote best-effort implementation to invoke the frameworks' implementation. If it fails 47 * when framework.jar is absent in the boot class path, it returns null instead of 48 * throwing exception to avoid crash. 49 * 50 * @return null if the corresponding frameworks' method is not found. 51 */ 52 @UnsupportedAppUsage(maxTargetSdk = VersionCodes.TIRAMISU, 53 publicAlternatives = "Use {@code android.text.format.DateUtils#formatDateRange(" 54 + "Context, Formatter, long, long, int, String)} instead.") formatDateRange(long startMs, long endMs, int flags, String olsonId)55 public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) { 56 // First, try the internal method in android.text.format.DateIntervalFormat, which 57 // can be modified by the OEMs. 58 Method m = getFrameworksDateIntervaFormatMethod(); 59 if (m != null) { 60 try { 61 return (String) m.invoke(null, startMs, endMs, flags, olsonId); 62 } catch (IllegalAccessException | InvocationTargetException e) { 63 return null; 64 } 65 } 66 67 // Second, try the public SDK method in android.text.format.DateUtils. 68 m = getDateUtilsMethod(); 69 if (m != null) { 70 try { 71 // To pass null frameworks' Context pointer, pre-process the flags here. 72 if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) 73 == FORMAT_SHOW_TIME) { 74 // Make an arbitrary choice of using 24-hour format if is24Hour is null. 75 if (DateFormat.is24Hour == null || DateFormat.is24Hour) { 76 flags |= FORMAT_24HOUR; 77 } else { 78 flags |= FORMAT_12HOUR; 79 } 80 } 81 82 Formatter formatter = new Formatter(); 83 m.invoke(null, /*context="*/ null, formatter, startMs, endMs, flags, olsonId); 84 return formatter.toString(); 85 } catch (IllegalAccessException | InvocationTargetException e) { 86 return null; 87 } 88 } 89 90 // If the above 2 attempts fail, it's likely that frameworks.jar is not present in the 91 // boot class path, and no 3rd party app code is running in this process. It should be safe 92 // to return null here. 93 return null; 94 } 95 getFrameworksDateIntervaFormatMethod()96 private static Method getFrameworksDateIntervaFormatMethod() { 97 try { 98 Class<?> cls = Class.forName("android.text.format.DateIntervalFormat"); 99 Method m = cls.getDeclaredMethod("formatDateRange", long.class, long.class, int.class, 100 String.class); 101 m.setAccessible(true); 102 return m; 103 } catch (ClassNotFoundException | NoSuchMethodException e) { 104 return null; 105 } 106 } 107 getDateUtilsMethod()108 private static Method getDateUtilsMethod() { 109 try { 110 Class<?> cls = Class.forName("android.text.format.DateUtils"); 111 Method m = cls.getMethod("formatDateRange", Class.forName("android.content.Context"), 112 Formatter.class, long.class, long.class, int.class, String.class); 113 return m; 114 } catch (ClassNotFoundException | NoSuchMethodException e) { 115 return null; 116 } 117 } 118 119 } 120