1 /* 2 * Copyright 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.internal.telephony.nitz; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.time.UnixEpochTime; 22 import android.app.timedetector.TelephonyTimeSuggestion; 23 import android.app.timedetector.TimeDetector; 24 import android.app.timezonedetector.TelephonyTimeZoneSuggestion; 25 import android.app.timezonedetector.TimeZoneDetector; 26 import android.content.Context; 27 import android.os.SystemClock; 28 import android.util.LocalLog; 29 30 import com.android.internal.telephony.Phone; 31 import com.android.internal.telephony.metrics.TelephonyMetrics; 32 import com.android.internal.util.IndentingPrintWriter; 33 34 import java.io.PrintWriter; 35 import java.util.Objects; 36 37 /** 38 * The real implementation of {@link TimeServiceHelper}. 39 */ 40 public final class TimeServiceHelperImpl implements TimeServiceHelper { 41 42 private final int mSlotIndex; 43 private final TimeDetector mTimeDetector; 44 private final TimeZoneDetector mTimeZoneDetector; 45 46 private final LocalLog mTimeZoneLog = new LocalLog(32, false /* mUseLocalTimestamps */); 47 private final LocalLog mTimeLog = new LocalLog(32, false /* mUseLocalTimestamps */); 48 49 /** 50 * Records the last time zone suggestion made. Used to avoid sending duplicate suggestions to 51 * the time zone service. The value can be {@code null} to indicate no previous suggestion has 52 * been made. 53 */ 54 @NonNull 55 private TelephonyTimeZoneSuggestion mLastSuggestedTimeZone; 56 TimeServiceHelperImpl(@onNull Phone phone)57 public TimeServiceHelperImpl(@NonNull Phone phone) { 58 mSlotIndex = phone.getPhoneId(); 59 Context context = Objects.requireNonNull(phone.getContext()); 60 mTimeDetector = Objects.requireNonNull(context.getSystemService(TimeDetector.class)); 61 mTimeZoneDetector = 62 Objects.requireNonNull(context.getSystemService(TimeZoneDetector.class)); 63 } 64 65 @Override suggestDeviceTime(@onNull TelephonyTimeSuggestion timeSuggestion)66 public void suggestDeviceTime(@NonNull TelephonyTimeSuggestion timeSuggestion) { 67 mTimeLog.log("Sending time suggestion: " + timeSuggestion); 68 69 Objects.requireNonNull(timeSuggestion); 70 71 if (timeSuggestion.getUnixEpochTime() != null) { 72 UnixEpochTime unixEpochTime = timeSuggestion.getUnixEpochTime(); 73 TelephonyMetrics.getInstance().writeNITZEvent( 74 mSlotIndex, unixEpochTime.getUnixEpochTimeMillis()); 75 } 76 mTimeDetector.suggestTelephonyTime(timeSuggestion); 77 } 78 79 @Override maybeSuggestDeviceTimeZone(@onNull TelephonyTimeZoneSuggestion newSuggestion)80 public void maybeSuggestDeviceTimeZone(@NonNull TelephonyTimeZoneSuggestion newSuggestion) { 81 Objects.requireNonNull(newSuggestion); 82 83 TelephonyTimeZoneSuggestion oldSuggestion = mLastSuggestedTimeZone; 84 if (shouldSendNewTimeZoneSuggestion(oldSuggestion, newSuggestion)) { 85 mTimeZoneLog.log("Suggesting time zone update: " + newSuggestion); 86 mTimeZoneDetector.suggestTelephonyTimeZone(newSuggestion); 87 mLastSuggestedTimeZone = newSuggestion; 88 } 89 } 90 shouldSendNewTimeZoneSuggestion( @ullable TelephonyTimeZoneSuggestion oldSuggestion, @NonNull TelephonyTimeZoneSuggestion newSuggestion)91 private static boolean shouldSendNewTimeZoneSuggestion( 92 @Nullable TelephonyTimeZoneSuggestion oldSuggestion, 93 @NonNull TelephonyTimeZoneSuggestion newSuggestion) { 94 if (oldSuggestion == null) { 95 // No previous suggestion. 96 return true; 97 } 98 // This code relies on PhoneTimeZoneSuggestion.equals() to only check meaningful fields. 99 return !Objects.equals(newSuggestion, oldSuggestion); 100 } 101 102 @Override dumpLogs(IndentingPrintWriter ipw)103 public void dumpLogs(IndentingPrintWriter ipw) { 104 ipw.println("TimeServiceHelperImpl:"); 105 ipw.increaseIndent(); 106 ipw.println("SystemClock.elapsedRealtime()=" + SystemClock.elapsedRealtime()); 107 ipw.println("System.currentTimeMillis()=" + System.currentTimeMillis()); 108 109 ipw.println("Time Logs:"); 110 ipw.increaseIndent(); 111 mTimeLog.dump(ipw); 112 ipw.decreaseIndent(); 113 114 ipw.println("Time zone Logs:"); 115 ipw.increaseIndent(); 116 mTimeZoneLog.dump(ipw); 117 ipw.decreaseIndent(); 118 ipw.decreaseIndent(); 119 } 120 121 @Override dumpState(PrintWriter pw)122 public void dumpState(PrintWriter pw) { 123 pw.println(" TimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone); 124 } 125 } 126