Skip to content

Commit 08063c9

Browse files
Jake HambyThe Android Automerger
authored andcommitted
Implement CMAS service category program results.
Correctly handle CDMA Service Category Program Data requests, and send the SCPT response to the message center. Parcel SCPD operations as an ArrayList instead of an array (current version will throw ClassCastException when the array is cast). Bug: 6853691 Change-Id: I949ea68891c78306059248832e59a593ab606e11
1 parent 54e963a commit 08063c9

File tree

7 files changed

+287
-29
lines changed

7 files changed

+287
-29
lines changed

telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ public class CdmaSmsCbProgramData implements Parcelable {
8181
/** Service category to modify. */
8282
private final int mCategory;
8383

84-
/** Language used for service category name (ISO 639 two character code). */
85-
private final String mLanguage;
84+
/** Language used for service category name (defined in BearerData.LANGUAGE_*). */
85+
private final int mLanguage;
8686

8787
/** Maximum number of messages to store for this service category. */
8888
private final int mMaxMessages;
@@ -94,7 +94,7 @@ public class CdmaSmsCbProgramData implements Parcelable {
9494
private final String mCategoryName;
9595

9696
/** Create a new CdmaSmsCbProgramData object with the specified values. */
97-
public CdmaSmsCbProgramData(int operation, int category, String language, int maxMessages,
97+
public CdmaSmsCbProgramData(int operation, int category, int language, int maxMessages,
9898
int alertOption, String categoryName) {
9999
mOperation = operation;
100100
mCategory = category;
@@ -108,7 +108,7 @@ public CdmaSmsCbProgramData(int operation, int category, String language, int ma
108108
CdmaSmsCbProgramData(Parcel in) {
109109
mOperation = in.readInt();
110110
mCategory = in.readInt();
111-
mLanguage = in.readString();
111+
mLanguage = in.readInt();
112112
mMaxMessages = in.readInt();
113113
mAlertOption = in.readInt();
114114
mCategoryName = in.readString();
@@ -124,7 +124,7 @@ public CdmaSmsCbProgramData(int operation, int category, String language, int ma
124124
public void writeToParcel(Parcel dest, int flags) {
125125
dest.writeInt(mOperation);
126126
dest.writeInt(mCategory);
127-
dest.writeString(mLanguage);
127+
dest.writeInt(mLanguage);
128128
dest.writeInt(mMaxMessages);
129129
dest.writeInt(mAlertOption);
130130
dest.writeString(mCategoryName);
@@ -147,10 +147,10 @@ public int getCategory() {
147147
}
148148

149149
/**
150-
* Returns the ISO-639-1 language code for the service category name, or null if not present.
151-
* @return a two-digit ISO-639-1 language code, e.g. "en" for English
150+
* Returns the CDMA language code for this service category.
151+
* @return one of the language values defined in BearerData.LANGUAGE_*
152152
*/
153-
public String getLanguageCode() {
153+
public int getLanguage() {
154154
return mLanguage;
155155
}
156156

@@ -171,7 +171,7 @@ public int getAlertOption() {
171171
}
172172

173173
/**
174-
* Returns the service category name, in the language specified by {@link #getLanguageCode()}.
174+
* Returns the service category name, in the language specified by {@link #getLanguage()}.
175175
* @return an optional service category name
176176
*/
177177
public String getCategoryName() {
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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+
17+
package android.telephony.cdma;
18+
19+
import android.os.Parcel;
20+
import android.os.Parcelable;
21+
22+
/**
23+
* CDMA Service Category Program Results from SCPT teleservice SMS.
24+
*
25+
* {@hide}
26+
*/
27+
public class CdmaSmsCbProgramResults implements Parcelable {
28+
29+
/** Program result: success. */
30+
public static final int RESULT_SUCCESS = 0;
31+
32+
/** Program result: memory limit exceeded. */
33+
public static final int RESULT_MEMORY_LIMIT_EXCEEDED = 1;
34+
35+
/** Program result: limit exceeded. */
36+
public static final int RESULT_CATEGORY_LIMIT_EXCEEDED = 2;
37+
38+
/** Program result: category already opted in. */
39+
public static final int RESULT_CATEGORY_ALREADY_ADDED = 3;
40+
41+
/** Program result: category already opted in. */
42+
public static final int RESULT_CATEGORY_ALREADY_DELETED = 4;
43+
44+
/** Program result: invalid MAX_MESSAGES. */
45+
public static final int RESULT_INVALID_MAX_MESSAGES = 5;
46+
47+
/** Program result: invalid ALERT_OPTION. */
48+
public static final int RESULT_INVALID_ALERT_OPTION = 6;
49+
50+
/** Program result: invalid service category name. */
51+
public static final int RESULT_INVALID_CATEGORY_NAME = 7;
52+
53+
/** Program result: unspecified programming failure. */
54+
public static final int RESULT_UNSPECIFIED_FAILURE = 8;
55+
56+
/** Service category to modify. */
57+
private final int mCategory;
58+
59+
/** Language used for service category name (defined in BearerData.LANGUAGE_*). */
60+
private final int mLanguage;
61+
62+
/** Result of service category programming for this category. */
63+
private final int mCategoryResult;
64+
65+
/** Create a new CdmaSmsCbProgramResults object with the specified values. */
66+
public CdmaSmsCbProgramResults(int category, int language, int categoryResult) {
67+
mCategory = category;
68+
mLanguage = language;
69+
mCategoryResult = categoryResult;
70+
}
71+
72+
/** Create a new CdmaSmsCbProgramResults object from a Parcel. */
73+
CdmaSmsCbProgramResults(Parcel in) {
74+
mCategory = in.readInt();
75+
mLanguage = in.readInt();
76+
mCategoryResult = in.readInt();
77+
}
78+
79+
/**
80+
* Flatten this object into a Parcel.
81+
*
82+
* @param dest The Parcel in which the object should be written.
83+
* @param flags Additional flags about how the object should be written (ignored).
84+
*/
85+
@Override
86+
public void writeToParcel(Parcel dest, int flags) {
87+
dest.writeInt(mCategory);
88+
dest.writeInt(mLanguage);
89+
dest.writeInt(mCategoryResult);
90+
}
91+
92+
/**
93+
* Returns the CDMA service category to modify.
94+
* @return a 16-bit CDMA service category value
95+
*/
96+
public int getCategory() {
97+
return mCategory;
98+
}
99+
100+
/**
101+
* Returns the CDMA language code for this service category.
102+
* @return one of the language values defined in BearerData.LANGUAGE_*
103+
*/
104+
public int getLanguage() {
105+
return mLanguage;
106+
}
107+
108+
/**
109+
* Returns the result of service programming for this category
110+
* @return the result of service programming for this category
111+
*/
112+
public int getCategoryResult() {
113+
return mCategoryResult;
114+
}
115+
116+
@Override
117+
public String toString() {
118+
return "CdmaSmsCbProgramResults{category=" + mCategory
119+
+ ", language=" + mLanguage + ", result=" + mCategoryResult + '}';
120+
}
121+
122+
/**
123+
* Describe the kinds of special objects contained in the marshalled representation.
124+
* @return a bitmask indicating this Parcelable contains no special objects
125+
*/
126+
@Override
127+
public int describeContents() {
128+
return 0;
129+
}
130+
131+
/** Creator for unparcelling objects. */
132+
public static final Parcelable.Creator<CdmaSmsCbProgramResults>
133+
CREATOR = new Parcelable.Creator<CdmaSmsCbProgramResults>() {
134+
@Override
135+
public CdmaSmsCbProgramResults createFromParcel(Parcel in) {
136+
return new CdmaSmsCbProgramResults(in);
137+
}
138+
139+
@Override
140+
public CdmaSmsCbProgramResults[] newArray(int size) {
141+
return new CdmaSmsCbProgramResults[size];
142+
}
143+
};
144+
}

telephony/java/com/android/internal/telephony/SMSDispatcher.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,22 @@ public void dispatch(Intent intent, String permission) {
338338
this, Activity.RESULT_OK, null, null);
339339
}
340340

341+
/**
342+
* Grabs a wake lock and sends intent as an ordered broadcast.
343+
* Used for setting a custom result receiver for CDMA SCPD.
344+
*
345+
* @param intent intent to broadcast
346+
* @param permission Receivers are required to have this permission
347+
* @param resultReceiver the result receiver to use
348+
*/
349+
public void dispatch(Intent intent, String permission, BroadcastReceiver resultReceiver) {
350+
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
351+
// receivers time to take their own wake locks.
352+
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
353+
mContext.sendOrderedBroadcast(intent, permission, resultReceiver,
354+
this, Activity.RESULT_OK, null, null);
355+
}
356+
341357
/**
342358
* Called when SMS send completes. Broadcasts a sentIntent on success.
343359
* On failure, either sets up retries or broadcasts a sentIntent with

telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,23 @@
2020
import android.app.Activity;
2121
import android.app.PendingIntent;
2222
import android.app.PendingIntent.CanceledException;
23-
import android.content.ContentValues;
23+
import android.content.BroadcastReceiver;
24+
import android.content.Context;
2425
import android.content.Intent;
2526
import android.content.SharedPreferences;
26-
import android.database.Cursor;
27-
import android.database.SQLException;
27+
import android.content.res.Resources;
28+
import android.os.Bundle;
2829
import android.os.Message;
2930
import android.os.SystemProperties;
3031
import android.preference.PreferenceManager;
3132
import android.provider.Telephony;
3233
import android.provider.Telephony.Sms.Intents;
34+
import android.telephony.PhoneNumberUtils;
3335
import android.telephony.SmsCbMessage;
3436
import android.telephony.SmsManager;
3537
import android.telephony.SmsMessage.MessageClass;
3638
import android.telephony.cdma.CdmaSmsCbProgramData;
39+
import android.telephony.cdma.CdmaSmsCbProgramResults;
3740
import android.util.Log;
3841

3942
import com.android.internal.telephony.CommandsInterface;
@@ -45,16 +48,17 @@
4548
import com.android.internal.telephony.SmsUsageMonitor;
4649
import com.android.internal.telephony.TelephonyProperties;
4750
import com.android.internal.telephony.WspTypeDecoder;
51+
import com.android.internal.telephony.cdma.sms.BearerData;
52+
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
4853
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
4954
import com.android.internal.telephony.cdma.sms.UserData;
50-
import com.android.internal.util.HexDump;
5155

5256
import java.io.ByteArrayOutputStream;
57+
import java.io.DataOutputStream;
58+
import java.io.IOException;
59+
import java.util.ArrayList;
5360
import java.util.Arrays;
5461
import java.util.HashMap;
55-
import java.util.List;
56-
57-
import android.content.res.Resources;
5862

5963

6064
final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -107,15 +111,16 @@ private void handleCdmaStatusReport(SmsMessage sms) {
107111
* {@link android.telephony.cdma.CdmaSmsCbProgramData} objects.
108112
*/
109113
private void handleServiceCategoryProgramData(SmsMessage sms) {
110-
List<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
114+
ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
111115
if (programDataList == null) {
112116
Log.e(TAG, "handleServiceCategoryProgramData: program data list is null!");
113117
return;
114118
}
115119

116120
Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
117-
intent.putExtra("program_data_list", (CdmaSmsCbProgramData[]) programDataList.toArray());
118-
dispatch(intent, RECEIVE_SMS_PERMISSION);
121+
intent.putExtra("sender", sms.getOriginatingAddress());
122+
intent.putParcelableArrayListExtra("program_data", programDataList);
123+
dispatch(intent, RECEIVE_SMS_PERMISSION, mScpResultsReceiver);
119124
}
120125

121126
/** {@inheritDoc} */
@@ -425,4 +430,72 @@ private static boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index)
425430
}
426431
return false;
427432
}
433+
434+
// Receiver for Service Category Program Data results.
435+
// We already ACK'd the original SCPD SMS, so this sends a new response SMS.
436+
// TODO: handle retries if the RIL returns an error.
437+
private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
438+
@Override
439+
public void onReceive(Context context, Intent intent) {
440+
int rc = getResultCode();
441+
boolean success = (rc == Activity.RESULT_OK) || (rc == Intents.RESULT_SMS_HANDLED);
442+
if (!success) {
443+
Log.e(TAG, "SCP results error: result code = " + rc);
444+
return;
445+
}
446+
Bundle extras = getResultExtras(false);
447+
if (extras == null) {
448+
Log.e(TAG, "SCP results error: missing extras");
449+
return;
450+
}
451+
String sender = extras.getString("sender");
452+
if (sender == null) {
453+
Log.e(TAG, "SCP results error: missing sender extra.");
454+
return;
455+
}
456+
ArrayList<CdmaSmsCbProgramResults> results
457+
= extras.getParcelableArrayList("results");
458+
if (results == null) {
459+
Log.e(TAG, "SCP results error: missing results extra.");
460+
return;
461+
}
462+
463+
BearerData bData = new BearerData();
464+
bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
465+
bData.messageId = SmsMessage.getNextMessageId();
466+
bData.serviceCategoryProgramResults = results;
467+
byte[] encodedBearerData = BearerData.encode(bData);
468+
469+
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
470+
DataOutputStream dos = new DataOutputStream(baos);
471+
try {
472+
dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
473+
dos.writeInt(0); //servicePresent
474+
dos.writeInt(0); //serviceCategory
475+
CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
476+
PhoneNumberUtils.cdmaCheckAndProcessPlusCode(sender));
477+
dos.write(destAddr.digitMode);
478+
dos.write(destAddr.numberMode);
479+
dos.write(destAddr.ton); // number_type
480+
dos.write(destAddr.numberPlan);
481+
dos.write(destAddr.numberOfDigits);
482+
dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
483+
// Subaddress is not supported.
484+
dos.write(0); //subaddressType
485+
dos.write(0); //subaddr_odd
486+
dos.write(0); //subaddr_nbr_of_digits
487+
dos.write(encodedBearerData.length);
488+
dos.write(encodedBearerData, 0, encodedBearerData.length);
489+
// Ignore the RIL response. TODO: implement retry if SMS send fails.
490+
mCm.sendCdmaSms(baos.toByteArray(), null);
491+
} catch (IOException e) {
492+
Log.e(TAG, "exception creating SCP results PDU", e);
493+
} finally {
494+
try {
495+
dos.close();
496+
} catch (IOException ignored) {
497+
}
498+
}
499+
}
500+
};
428501
}

telephony/java/com/android/internal/telephony/cdma/SmsMessage.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.io.DataInputStream;
4343
import java.io.DataOutputStream;
4444
import java.io.IOException;
45+
import java.util.ArrayList;
4546
import java.util.List;
4647

4748
import static android.telephony.SmsMessage.MessageClass;
@@ -781,7 +782,7 @@ public MessageClass getMessageClass() {
781782
* binder-call, and hence should be thread-safe, it has been
782783
* synchronized.
783784
*/
784-
private synchronized static int getNextMessageId() {
785+
synchronized static int getNextMessageId() {
785786
// Testing and dialog with partners has indicated that
786787
// msgId==0 is (sometimes?) treated specially by lower levels.
787788
// Specifically, the ID is not preserved for delivery ACKs.
@@ -997,7 +998,7 @@ private byte convertDtmfToAscii(byte dtmfDigit) {
997998
* Returns the list of service category program data, if present.
998999
* @return a list of CdmaSmsCbProgramData objects, or null if not present
9991000
*/
1000-
List<CdmaSmsCbProgramData> getSmsCbProgramData() {
1001+
ArrayList<CdmaSmsCbProgramData> getSmsCbProgramData() {
10011002
return mBearerData.serviceCategoryProgramData;
10021003
}
10031004
}

0 commit comments

Comments
 (0)