1 /* 2 * Copyright (C) 2019 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 com.android.car.developeroptions.datetime.timezone; 18 19 import android.content.Context; 20 import android.icu.text.DateFormat; 21 import android.icu.text.DisplayContext; 22 import android.icu.text.SimpleDateFormat; 23 import android.icu.util.BasicTimeZone; 24 import android.icu.util.Calendar; 25 import android.icu.util.TimeZone; 26 import android.icu.util.TimeZoneTransition; 27 28 import androidx.annotation.VisibleForTesting; 29 30 import com.android.car.developeroptions.R; 31 import com.android.car.developeroptions.core.BasePreferenceController; 32 33 import java.util.Date; 34 35 public class TimeZoneInfoPreferenceController extends BasePreferenceController { 36 37 @VisibleForTesting 38 Date mDate; 39 private TimeZoneInfo mTimeZoneInfo; 40 private final DateFormat mDateFormat; 41 TimeZoneInfoPreferenceController(Context context, String key)42 public TimeZoneInfoPreferenceController(Context context, String key) { 43 super(context, key); 44 mDateFormat = DateFormat.getDateInstance(SimpleDateFormat.LONG); 45 mDateFormat.setContext(DisplayContext.CAPITALIZATION_NONE); 46 mDate = new Date(); 47 } 48 49 @Override getAvailabilityStatus()50 public int getAvailabilityStatus() { 51 return mTimeZoneInfo != null ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE; 52 } 53 54 @Override getSummary()55 public CharSequence getSummary() { 56 return mTimeZoneInfo == null ? "" : formatInfo(mTimeZoneInfo); 57 } 58 setTimeZoneInfo(TimeZoneInfo timeZoneInfo)59 public void setTimeZoneInfo(TimeZoneInfo timeZoneInfo) { 60 mTimeZoneInfo = timeZoneInfo; 61 } 62 formatOffsetAndName(TimeZoneInfo item)63 private CharSequence formatOffsetAndName(TimeZoneInfo item) { 64 String name = item.getGenericName(); 65 if (name == null) { 66 if (item.getTimeZone().inDaylightTime(mDate)) { 67 name = item.getDaylightName(); 68 } else { 69 name = item.getStandardName(); 70 } 71 } 72 if (name == null) { 73 return item.getGmtOffset().toString(); 74 } else { 75 return SpannableUtil.getResourcesText(mContext.getResources(), 76 R.string.zone_info_offset_and_name, item.getGmtOffset(), 77 name); 78 } 79 } 80 formatInfo(TimeZoneInfo item)81 private CharSequence formatInfo(TimeZoneInfo item) { 82 final CharSequence offsetAndName = formatOffsetAndName(item); 83 final TimeZone timeZone = item.getTimeZone(); 84 if (!timeZone.observesDaylightTime()) { 85 return mContext.getString(R.string.zone_info_footer_no_dst, offsetAndName); 86 } 87 88 final TimeZoneTransition nextDstTransition = findNextDstTransition(timeZone); 89 if (nextDstTransition == null) { 90 return null; 91 } 92 final boolean toDst = nextDstTransition.getTo().getDSTSavings() != 0; 93 String timeType = toDst ? item.getDaylightName() : item.getStandardName(); 94 if (timeType == null) { 95 // Fall back to generic "summer time" and "standard time" if the time zone has no 96 // specific names. 97 timeType = toDst ? 98 mContext.getString(R.string.zone_time_type_dst) : 99 mContext.getString(R.string.zone_time_type_standard); 100 101 } 102 final Calendar transitionTime = Calendar.getInstance(timeZone); 103 transitionTime.setTimeInMillis(nextDstTransition.getTime()); 104 final String date = mDateFormat.format(transitionTime); 105 return SpannableUtil.getResourcesText(mContext.getResources(), 106 R.string.zone_info_footer, offsetAndName, timeType, date); 107 } 108 findNextDstTransition(TimeZone timeZone)109 private TimeZoneTransition findNextDstTransition(TimeZone timeZone) { 110 if (!(timeZone instanceof BasicTimeZone)) { 111 return null; 112 } 113 final BasicTimeZone basicTimeZone = (BasicTimeZone) timeZone; 114 TimeZoneTransition transition = basicTimeZone.getNextTransition( 115 mDate.getTime(), /* inclusive */ false); 116 do { 117 if (transition.getTo().getDSTSavings() != transition.getFrom().getDSTSavings()) { 118 break; 119 } 120 transition = basicTimeZone.getNextTransition( 121 transition.getTime(), /*inclusive */ false); 122 } while (transition != null); 123 return transition; 124 } 125 } 126