1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/*
2c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Copyright (C) 2006 The Android Open Source Project
3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License.
6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at
7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software
11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and
14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License.
15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */
16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony.gsm;
18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
19c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.PhoneNumberUtils;
205ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumarimport java.text.ParseException;
21c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet;
22c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsAddress;
23c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
24c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepublic class GsmSmsAddress extends SmsAddress {
25c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
26c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    static final int OFFSET_ADDRESS_LENGTH = 0;
27c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
28c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    static final int OFFSET_TOA = 1;
29c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
30c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    static final int OFFSET_ADDRESS_VALUE = 2;
31c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
32c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
33c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field
34c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     *
35c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * @param offset the offset of the Address-Length byte
36c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * @param length the length in bytes rounded up, e.g. "2 +
37c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     *        (addressLength + 1) / 2"
385ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar     * @throws ParseException
39c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
40c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
415ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar    public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException {
42c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        origBytes = new byte[length];
43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        System.arraycopy(data, offset, origBytes, 0, length);
44c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
45c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // addressLength is the count of semi-octets, not bytes
46c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff;
47c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
48c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        int toa = origBytes[OFFSET_TOA] & 0xff;
49c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        ton = 0x7 & (toa >> 4);
50c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // TOA must have its high bit set
52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if ((toa & 0x80) != 0x80) {
535ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar            throw new ParseException("Invalid TOA - high bit must be set. toa = " + toa,
545ad6947b2d955a4e972d556090922d77aa6a2641Rekha Kumar                    offset + OFFSET_TOA);
55c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
56c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (isAlphanumeric()) {
58c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // An alphanumeric address
59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            int countSeptets = addressLength * 4 / 7;
60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
61c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            address = GsmAlphabet.gsm7BitPackedToString(origBytes,
62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    OFFSET_ADDRESS_VALUE, countSeptets);
63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        } else {
64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // TS 23.040 9.1.2.5 says
65c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // that "the MS shall interpret reserved values as 'Unknown'
66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // but shall store them exactly as received"
67c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            byte lastByte = origBytes[length - 1];
69c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            if ((addressLength & 1) == 1) {
71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                // Make sure the final unused BCD digit is 0xf
72c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                origBytes[length - 1] |= 0xf0;
73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            }
74c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            address = PhoneNumberUtils.calledPartyBCDToString(origBytes,
75c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    OFFSET_TOA, length - OFFSET_TOA);
76c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
77c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // And restore origBytes
78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            origBytes[length - 1] = lastByte;
79c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
81c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
82cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    @Override
83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public String getAddressString() {
84c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return address;
85c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
86c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
87c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
88c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Returns true if this is an alphanumeric address
89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
90cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    @Override
91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public boolean isAlphanumeric() {
92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return ton == TON_ALPHANUMERIC;
93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
95cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    @Override
96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public boolean isNetworkSpecific() {
97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return ton == TON_NETWORK;
98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
99c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Returns true of this is a valid CPHS voice message waiting indicator
102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * address
103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public boolean isCphsVoiceMessageIndicatorAddress() {
105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // CPHS-style MWI message
106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // See CPHS 4.7 B.4.2.1
107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        //
108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Basically:
109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        //
110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // - Originating address should be 4 bytes long and alphanumeric
111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // - Decode will result with two chars:
112c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // - Char 1
113c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // 76543210
114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // ^ set/clear indicator (0 = clear)
115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // ^^^ type of indicator (000 = voice)
116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // ^^^^ must be equal to 0001
117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // - Char 2:
118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // 76543210
119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // ^ line number (0 = line 1)
120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // ^^^^^^^ set to 0
121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        //
122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Remember, since the alpha address is stored in 7-bit compact form,
123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // the "line number" is really the top bit of the first address value
124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // byte
125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4
127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0;
128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Returns true if this is a valid CPHS voice message waiting indicator
132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * address indicating a "set" of "indicator 1" of type "voice message
133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * waiting"
134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public boolean isCphsVoiceMessageSet() {
136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // 0x11 means "set" "voice message waiting" "indicator 1"
137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return isCphsVoiceMessageIndicatorAddress()
138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11;
139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Returns true if this is a valid CPHS voice message waiting indicator
144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * address indicating a "clear" of "indicator 1" of type "voice message
145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * waiting"
146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public boolean isCphsVoiceMessageClear() {
148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // 0x10 means "clear" "voice message waiting" "indicator 1"
149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return isCphsVoiceMessageIndicatorAddress()
150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10;
151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
152c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
153c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville}
154