1 /*
2  * Copyright (C) 2012 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 android.telephony;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import com.android.internal.telephony.uicc.IccUtils;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.time.LocalDateTime;
31 import java.time.ZoneOffset;
32 import java.util.Arrays;
33 
34 /**
35  * Contains information elements for a GSM or UMTS ETWS (Earthquake and Tsunami Warning
36  * System) warning notification. Supported values for each element are defined in 3GPP TS 23.041.
37  *
38  * {@hide}
39  */
40 @SystemApi
41 public final class SmsCbEtwsInfo implements Parcelable {
42 
43     /** ETWS warning type for earthquake. */
44     public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00;
45 
46     /** ETWS warning type for tsunami. */
47     public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01;
48 
49     /** ETWS warning type for earthquake and tsunami. */
50     public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02;
51 
52     /** ETWS warning type for test messages. */
53     public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 0x03;
54 
55     /** ETWS warning type for other emergency types. */
56     public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 0x04;
57 
58     /** Unknown ETWS warning type. */
59     public static final int ETWS_WARNING_TYPE_UNKNOWN = -1;
60 
61     /** @hide */
62     @Retention(RetentionPolicy.SOURCE)
63     @IntDef(prefix = {"ETWS_WARNING_TYPE_"},
64             value = {
65                     ETWS_WARNING_TYPE_EARTHQUAKE,
66                     ETWS_WARNING_TYPE_TSUNAMI,
67                     ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI,
68                     ETWS_WARNING_TYPE_TEST_MESSAGE,
69                     ETWS_WARNING_TYPE_OTHER_EMERGENCY,
70                     ETWS_WARNING_TYPE_UNKNOWN,
71             })
72     public @interface WarningType {}
73 
74     /** One of the ETWS warning type constants defined in this class. */
75     private final @WarningType int mWarningType;
76 
77     /** Whether or not to activate the emergency user alert tone and vibration. */
78     private final boolean mIsEmergencyUserAlert;
79 
80     /** Whether or not to activate a popup alert. */
81     private final boolean mIsPopupAlert;
82 
83     /** Whether ETWS primary message or not/ */
84     private final boolean mIsPrimary;
85 
86     /**
87      * 50-byte security information (ETWS primary notification for GSM only). As of Release 10,
88      * 3GPP TS 23.041 states that the UE shall ignore the ETWS primary notification timestamp
89      * and digital signature if received. Therefore it is treated as a raw byte array and
90      * parceled with the broadcast intent if present, but the timestamp is only computed if an
91      * application asks for the individual components.
92      */
93     @Nullable
94     private final byte[] mWarningSecurityInformation;
95 
96     /**
97      * Create a new SmsCbEtwsInfo object with the specified values.
98      * @param warningType the type of ETWS warning
99      * @param isEmergencyUserAlert whether the warning is an emergency alert, which will activate
100      *                             the user alert tone and vibration
101      * @param isPopupAlert whether the warning will activate a popup alert
102      * @param isPrimary whether this is an ETWS primary message
103      * @param warningSecurityInformation 50-byte security information (for primary notifications
104      *                                   on GSM only).
105      */
SmsCbEtwsInfo(@arningType int warningType, boolean isEmergencyUserAlert, boolean isPopupAlert, boolean isPrimary, @Nullable byte[] warningSecurityInformation)106     public SmsCbEtwsInfo(@WarningType int warningType, boolean isEmergencyUserAlert,
107             boolean isPopupAlert,
108             boolean isPrimary, @Nullable byte[] warningSecurityInformation) {
109         mWarningType = warningType;
110         mIsEmergencyUserAlert = isEmergencyUserAlert;
111         mIsPopupAlert = isPopupAlert;
112         mIsPrimary = isPrimary;
113         mWarningSecurityInformation = warningSecurityInformation;
114     }
115 
116     /** Create a new SmsCbEtwsInfo object from a Parcel. */
SmsCbEtwsInfo(Parcel in)117     SmsCbEtwsInfo(Parcel in) {
118         mWarningType = in.readInt();
119         mIsEmergencyUserAlert = (in.readInt() != 0);
120         mIsPopupAlert = (in.readInt() != 0);
121         mIsPrimary = (in.readInt() != 0);
122         mWarningSecurityInformation = in.createByteArray();
123     }
124 
125     /**
126      * Flatten this object into a Parcel.
127      *
128      * @param dest  The Parcel in which the object should be written.
129      * @param flags Additional flags about how the object should be written (ignored).
130      */
131     @Override
writeToParcel(Parcel dest, int flags)132     public void writeToParcel(Parcel dest, int flags) {
133         dest.writeInt(mWarningType);
134         dest.writeInt(mIsEmergencyUserAlert ? 1 : 0);
135         dest.writeInt(mIsPopupAlert ? 1 : 0);
136         dest.writeInt(mIsPrimary ? 1 : 0);
137         dest.writeByteArray(mWarningSecurityInformation);
138     }
139 
140     /**
141      * Returns the ETWS warning type.
142      * @return a warning type such as {@link #ETWS_WARNING_TYPE_EARTHQUAKE}
143      */
getWarningType()144     public @WarningType int getWarningType() {
145         return mWarningType;
146     }
147 
148     /**
149      * Returns the ETWS emergency user alert flag. If the ETWS message is an emergency alert, it
150      * will activate an alert tone and vibration.
151      * @return true to notify terminal to activate emergency user alert; false otherwise
152      */
isEmergencyUserAlert()153     public boolean isEmergencyUserAlert() {
154         return mIsEmergencyUserAlert;
155     }
156 
157     /**
158      * Returns the ETWS activate popup flag.
159      * @return true to notify terminal to activate display popup; false otherwise
160      */
isPopupAlert()161     public boolean isPopupAlert() {
162         return mIsPopupAlert;
163     }
164 
165     /**
166      * Returns the ETWS format flag.
167      * @return true if the message is primary message, otherwise secondary message
168      */
isPrimary()169     public boolean isPrimary() {
170         return mIsPrimary;
171     }
172 
173     /**
174      * Returns the Warning-Security-Information timestamp (GSM primary notifications only).
175      * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received.
176      * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present
177      */
getPrimaryNotificationTimestamp()178     public long getPrimaryNotificationTimestamp() {
179         if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) {
180             return 0;
181         }
182 
183         int year = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[0]);
184         int month = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[1]);
185         int day = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[2]);
186         int hour = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[3]);
187         int minute = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[4]);
188         int second = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[5]);
189 
190         // For the timezone, the most significant bit of the
191         // least significant nibble is the sign byte
192         // (meaning the max range of this field is 79 quarter-hours,
193         // which is more than enough)
194 
195         byte tzByte = mWarningSecurityInformation[6];
196 
197         // Mask out sign bit.
198         int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
199 
200         timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
201         // timezoneOffset is in quarter hours.
202         int timeZoneOffsetSeconds = timezoneOffset * 15 * 60;
203 
204         LocalDateTime localDateTime = LocalDateTime.of(
205                 // We only need to support years above 2000.
206                 year + 2000,
207                 month /* 1-12 */,
208                 day,
209                 hour,
210                 minute,
211                 second);
212 
213         long epochSeconds = localDateTime.toEpochSecond(ZoneOffset.UTC) - timeZoneOffsetSeconds;
214         // Convert to milliseconds, ignore overflow.
215         return epochSeconds * 1000;
216     }
217 
218     /**
219      * Returns the digital signature (GSM primary notifications only). As of Release 10,
220      * 3GPP TS 23.041 states that the UE shall ignore this value if received.
221      * @return a byte array containing a copy of the primary notification digital signature
222      */
223     @Nullable
getPrimaryNotificationSignature()224     public byte[] getPrimaryNotificationSignature() {
225         if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 50) {
226             return null;
227         }
228         return Arrays.copyOfRange(mWarningSecurityInformation, 7, 50);
229     }
230 
231     @Override
toString()232     public String toString() {
233         return "SmsCbEtwsInfo{warningType=" + mWarningType + ", emergencyUserAlert="
234                 + mIsEmergencyUserAlert + ", activatePopup=" + mIsPopupAlert + '}';
235     }
236 
237     /**
238      * Describe the kinds of special objects contained in the marshalled representation.
239      * @return a bitmask indicating this Parcelable contains no special objects
240      */
241     @Override
describeContents()242     public int describeContents() {
243         return 0;
244     }
245 
246     /** Creator for unparcelling objects. */
247     @NonNull
248     public static final Creator<SmsCbEtwsInfo> CREATOR = new Creator<SmsCbEtwsInfo>() {
249         @Override
250         public SmsCbEtwsInfo createFromParcel(Parcel in) {
251             return new SmsCbEtwsInfo(in);
252         }
253 
254         @Override
255         public SmsCbEtwsInfo[] newArray(int size) {
256             return new SmsCbEtwsInfo[size];
257         }
258     };
259 }
260