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