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.timedetector.TelephonyTimeSuggestion;
22 import android.app.timedetector.TimeDetector;
23 import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
24 import android.app.timezonedetector.TimeZoneDetector;
25 import android.content.Context;
26 import android.os.SystemClock;
27 import android.os.TimestampedValue;
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(30, false /* mUseLocalTimestamps */);
47     private final LocalLog mTimeLog = new LocalLog(30, 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.getUtcTime() != null) {
72             TimestampedValue<Long> utcTime = timeSuggestion.getUtcTime();
73             TelephonyMetrics.getInstance().writeNITZEvent(mSlotIndex, utcTime.getValue());
74         }
75         mTimeDetector.suggestTelephonyTime(timeSuggestion);
76     }
77 
78     @Override
maybeSuggestDeviceTimeZone(@onNull TelephonyTimeZoneSuggestion newSuggestion)79     public void maybeSuggestDeviceTimeZone(@NonNull TelephonyTimeZoneSuggestion newSuggestion) {
80         Objects.requireNonNull(newSuggestion);
81 
82         TelephonyTimeZoneSuggestion oldSuggestion = mLastSuggestedTimeZone;
83         if (shouldSendNewTimeZoneSuggestion(oldSuggestion, newSuggestion)) {
84             mTimeZoneLog.log("Suggesting time zone update: " + newSuggestion);
85             mTimeZoneDetector.suggestTelephonyTimeZone(newSuggestion);
86             mLastSuggestedTimeZone = newSuggestion;
87         }
88     }
89 
shouldSendNewTimeZoneSuggestion( @ullable TelephonyTimeZoneSuggestion oldSuggestion, @NonNull TelephonyTimeZoneSuggestion newSuggestion)90     private static boolean shouldSendNewTimeZoneSuggestion(
91             @Nullable TelephonyTimeZoneSuggestion oldSuggestion,
92             @NonNull TelephonyTimeZoneSuggestion newSuggestion) {
93         if (oldSuggestion == null) {
94             // No previous suggestion.
95             return true;
96         }
97         // This code relies on PhoneTimeZoneSuggestion.equals() to only check meaningful fields.
98         return !Objects.equals(newSuggestion, oldSuggestion);
99     }
100 
101     @Override
dumpLogs(IndentingPrintWriter ipw)102     public void dumpLogs(IndentingPrintWriter ipw) {
103         ipw.println("TimeServiceHelperImpl:");
104         ipw.increaseIndent();
105         ipw.println("SystemClock.elapsedRealtime()=" + SystemClock.elapsedRealtime());
106         ipw.println("System.currentTimeMillis()=" + System.currentTimeMillis());
107 
108         ipw.println("Time Logs:");
109         ipw.increaseIndent();
110         mTimeLog.dump(ipw);
111         ipw.decreaseIndent();
112 
113         ipw.println("Time zone Logs:");
114         ipw.increaseIndent();
115         mTimeZoneLog.dump(ipw);
116         ipw.decreaseIndent();
117         ipw.decreaseIndent();
118     }
119 
120     @Override
dumpState(PrintWriter pw)121     public void dumpState(PrintWriter pw) {
122         pw.println(" TimeServiceHelperImpl.mLastSuggestedTimeZone=" + mLastSuggestedTimeZone);
123     }
124 }
125