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