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