Skip to content

Commit e4ae7fc

Browse files
Jean-Baptiste QueruAndroid Code Review
authored andcommitted
Merge "Enabling cell broadcast (SMS-CB) support in the platform."
2 parents b2b0db2 + 95bc625 commit e4ae7fc

File tree

11 files changed

+1064
-1
lines changed

11 files changed

+1064
-1
lines changed
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/*
2+
* Copyright (C) 2010 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+
17+
package android.telephony;
18+
19+
import com.android.internal.telephony.GsmAlphabet;
20+
import com.android.internal.telephony.gsm.SmsCbHeader;
21+
22+
import java.io.UnsupportedEncodingException;
23+
24+
/**
25+
* Describes an SMS-CB message.
26+
*
27+
* {@hide}
28+
*/
29+
public class SmsCbMessage {
30+
31+
/**
32+
* Cell wide immediate geographical scope
33+
*/
34+
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
35+
36+
/**
37+
* PLMN wide geographical scope
38+
*/
39+
public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
40+
41+
/**
42+
* Location / service area wide geographical scope
43+
*/
44+
public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
45+
46+
/**
47+
* Cell wide geographical scope
48+
*/
49+
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
50+
51+
/**
52+
* Create an instance of this class from a received PDU
53+
*
54+
* @param pdu PDU bytes
55+
* @return An instance of this class, or null if invalid pdu
56+
*/
57+
public static SmsCbMessage createFromPdu(byte[] pdu) {
58+
try {
59+
return new SmsCbMessage(pdu);
60+
} catch (IllegalArgumentException e) {
61+
return null;
62+
}
63+
}
64+
65+
/**
66+
* Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
67+
*/
68+
private static final String[] LANGUAGE_CODES_GROUP_0 = {
69+
"de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
70+
"pl", null
71+
};
72+
73+
/**
74+
* Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
75+
*/
76+
private static final String[] LANGUAGE_CODES_GROUP_2 = {
77+
"cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
78+
null, null
79+
};
80+
81+
private static final char CARRIAGE_RETURN = 0x0d;
82+
83+
private SmsCbHeader mHeader;
84+
85+
private String mLanguage;
86+
87+
private String mBody;
88+
89+
private SmsCbMessage(byte[] pdu) throws IllegalArgumentException {
90+
mHeader = new SmsCbHeader(pdu);
91+
parseBody(pdu);
92+
}
93+
94+
/**
95+
* Return the geographical scope of this message, one of
96+
* {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE},
97+
* {@link #GEOGRAPHICAL_SCOPE_PLMN_WIDE},
98+
* {@link #GEOGRAPHICAL_SCOPE_LA_WIDE},
99+
* {@link #GEOGRAPHICAL_SCOPE_CELL_WIDE}
100+
*
101+
* @return Geographical scope
102+
*/
103+
public int getGeographicalScope() {
104+
return mHeader.geographicalScope;
105+
}
106+
107+
/**
108+
* Get the ISO-639-1 language code for this message, or null if unspecified
109+
*
110+
* @return Language code
111+
*/
112+
public String getLanguageCode() {
113+
return mLanguage;
114+
}
115+
116+
/**
117+
* Get the body of this message, or null if no body available
118+
*
119+
* @return Body, or null
120+
*/
121+
public String getMessageBody() {
122+
return mBody;
123+
}
124+
125+
/**
126+
* Get the message identifier of this message (0-65535)
127+
*
128+
* @return Message identifier
129+
*/
130+
public int getMessageIdentifier() {
131+
return mHeader.messageIdentifier;
132+
}
133+
134+
/**
135+
* Get the message code of this message (0-1023)
136+
*
137+
* @return Message code
138+
*/
139+
public int getMessageCode() {
140+
return mHeader.messageCode;
141+
}
142+
143+
/**
144+
* Get the update number of this message (0-15)
145+
*
146+
* @return Update number
147+
*/
148+
public int getUpdateNumber() {
149+
return mHeader.updateNumber;
150+
}
151+
152+
private void parseBody(byte[] pdu) {
153+
int encoding;
154+
boolean hasLanguageIndicator = false;
155+
156+
// Extract encoding and language from DCS, as defined in 3gpp TS 23.038,
157+
// section 5.
158+
switch ((mHeader.dataCodingScheme & 0xf0) >> 4) {
159+
case 0x00:
160+
encoding = SmsMessage.ENCODING_7BIT;
161+
mLanguage = LANGUAGE_CODES_GROUP_0[mHeader.dataCodingScheme & 0x0f];
162+
break;
163+
164+
case 0x01:
165+
hasLanguageIndicator = true;
166+
if ((mHeader.dataCodingScheme & 0x0f) == 0x01) {
167+
encoding = SmsMessage.ENCODING_16BIT;
168+
} else {
169+
encoding = SmsMessage.ENCODING_7BIT;
170+
}
171+
break;
172+
173+
case 0x02:
174+
encoding = SmsMessage.ENCODING_7BIT;
175+
mLanguage = LANGUAGE_CODES_GROUP_2[mHeader.dataCodingScheme & 0x0f];
176+
break;
177+
178+
case 0x03:
179+
encoding = SmsMessage.ENCODING_7BIT;
180+
break;
181+
182+
case 0x04:
183+
case 0x05:
184+
switch ((mHeader.dataCodingScheme & 0x0c) >> 2) {
185+
case 0x01:
186+
encoding = SmsMessage.ENCODING_8BIT;
187+
break;
188+
189+
case 0x02:
190+
encoding = SmsMessage.ENCODING_16BIT;
191+
break;
192+
193+
case 0x00:
194+
default:
195+
encoding = SmsMessage.ENCODING_7BIT;
196+
break;
197+
}
198+
break;
199+
200+
case 0x06:
201+
case 0x07:
202+
// Compression not supported
203+
case 0x09:
204+
// UDH structure not supported
205+
case 0x0e:
206+
// Defined by the WAP forum not supported
207+
encoding = SmsMessage.ENCODING_UNKNOWN;
208+
break;
209+
210+
case 0x0f:
211+
if (((mHeader.dataCodingScheme & 0x04) >> 2) == 0x01) {
212+
encoding = SmsMessage.ENCODING_8BIT;
213+
} else {
214+
encoding = SmsMessage.ENCODING_7BIT;
215+
}
216+
break;
217+
218+
default:
219+
// Reserved values are to be treated as 7-bit
220+
encoding = SmsMessage.ENCODING_7BIT;
221+
break;
222+
}
223+
224+
switch (encoding) {
225+
case SmsMessage.ENCODING_7BIT:
226+
mBody = GsmAlphabet.gsm7BitPackedToString(pdu, SmsCbHeader.PDU_HEADER_LENGTH,
227+
(pdu.length - SmsCbHeader.PDU_HEADER_LENGTH) * 8 / 7);
228+
229+
if (hasLanguageIndicator && mBody != null && mBody.length() > 2) {
230+
mLanguage = mBody.substring(0, 2);
231+
mBody = mBody.substring(3);
232+
}
233+
break;
234+
235+
case SmsMessage.ENCODING_16BIT:
236+
int offset = SmsCbHeader.PDU_HEADER_LENGTH;
237+
238+
if (hasLanguageIndicator && pdu.length >= SmsCbHeader.PDU_HEADER_LENGTH + 2) {
239+
mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu,
240+
SmsCbHeader.PDU_HEADER_LENGTH, 2);
241+
offset += 2;
242+
}
243+
244+
try {
245+
mBody = new String(pdu, offset, (pdu.length & 0xfffe) - offset, "utf-16");
246+
} catch (UnsupportedEncodingException e) {
247+
// Eeeek
248+
}
249+
break;
250+
251+
default:
252+
break;
253+
}
254+
255+
if (mBody != null) {
256+
// Remove trailing carriage return
257+
for (int i = mBody.length() - 1; i >= 0; i--) {
258+
if (mBody.charAt(i) != CARRIAGE_RETURN) {
259+
mBody = mBody.substring(0, i + 1);
260+
break;
261+
}
262+
}
263+
} else {
264+
mBody = "";
265+
}
266+
}
267+
}

telephony/java/android/telephony/SmsManager.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,67 @@ public ArrayList<SmsMessage> getAllMessagesFromIcc() {
341341
}
342342

343343
return createMessageListFromRawRecords(records);
344-
}
344+
}
345+
346+
/**
347+
* Enable reception of cell broadcast (SMS-CB) messages with the given
348+
* message identifier. Note that if two different clients enable the same
349+
* message identifier, they must both disable it for the device to stop
350+
* receiving those messages. All received messages will be broadcast in an
351+
* intent with the action "android.provider.telephony.SMS_CB_RECEIVED".
352+
* Note: This call is blocking, callers may want to avoid calling it from
353+
* the main thread of an application.
354+
*
355+
* @param messageIdentifier Message identifier as specified in TS 23.041
356+
* @return true if successful, false otherwise
357+
* @see #disableCellBroadcast(int)
358+
*
359+
* {@hide}
360+
*/
361+
public boolean enableCellBroadcast(int messageIdentifier) {
362+
boolean success = false;
363+
364+
try {
365+
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
366+
if (iccISms != null) {
367+
success = iccISms.enableCellBroadcast(messageIdentifier);
368+
}
369+
} catch (RemoteException ex) {
370+
// ignore it
371+
}
372+
373+
return success;
374+
}
375+
376+
/**
377+
* Disable reception of cell broadcast (SMS-CB) messages with the given
378+
* message identifier. Note that if two different clients enable the same
379+
* message identifier, they must both disable it for the device to stop
380+
* receiving those messages.
381+
* Note: This call is blocking, callers may want to avoid calling it from
382+
* the main thread of an application.
383+
*
384+
* @param messageIdentifier Message identifier as specified in TS 23.041
385+
* @return true if successful, false otherwise
386+
*
387+
* @see #enableCellBroadcast(int)
388+
*
389+
* {@hide}
390+
*/
391+
public boolean disableCellBroadcast(int messageIdentifier) {
392+
boolean success = false;
393+
394+
try {
395+
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
396+
if (iccISms != null) {
397+
success = iccISms.disableCellBroadcast(messageIdentifier);
398+
}
399+
} catch (RemoteException ex) {
400+
// ignore it
401+
}
402+
403+
return success;
404+
}
345405

346406
/**
347407
* Create a list of <code>SmsMessage</code>s from a list of RawSmsData

telephony/java/com/android/internal/telephony/ISms.aidl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,30 @@ interface ISms {
144144
in List<String> parts, in List<PendingIntent> sentIntents,
145145
in List<PendingIntent> deliveryIntents);
146146

147+
/**
148+
* Enable reception of cell broadcast (SMS-CB) messages with the given
149+
* message identifier. Note that if two different clients enable the same
150+
* message identifier, they must both disable it for the device to stop
151+
* receiving those messages.
152+
*
153+
* @param messageIdentifier Message identifier as specified in TS 23.041
154+
* @return true if successful, false otherwise
155+
*
156+
* @see #disableCellBroadcast(int)
157+
*/
158+
boolean enableCellBroadcast(int messageIdentifier);
159+
160+
/**
161+
* Disable reception of cell broadcast (SMS-CB) messages with the given
162+
* message identifier. Note that if two different clients enable the same
163+
* message identifier, they must both disable it for the device to stop
164+
* receiving those messages.
165+
*
166+
* @param messageIdentifier Message identifier as specified in TS 23.041
167+
* @return true if successful, false otherwise
168+
*
169+
* @see #enableCellBroadcast(int)
170+
*/
171+
boolean disableCellBroadcast(int messageIdentifier);
172+
147173
}

telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,12 @@ public void sendMultipartText(String destAddr, String scAddr,
6868
parts, sentIntents, deliveryIntents);
6969
}
7070

71+
public boolean enableCellBroadcast(int messageIdentifier) throws android.os.RemoteException {
72+
return mIccSmsInterfaceManager.enableCellBroadcast(messageIdentifier);
73+
}
74+
75+
public boolean disableCellBroadcast(int messageIdentifier) throws android.os.RemoteException {
76+
return mIccSmsInterfaceManager.disableCellBroadcast(messageIdentifier);
77+
}
78+
7179
}

0 commit comments

Comments
 (0)