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.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    /**
63     * 50-byte security information (ETWS primary notification for GSM only). As of Release 10,
64     * 3GPP TS 23.041 states that the UE shall ignore the ETWS primary notification timestamp
65     * and digital signature if received. Therefore it is treated as a raw byte array and
66     * parceled with the broadcast intent if present, but the timestamp is only computed if an
67     * application asks for the individual components.
68     */
69    private final byte[] mWarningSecurityInformation;
70
71    /** Create a new SmsCbEtwsInfo object with the specified values. */
72    public SmsCbEtwsInfo(int warningType, boolean emergencyUserAlert, boolean activatePopup,
73            byte[] warningSecurityInformation) {
74        mWarningType = warningType;
75        mEmergencyUserAlert = emergencyUserAlert;
76        mActivatePopup = activatePopup;
77        mWarningSecurityInformation = warningSecurityInformation;
78    }
79
80    /** Create a new SmsCbEtwsInfo object from a Parcel. */
81    SmsCbEtwsInfo(Parcel in) {
82        mWarningType = in.readInt();
83        mEmergencyUserAlert = (in.readInt() != 0);
84        mActivatePopup = (in.readInt() != 0);
85        mWarningSecurityInformation = in.createByteArray();
86    }
87
88    /**
89     * Flatten this object into a Parcel.
90     *
91     * @param dest  The Parcel in which the object should be written.
92     * @param flags Additional flags about how the object should be written (ignored).
93     */
94    @Override
95    public void writeToParcel(Parcel dest, int flags) {
96        dest.writeInt(mWarningType);
97        dest.writeInt(mEmergencyUserAlert ? 1 : 0);
98        dest.writeInt(mActivatePopup ? 1 : 0);
99        dest.writeByteArray(mWarningSecurityInformation);
100    }
101
102    /**
103     * Returns the ETWS warning type.
104     * @return a warning type such as {@link #ETWS_WARNING_TYPE_EARTHQUAKE}
105     */
106    public int getWarningType() {
107        return mWarningType;
108    }
109
110    /**
111     * Returns the ETWS emergency user alert flag.
112     * @return true to notify terminal to activate emergency user alert; false otherwise
113     */
114    public boolean isEmergencyUserAlert() {
115        return mEmergencyUserAlert;
116    }
117
118    /**
119     * Returns the ETWS activate popup flag.
120     * @return true to notify terminal to activate display popup; false otherwise
121     */
122    public boolean isPopupAlert() {
123        return mActivatePopup;
124    }
125
126    /**
127     * Returns the Warning-Security-Information timestamp (GSM primary notifications only).
128     * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received.
129     * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present
130     */
131    public long getPrimaryNotificationTimestamp() {
132        if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) {
133            return 0;
134        }
135
136        int year = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[0]);
137        int month = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[1]);
138        int day = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[2]);
139        int hour = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[3]);
140        int minute = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[4]);
141        int second = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[5]);
142
143        // For the timezone, the most significant bit of the
144        // least significant nibble is the sign byte
145        // (meaning the max range of this field is 79 quarter-hours,
146        // which is more than enough)
147
148        byte tzByte = mWarningSecurityInformation[6];
149
150        // Mask out sign bit.
151        int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
152
153        timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
154
155        Time time = new Time(Time.TIMEZONE_UTC);
156
157        // We only need to support years above 2000.
158        time.year = year + 2000;
159        time.month = month - 1;
160        time.monthDay = day;
161        time.hour = hour;
162        time.minute = minute;
163        time.second = second;
164
165        // Timezone offset is in quarter hours.
166        return time.toMillis(true) - (long) (timezoneOffset * 15 * 60 * 1000);
167    }
168
169    /**
170     * Returns the digital signature (GSM primary notifications only). As of Release 10,
171     * 3GPP TS 23.041 states that the UE shall ignore this value if received.
172     * @return a byte array containing a copy of the primary notification digital signature
173     */
174    public byte[] getPrimaryNotificationSignature() {
175        if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 50) {
176            return null;
177        }
178        return Arrays.copyOfRange(mWarningSecurityInformation, 7, 50);
179    }
180
181    @Override
182    public String toString() {
183        return "SmsCbEtwsInfo{warningType=" + mWarningType + ", emergencyUserAlert="
184                + mEmergencyUserAlert + ", activatePopup=" + mActivatePopup + '}';
185    }
186
187    /**
188     * Describe the kinds of special objects contained in the marshalled representation.
189     * @return a bitmask indicating this Parcelable contains no special objects
190     */
191    @Override
192    public int describeContents() {
193        return 0;
194    }
195
196    /** Creator for unparcelling objects. */
197    public static final Creator<SmsCbEtwsInfo> CREATOR = new Creator<SmsCbEtwsInfo>() {
198        public SmsCbEtwsInfo createFromParcel(Parcel in) {
199            return new SmsCbEtwsInfo(in);
200        }
201
202        public SmsCbEtwsInfo[] newArray(int size) {
203            return new SmsCbEtwsInfo[size];
204        }
205    };
206}
207