1 /*
2  * Copyright 2018 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;
18 
19 import android.annotation.NonNull;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.os.SystemClock;
23 import android.os.SystemProperties;
24 import android.provider.Settings;
25 
26 import com.android.internal.util.IndentingPrintWriter;
27 
28 import java.io.FileDescriptor;
29 import java.io.PrintWriter;
30 
31 /**
32  * An interface for the Android component that handles NITZ and related signals for time and time
33  * zone detection.
34  *
35  * {@hide}
36  */
37 public interface NitzStateMachine {
38 
39     /**
40      * Called when the country suitable for time zone detection is detected.
41      *
42      * @param countryIsoCode the countryIsoCode to use for time zone detection, may be "" for test
43      *     cells only, otherwise {@link #handleCountryUnavailable()} should be called
44      */
handleCountryDetected(@onNull String countryIsoCode)45     void handleCountryDetected(@NonNull String countryIsoCode);
46 
47     /**
48      * Informs the {@link NitzStateMachine} that the network has become available.
49      */
handleNetworkAvailable()50     void handleNetworkAvailable();
51 
52     /**
53      * Informs the {@link NitzStateMachine} that the network has become unavailable. Any network
54      * state, i.e. NITZ, should be cleared.
55      */
handleNetworkUnavailable()56     void handleNetworkUnavailable();
57 
58     /**
59      * Informs the {@link NitzStateMachine} that any previously detected country supplied via
60      * {@link #handleCountryDetected(String)} is no longer valid.
61      */
handleCountryUnavailable()62     void handleCountryUnavailable();
63 
64     /**
65      * Handle a new NITZ signal being received.
66      */
handleNitzReceived(@onNull NitzSignal nitzSignal)67     void handleNitzReceived(@NonNull NitzSignal nitzSignal);
68 
69     /**
70      * Handle the user putting the device into or out of airplane mode
71      * @param on true if airplane mode has been turned on, false if it's been turned off.
72      */
handleAirplaneModeChanged(boolean on)73     void handleAirplaneModeChanged(boolean on);
74 
75     /**
76      * Dumps the current in-memory state to the supplied PrintWriter.
77      */
dumpState(PrintWriter pw)78     void dumpState(PrintWriter pw);
79 
80     /**
81      * Dumps the time / time zone logs to the supplied IndentingPrintWriter.
82      */
dumpLogs(FileDescriptor fd, IndentingPrintWriter ipw, String[] args)83     void dumpLogs(FileDescriptor fd, IndentingPrintWriter ipw, String[] args);
84 
85     /**
86      * A proxy over read-only device state that allows things like system properties, elapsed
87      * realtime clock to be faked for tests.
88      */
89     interface DeviceState {
90 
91         /**
92          * If the elapsed realtime between two NITZ signals is greater than this value then the
93          * second signal cannot be ignored.
94          */
getNitzUpdateSpacingMillis()95         int getNitzUpdateSpacingMillis();
96 
97         /**
98          * If Unix epoch time between two NITZ signals is greater than this value then the second
99          * signal cannot be ignored.
100          */
getNitzUpdateDiffMillis()101         int getNitzUpdateDiffMillis();
102 
103         /**
104          * If the device connects to a telephony network and was disconnected from a telephony
105          * network for less than this time, a previously received NITZ signal can be restored.
106          *
107          * <p>The restored NITZ may not be from the same network as the current network. It is
108          * intended to be a relatively small value to allow for brief disconnections. Larger values
109          * increase the likelihood that the device has moved to a different network and/or time
110          * zone.
111          */
getNitzNetworkDisconnectRetentionMillis()112         int getNitzNetworkDisconnectRetentionMillis();
113 
114         /**
115          * Returns true if the {@code gsm.ignore-nitz} system property is set to "yes".
116          */
getIgnoreNitz()117         boolean getIgnoreNitz();
118 
119         /**
120          * Returns the same value as {@link SystemClock#elapsedRealtime()}.
121          */
elapsedRealtimeMillis()122         long elapsedRealtimeMillis();
123 
124         /**
125          * Returns the same value as {@link System#currentTimeMillis()}.
126          */
currentTimeMillis()127         long currentTimeMillis();
128     }
129 
130     /**
131      * The real implementation of {@link DeviceState}.
132      *
133      * {@hide}
134      */
135     class DeviceStateImpl implements DeviceState {
136 
137         /** The default value to use for {@link #getNitzUpdateSpacingMillis()}. 10 minutes. */
138         private static final int NITZ_UPDATE_SPACING_MILLIS_DEFAULT = 1000 * 60 * 10;
139         private final int mNitzUpdateSpacingMillis;
140 
141         /** The default value to use for {@link #getNitzUpdateDiffMillis()}. 2 seconds. */
142         private static final int NITZ_UPDATE_DIFF_MILLIS_DEFAULT = 2000;
143         private final int mNitzUpdateDiffMillis;
144 
145         /**
146          * The default value to use for {@link #getNitzNetworkDisconnectRetentionMillis()}.
147          * 5 minutes.
148          */
149         private static final int NITZ_NETWORK_DISCONNECT_RETENTION_MILLIS_DEFAULT = 1000 * 60 * 5;
150         private final int mNitzNetworkDisconnectRetentionMillis;
151 
152         private final ContentResolver mCr;
153 
DeviceStateImpl(Phone phone)154         public DeviceStateImpl(Phone phone) {
155             Context context = phone.getContext();
156             mCr = context.getContentResolver();
157             mNitzUpdateSpacingMillis =
158                     SystemProperties.getInt("ro.nitz_update_spacing",
159                             NITZ_UPDATE_SPACING_MILLIS_DEFAULT);
160             mNitzUpdateDiffMillis =
161                     SystemProperties.getInt("ro.nitz_update_diff", NITZ_UPDATE_DIFF_MILLIS_DEFAULT);
162             mNitzNetworkDisconnectRetentionMillis =
163                     SystemProperties.getInt("ro.nitz_network_disconnect_retention",
164                             NITZ_NETWORK_DISCONNECT_RETENTION_MILLIS_DEFAULT);
165         }
166 
167         @Override
getNitzUpdateSpacingMillis()168         public int getNitzUpdateSpacingMillis() {
169             return Settings.Global.getInt(mCr, Settings.Global.NITZ_UPDATE_SPACING,
170                     mNitzUpdateSpacingMillis);
171         }
172 
173         @Override
getNitzUpdateDiffMillis()174         public int getNitzUpdateDiffMillis() {
175             return Settings.Global.getInt(mCr, Settings.Global.NITZ_UPDATE_DIFF,
176                     mNitzUpdateDiffMillis);
177         }
178 
179         @Override
getNitzNetworkDisconnectRetentionMillis()180         public int getNitzNetworkDisconnectRetentionMillis() {
181             return Settings.Global.getInt(mCr, Settings.Global.NITZ_NETWORK_DISCONNECT_RETENTION,
182                     mNitzNetworkDisconnectRetentionMillis);
183         }
184 
185         @Override
getIgnoreNitz()186         public boolean getIgnoreNitz() {
187             String ignoreNitz = SystemProperties.get("gsm.ignore-nitz");
188             return ignoreNitz != null && ignoreNitz.equals("yes");
189         }
190 
191         @Override
elapsedRealtimeMillis()192         public long elapsedRealtimeMillis() {
193             return SystemClock.elapsedRealtime();
194         }
195 
196         @Override
currentTimeMillis()197         public long currentTimeMillis() {
198             return System.currentTimeMillis();
199         }
200     }
201 }
202