1/* 2 * Copyright (C) 2006 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 com.android.internal.telephony.gsm; 18 19import android.telephony.PhoneNumberUtils; 20 21import java.text.ParseException; 22import com.android.internal.telephony.GsmAlphabet; 23import com.android.internal.telephony.SmsAddress; 24 25public class GsmSmsAddress extends SmsAddress { 26 27 static final int OFFSET_ADDRESS_LENGTH = 0; 28 29 static final int OFFSET_TOA = 1; 30 31 static final int OFFSET_ADDRESS_VALUE = 2; 32 33 /** 34 * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field 35 * 36 * @param offset the offset of the Address-Length byte 37 * @param length the length in bytes rounded up, e.g. "2 + 38 * (addressLength + 1) / 2" 39 * @throws ParseException 40 */ 41 42 public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException { 43 origBytes = new byte[length]; 44 System.arraycopy(data, offset, origBytes, 0, length); 45 46 // addressLength is the count of semi-octets, not bytes 47 int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; 48 49 int toa = origBytes[OFFSET_TOA] & 0xff; 50 ton = 0x7 & (toa >> 4); 51 52 // TOA must have its high bit set 53 if ((toa & 0x80) != 0x80) { 54 throw new ParseException("Invalid TOA - high bit must be set. toa = " + toa, 55 offset + OFFSET_TOA); 56 } 57 58 if (isAlphanumeric()) { 59 // An alphanumeric address 60 int countSeptets = addressLength * 4 / 7; 61 62 address = GsmAlphabet.gsm7BitPackedToString(origBytes, 63 OFFSET_ADDRESS_VALUE, countSeptets); 64 } else { 65 // TS 23.040 9.1.2.5 says 66 // that "the MS shall interpret reserved values as 'Unknown' 67 // but shall store them exactly as received" 68 69 byte lastByte = origBytes[length - 1]; 70 71 if ((addressLength & 1) == 1) { 72 // Make sure the final unused BCD digit is 0xf 73 origBytes[length - 1] |= 0xf0; 74 } 75 address = PhoneNumberUtils.calledPartyBCDToString( 76 origBytes, 77 OFFSET_TOA, 78 length - OFFSET_TOA, 79 PhoneNumberUtils.BCD_EXTENDED_TYPE_CALLED_PARTY); 80 81 // And restore origBytes 82 origBytes[length - 1] = lastByte; 83 } 84 } 85 86 @Override 87 public String getAddressString() { 88 return address; 89 } 90 91 /** 92 * Returns true if this is an alphanumeric address 93 */ 94 @Override 95 public boolean isAlphanumeric() { 96 return ton == TON_ALPHANUMERIC; 97 } 98 99 @Override 100 public boolean isNetworkSpecific() { 101 return ton == TON_NETWORK; 102 } 103 104 /** 105 * Returns true of this is a valid CPHS voice message waiting indicator 106 * address 107 */ 108 public boolean isCphsVoiceMessageIndicatorAddress() { 109 // CPHS-style MWI message 110 // See CPHS 4.7 B.4.2.1 111 // 112 // Basically: 113 // 114 // - Originating address should be 4 bytes long and alphanumeric 115 // - Decode will result with two chars: 116 // - Char 1 117 // 76543210 118 // ^ set/clear indicator (0 = clear) 119 // ^^^ type of indicator (000 = voice) 120 // ^^^^ must be equal to 0001 121 // - Char 2: 122 // 76543210 123 // ^ line number (0 = line 1) 124 // ^^^^^^^ set to 0 125 // 126 // Remember, since the alpha address is stored in 7-bit compact form, 127 // the "line number" is really the top bit of the first address value 128 // byte 129 130 return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 131 && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; 132 } 133 134 /** 135 * Returns true if this is a valid CPHS voice message waiting indicator 136 * address indicating a "set" of "indicator 1" of type "voice message 137 * waiting" 138 */ 139 public boolean isCphsVoiceMessageSet() { 140 // 0x11 means "set" "voice message waiting" "indicator 1" 141 return isCphsVoiceMessageIndicatorAddress() 142 && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; 143 144 } 145 146 /** 147 * Returns true if this is a valid CPHS voice message waiting indicator 148 * address indicating a "clear" of "indicator 1" of type "voice message 149 * waiting" 150 */ 151 public boolean isCphsVoiceMessageClear() { 152 // 0x10 means "clear" "voice message waiting" "indicator 1" 153 return isCphsVoiceMessageIndicatorAddress() 154 && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; 155 156 } 157} 158