Merge "resolved conflicts for merge of 0cb17a52
to honeycomb-plus-aosp" into honeycomb-plus-aosp
This commit is contained in:
@ -542,7 +542,7 @@ public final class Telephony {
|
|||||||
* values:</p>
|
* values:</p>
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs
|
* <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
|
||||||
* that make up the message.</li>
|
* that make up the message.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@ -585,6 +585,46 @@ public final class Telephony {
|
|||||||
public static final String WAP_PUSH_RECEIVED_ACTION =
|
public static final String WAP_PUSH_RECEIVED_ACTION =
|
||||||
"android.provider.Telephony.WAP_PUSH_RECEIVED";
|
"android.provider.Telephony.WAP_PUSH_RECEIVED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast Action: A new Cell Broadcast message has been received
|
||||||
|
* by the device. The intent will have the following extra
|
||||||
|
* values:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
|
||||||
|
* that make up the message.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>The extra values can be extracted using
|
||||||
|
* {@link #getMessagesFromIntent(Intent)}.</p>
|
||||||
|
*
|
||||||
|
* <p>If a BroadcastReceiver encounters an error while processing
|
||||||
|
* this intent it should set the result code appropriately.</p>
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
|
public static final String SMS_CB_RECEIVED_ACTION =
|
||||||
|
"android.provider.Telephony.SMS_CB_RECEIVED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast Action: A new Emergency Broadcast message has been received
|
||||||
|
* by the device. The intent will have the following extra
|
||||||
|
* values:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
|
||||||
|
* that make up the message.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>The extra values can be extracted using
|
||||||
|
* {@link #getMessagesFromIntent(Intent)}.</p>
|
||||||
|
*
|
||||||
|
* <p>If a BroadcastReceiver encounters an error while processing
|
||||||
|
* this intent it should set the result code appropriately.</p>
|
||||||
|
*/
|
||||||
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
|
public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION =
|
||||||
|
"android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast Action: The SIM storage for SMS messages is full. If
|
* Broadcast Action: The SIM storage for SMS messages is full. If
|
||||||
* space is not freed, messages targeted for the SIM (class 2) may
|
* space is not freed, messages targeted for the SIM (class 2) may
|
||||||
@ -618,7 +658,7 @@ public final class Telephony {
|
|||||||
* @param intent the intent to read from
|
* @param intent the intent to read from
|
||||||
* @return an array of SmsMessages for the PDUs
|
* @return an array of SmsMessages for the PDUs
|
||||||
*/
|
*/
|
||||||
public static final SmsMessage[] getMessagesFromIntent(
|
public static SmsMessage[] getMessagesFromIntent(
|
||||||
Intent intent) {
|
Intent intent) {
|
||||||
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
|
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
|
||||||
byte[][] pduObjs = new byte[messages.length][];
|
byte[][] pduObjs = new byte[messages.length][];
|
||||||
|
@ -159,6 +159,15 @@
|
|||||||
android:label="@string/permlab_receiveMms"
|
android:label="@string/permlab_receiveMms"
|
||||||
android:description="@string/permdesc_receiveMms" />
|
android:description="@string/permdesc_receiveMms" />
|
||||||
|
|
||||||
|
<!-- Allows an application to receive emergency cell broadcast messages,
|
||||||
|
to record or display them to the user. Reserved for system apps.
|
||||||
|
@hide Pending API council approval -->
|
||||||
|
<permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
|
||||||
|
android:permissionGroup="android.permission-group.MESSAGES"
|
||||||
|
android:protectionLevel="signatureOrSystem"
|
||||||
|
android:label="@string/permlab_receiveEmergencyBroadcast"
|
||||||
|
android:description="@string/permdesc_receiveEmergencyBroadcast" />
|
||||||
|
|
||||||
<!-- Allows an application to read SMS messages. -->
|
<!-- Allows an application to read SMS messages. -->
|
||||||
<permission android:name="android.permission.READ_SMS"
|
<permission android:name="android.permission.READ_SMS"
|
||||||
android:permissionGroup="android.permission-group.MESSAGES"
|
android:permissionGroup="android.permission-group.MESSAGES"
|
||||||
|
@ -459,6 +459,13 @@
|
|||||||
your messages or delete them without showing them to you.</string>
|
your messages or delete them without showing them to you.</string>
|
||||||
|
|
||||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
|
<string name="permlab_receiveEmergencyBroadcast">receive emergency broadcasts</string>
|
||||||
|
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
|
<string name="permdesc_receiveEmergencyBroadcast">Allows application to receive
|
||||||
|
and process emergency broadcast messages. This permission is only available
|
||||||
|
to system applications.</string>
|
||||||
|
|
||||||
|
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
<string name="permlab_sendSms">send SMS messages</string>
|
<string name="permlab_sendSms">send SMS messages</string>
|
||||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||||
<string name="permdesc_sendSms">Allows application to send SMS
|
<string name="permdesc_sendSms">Allows application to send SMS
|
||||||
|
114
telephony/java/android/telephony/SmsCbConstants.java
Normal file
114
telephony/java/android/telephony/SmsCbConstants.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.telephony;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constants used in SMS Cell Broadcast messages.
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
public interface SmsCbConstants {
|
||||||
|
/** Cell wide immediate geographical scope */
|
||||||
|
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
|
||||||
|
|
||||||
|
/** PLMN wide geographical scope */
|
||||||
|
public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
|
||||||
|
|
||||||
|
/** Location / service area wide geographical scope */
|
||||||
|
public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
|
||||||
|
|
||||||
|
/** Cell wide geographical scope */
|
||||||
|
public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
|
||||||
|
|
||||||
|
/** Start of PWS Message Identifier range (includes ETWS and CMAS). */
|
||||||
|
public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER = 0x1100;
|
||||||
|
|
||||||
|
/** Bitmask for messages of ETWS type (including future extensions). */
|
||||||
|
public static final int MESSAGE_ID_ETWS_TYPE_MASK = 0xFFF8;
|
||||||
|
|
||||||
|
/** Value for messages of ETWS type after applying {@link #MESSAGE_ID_ETWS_TYPE_MASK}. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_TYPE = 0x1100;
|
||||||
|
|
||||||
|
/** ETWS Message Identifier for earthquake warning message. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_EARTHQUAKE_WARNING = 0x1100;
|
||||||
|
|
||||||
|
/** ETWS Message Identifier for tsunami warning message. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_TSUNAMI_WARNING = 0x1101;
|
||||||
|
|
||||||
|
/** ETWS Message Identifier for earthquake and tsunami combined warning message. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING = 0x1102;
|
||||||
|
|
||||||
|
/** ETWS Message Identifier for test message. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_TEST_MESSAGE = 0x1103;
|
||||||
|
|
||||||
|
/** ETWS Message Identifier for messages related to other emergency types. */
|
||||||
|
public static final int MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE = 0x1104;
|
||||||
|
|
||||||
|
/** Start of CMAS Message Identifier range. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_FIRST_IDENTIFIER = 0x1112;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Presidential Level alerts. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL = 0x1112;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED = 0x1113;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY = 0x1114;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED = 0x1115;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY = 0x1116;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED = 0x1117;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY = 0x1118;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED = 0x1119;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY = 0x111A;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for Child Abduction Emergency (Amber Alert). */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY = 0x111B;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for the Required Monthly Test. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST = 0x111C;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for CMAS Exercise. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE = 0x111D;
|
||||||
|
|
||||||
|
/** CMAS Message Identifier for operator defined use. */
|
||||||
|
public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE = 0x111E;
|
||||||
|
|
||||||
|
/** End of CMAS Message Identifier range (including future extensions). */
|
||||||
|
public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER = 0x112F;
|
||||||
|
|
||||||
|
/** End of PWS Message Identifier range (includes ETWS, CMAS, and future extensions). */
|
||||||
|
public static final int MESSAGE_ID_PWS_LAST_IDENTIFIER = 0x18FF;
|
||||||
|
|
||||||
|
/** ETWS message code flag to activate the popup display. */
|
||||||
|
public static final int MESSAGE_CODE_ETWS_ACTIVATE_POPUP = 0x100;
|
||||||
|
|
||||||
|
/** ETWS message code flag to activate the emergency user alert. */
|
||||||
|
public static final int MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT = 0x200;
|
||||||
|
}
|
@ -333,4 +333,10 @@ public class SmsCbMessage {
|
|||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SmsCbMessage{" + mHeader.toString() + ", language=" + mLanguage +
|
||||||
|
", body=\"" + mBody + "\"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ public final class SmsManager {
|
|||||||
* message identifier. Note that if two different clients enable the same
|
* message identifier. Note that if two different clients enable the same
|
||||||
* message identifier, they must both disable it for the device to stop
|
* message identifier, they must both disable it for the device to stop
|
||||||
* receiving those messages. All received messages will be broadcast in an
|
* receiving those messages. All received messages will be broadcast in an
|
||||||
* intent with the action "android.provider.telephony.SMS_CB_RECEIVED".
|
* intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
|
||||||
* Note: This call is blocking, callers may want to avoid calling it from
|
* Note: This call is blocking, callers may want to avoid calling it from
|
||||||
* the main thread of an application.
|
* the main thread of an application.
|
||||||
*
|
*
|
||||||
@ -400,6 +400,68 @@ public final class SmsManager {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable reception of cell broadcast (SMS-CB) messages with the given
|
||||||
|
* message identifier range. Note that if two different clients enable the same
|
||||||
|
* message identifier, they must both disable it for the device to stop
|
||||||
|
* receiving those messages. All received messages will be broadcast in an
|
||||||
|
* intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
|
||||||
|
* Note: This call is blocking, callers may want to avoid calling it from
|
||||||
|
* the main thread of an application.
|
||||||
|
*
|
||||||
|
* @param startMessageId first message identifier as specified in TS 23.041
|
||||||
|
* @param endMessageId last message identifier as specified in TS 23.041
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
* @see #disableCellBroadcastRange(int, int)
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||||
|
if (iccISms != null) {
|
||||||
|
success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId);
|
||||||
|
}
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
// ignore it
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable reception of cell broadcast (SMS-CB) messages with the given
|
||||||
|
* message identifier range. Note that if two different clients enable the same
|
||||||
|
* message identifier, they must both disable it for the device to stop
|
||||||
|
* receiving those messages.
|
||||||
|
* Note: This call is blocking, callers may want to avoid calling it from
|
||||||
|
* the main thread of an application.
|
||||||
|
*
|
||||||
|
* @param startMessageId first message identifier as specified in TS 23.041
|
||||||
|
* @param endMessageId last message identifier as specified in TS 23.041
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*
|
||||||
|
* @see #enableCellBroadcastRange(int, int)
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||||
|
if (iccISms != null) {
|
||||||
|
success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId);
|
||||||
|
}
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
// ignore it
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a list of <code>SmsMessage</code>s from a list of RawSmsData
|
* Create a list of <code>SmsMessage</code>s from a list of RawSmsData
|
||||||
* records returned by <code>getAllMessagesFromIcc()</code>
|
* records returned by <code>getAllMessagesFromIcc()</code>
|
||||||
|
@ -86,6 +86,8 @@ public class GsmAlphabet {
|
|||||||
* GSM_EXTENDED_ESCAPE if this character is in the extended table.
|
* GSM_EXTENDED_ESCAPE if this character is in the extended table.
|
||||||
* In this case, you must call charToGsmExtended() for the value
|
* In this case, you must call charToGsmExtended() for the value
|
||||||
* that should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string.
|
* that should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string.
|
||||||
|
* @param c the character to convert
|
||||||
|
* @return the GSM 7 bit table index for the specified character
|
||||||
*/
|
*/
|
||||||
public static int
|
public static int
|
||||||
charToGsm(char c) {
|
charToGsm(char c) {
|
||||||
@ -99,12 +101,15 @@ public class GsmAlphabet {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a char to a GSM 7 bit table index.
|
* Converts a char to a GSM 7 bit table index.
|
||||||
|
* Returns GSM_EXTENDED_ESCAPE if this character is in the extended table.
|
||||||
|
* In this case, you must call charToGsmExtended() for the value that
|
||||||
|
* should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string.
|
||||||
|
*
|
||||||
|
* @param c the character to convert
|
||||||
* @param throwException If true, throws EncodeException on invalid char.
|
* @param throwException If true, throws EncodeException on invalid char.
|
||||||
* If false, returns GSM alphabet ' ' char.
|
* If false, returns GSM alphabet ' ' char.
|
||||||
*
|
* @throws EncodeException encode error when throwException is true
|
||||||
* Returns GSM_EXTENDED_ESCAPE if this character is in the extended table
|
* @return the GSM 7 bit table index for the specified character
|
||||||
* In this case, you must call charToGsmExtended() for the value that
|
|
||||||
* should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string
|
|
||||||
*/
|
*/
|
||||||
public static int
|
public static int
|
||||||
charToGsm(char c, boolean throwException) throws EncodeException {
|
charToGsm(char c, boolean throwException) throws EncodeException {
|
||||||
@ -133,6 +138,8 @@ public class GsmAlphabet {
|
|||||||
* Converts a char to an extended GSM 7 bit table index.
|
* Converts a char to an extended GSM 7 bit table index.
|
||||||
* Extended chars should be escaped with GSM_EXTENDED_ESCAPE.
|
* Extended chars should be escaped with GSM_EXTENDED_ESCAPE.
|
||||||
* Returns ' ' in GSM alphabet if there's no possible match.
|
* Returns ' ' in GSM alphabet if there's no possible match.
|
||||||
|
* @param c the character to convert
|
||||||
|
* @return the GSM 7 bit extended table index for the specified character
|
||||||
*/
|
*/
|
||||||
public static int
|
public static int
|
||||||
charToGsmExtended(char c) {
|
charToGsmExtended(char c) {
|
||||||
@ -155,6 +162,9 @@ public class GsmAlphabet {
|
|||||||
* gsmExtendedToChar().
|
* gsmExtendedToChar().
|
||||||
*
|
*
|
||||||
* If an unmappable value is passed (one greater than 127), ' ' is returned.
|
* If an unmappable value is passed (one greater than 127), ' ' is returned.
|
||||||
|
*
|
||||||
|
* @param gsmChar the GSM 7 bit table index to convert
|
||||||
|
* @return the decoded character
|
||||||
*/
|
*/
|
||||||
public static char
|
public static char
|
||||||
gsmToChar(int gsmChar) {
|
gsmToChar(int gsmChar) {
|
||||||
@ -174,6 +184,9 @@ public class GsmAlphabet {
|
|||||||
*
|
*
|
||||||
* If an unmappable value is passed, the character from the GSM 7 bit
|
* If an unmappable value is passed, the character from the GSM 7 bit
|
||||||
* default table will be used (table 6.2.1.1 of TS 23.038).
|
* default table will be used (table 6.2.1.1 of TS 23.038).
|
||||||
|
*
|
||||||
|
* @param gsmChar the GSM 7 bit extended table index to convert
|
||||||
|
* @return the decoded character
|
||||||
*/
|
*/
|
||||||
public static char
|
public static char
|
||||||
gsmExtendedToChar(int gsmChar) {
|
gsmExtendedToChar(int gsmChar) {
|
||||||
@ -232,6 +245,26 @@ public class GsmAlphabet {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a String into a byte array containing
|
||||||
|
* the 7-bit packed GSM Alphabet representation of the string.
|
||||||
|
*
|
||||||
|
* Unencodable chars are encoded as spaces
|
||||||
|
*
|
||||||
|
* Byte 0 in the returned byte array is the count of septets used
|
||||||
|
* The returned byte array is the minimum size required to store
|
||||||
|
* the packed septets. The returned array cannot contain more than 255
|
||||||
|
* septets.
|
||||||
|
*
|
||||||
|
* @param data the data string to encode
|
||||||
|
* @return the encoded string
|
||||||
|
* @throws EncodeException if String is too large to encode
|
||||||
|
*/
|
||||||
|
public static byte[] stringToGsm7BitPacked(String data)
|
||||||
|
throws EncodeException {
|
||||||
|
return stringToGsm7BitPacked(data, 0, true, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a String into a byte array containing
|
* Converts a String into a byte array containing
|
||||||
* the 7-bit packed GSM Alphabet representation of the string.
|
* the 7-bit packed GSM Alphabet representation of the string.
|
||||||
@ -449,6 +482,11 @@ public class GsmAlphabet {
|
|||||||
*
|
*
|
||||||
* Field may be padded with trailing 0xff's. The decode stops
|
* Field may be padded with trailing 0xff's. The decode stops
|
||||||
* at the first 0xff encountered.
|
* at the first 0xff encountered.
|
||||||
|
*
|
||||||
|
* @param data the byte array to decode
|
||||||
|
* @param offset array offset for the first character to decode
|
||||||
|
* @param length the number of bytes to decode
|
||||||
|
* @return the decoded string
|
||||||
*/
|
*/
|
||||||
public static String
|
public static String
|
||||||
gsm8BitUnpackedToString(byte[] data, int offset, int length) {
|
gsm8BitUnpackedToString(byte[] data, int offset, int length) {
|
||||||
@ -532,6 +570,8 @@ public class GsmAlphabet {
|
|||||||
/**
|
/**
|
||||||
* Convert a string into an 8-bit unpacked GSM alphabet byte array.
|
* Convert a string into an 8-bit unpacked GSM alphabet byte array.
|
||||||
* Always uses GSM default 7-bit alphabet and extension table.
|
* Always uses GSM default 7-bit alphabet and extension table.
|
||||||
|
* @param s the string to encode
|
||||||
|
* @return the 8-bit GSM encoded byte array for the string
|
||||||
*/
|
*/
|
||||||
public static byte[]
|
public static byte[]
|
||||||
stringToGsm8BitPacked(String s) {
|
stringToGsm8BitPacked(String s) {
|
||||||
@ -550,11 +590,13 @@ public class GsmAlphabet {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a String into a GSM 8-bit unpacked field of
|
* Write a String into a GSM 8-bit unpacked field of
|
||||||
* @param length size at @param offset in @param dest
|
|
||||||
*
|
|
||||||
* Field is padded with 0xff's, string is truncated if necessary
|
* Field is padded with 0xff's, string is truncated if necessary
|
||||||
|
*
|
||||||
|
* @param s the string to encode
|
||||||
|
* @param dest the destination byte array
|
||||||
|
* @param offset the starting offset for the encoded string
|
||||||
|
* @param length the maximum number of bytes to write
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void
|
public static void
|
||||||
stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) {
|
stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) {
|
||||||
int outByteIndex = offset;
|
int outByteIndex = offset;
|
||||||
@ -596,6 +638,8 @@ public class GsmAlphabet {
|
|||||||
/**
|
/**
|
||||||
* Returns the count of 7-bit GSM alphabet characters
|
* Returns the count of 7-bit GSM alphabet characters
|
||||||
* needed to represent this character. Counts unencodable char as 1 septet.
|
* needed to represent this character. Counts unencodable char as 1 septet.
|
||||||
|
* @param c the character to examine
|
||||||
|
* @return the number of septets for this character
|
||||||
*/
|
*/
|
||||||
public static int
|
public static int
|
||||||
countGsmSeptets(char c) {
|
countGsmSeptets(char c) {
|
||||||
@ -610,8 +654,11 @@ public class GsmAlphabet {
|
|||||||
/**
|
/**
|
||||||
* Returns the count of 7-bit GSM alphabet characters
|
* Returns the count of 7-bit GSM alphabet characters
|
||||||
* needed to represent this character using the default 7 bit GSM alphabet.
|
* needed to represent this character using the default 7 bit GSM alphabet.
|
||||||
|
* @param c the character to examine
|
||||||
* @param throwsException If true, throws EncodeException if unencodable
|
* @param throwsException If true, throws EncodeException if unencodable
|
||||||
* char. Otherwise, counts invalid char as 1 septet
|
* char. Otherwise, counts invalid char as 1 septet.
|
||||||
|
* @return the number of septets for this character
|
||||||
|
* @throws EncodeException the character can't be encoded and throwsException is true
|
||||||
*/
|
*/
|
||||||
public static int
|
public static int
|
||||||
countGsmSeptets(char c, boolean throwsException) throws EncodeException {
|
countGsmSeptets(char c, boolean throwsException) throws EncodeException {
|
||||||
|
@ -170,4 +170,32 @@ interface ISms {
|
|||||||
*/
|
*/
|
||||||
boolean disableCellBroadcast(int messageIdentifier);
|
boolean disableCellBroadcast(int messageIdentifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable reception of cell broadcast (SMS-CB) messages with the given
|
||||||
|
* message identifier range. Note that if two different clients enable
|
||||||
|
* a message identifier range, they must both disable it for the device
|
||||||
|
* to stop receiving those messages.
|
||||||
|
*
|
||||||
|
* @param startMessageId first message identifier as specified in TS 23.041
|
||||||
|
* @param endMessageId last message identifier as specified in TS 23.041
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*
|
||||||
|
* @see #disableCellBroadcastRange(int, int)
|
||||||
|
*/
|
||||||
|
boolean enableCellBroadcastRange(int startMessageId, int endMessageId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable reception of cell broadcast (SMS-CB) messages with the given
|
||||||
|
* message identifier range. Note that if two different clients enable
|
||||||
|
* a message identifier range, they must both disable it for the device
|
||||||
|
* to stop receiving those messages.
|
||||||
|
*
|
||||||
|
* @param startMessageId first message identifier as specified in TS 23.041
|
||||||
|
* @param endMessageId last message identifier as specified in TS 23.041
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*
|
||||||
|
* @see #enableCellBroadcastRange(int, int)
|
||||||
|
*/
|
||||||
|
boolean disableCellBroadcastRange(int startMessageId, int endMessageId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,4 +76,13 @@ public class IccSmsInterfaceManagerProxy extends ISms.Stub {
|
|||||||
return mIccSmsInterfaceManager.disableCellBroadcast(messageIdentifier);
|
return mIccSmsInterfaceManager.disableCellBroadcast(messageIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean enableCellBroadcastRange(int startMessageId, int endMessageId)
|
||||||
|
throws android.os.RemoteException {
|
||||||
|
return mIccSmsInterfaceManager.enableCellBroadcastRange(startMessageId, endMessageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean disableCellBroadcastRange(int startMessageId, int endMessageId)
|
||||||
|
throws android.os.RemoteException {
|
||||||
|
return mIccSmsInterfaceManager.disableCellBroadcastRange(startMessageId, endMessageId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,560 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.telephony;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clients can enable reception of SMS-CB messages for specific ranges of
|
||||||
|
* message identifiers (channels). This class keeps track of the currently
|
||||||
|
* enabled message identifiers and calls abstract methods to update the
|
||||||
|
* radio when the range of enabled message identifiers changes.
|
||||||
|
*
|
||||||
|
* An update is a call to {@link #startUpdate} followed by zero or more
|
||||||
|
* calls to {@link #addRange} followed by a call to {@link #finishUpdate}.
|
||||||
|
* Calls to {@link #enableRange} and {@link #disableRange} will perform
|
||||||
|
* an incremental update operation if the enabled ranges have changed.
|
||||||
|
* A full update operation (i.e. after a radio reset) can be performed
|
||||||
|
* by a call to {@link #updateRanges}.
|
||||||
|
*
|
||||||
|
* Clients are identified by String (the name associated with the User ID
|
||||||
|
* of the caller) so that a call to remove a range can be mapped to the
|
||||||
|
* client that enabled that range (or else rejected).
|
||||||
|
*/
|
||||||
|
public abstract class IntRangeManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial capacity for IntRange clients array list. There will be
|
||||||
|
* few cell broadcast listeners on a typical device, so this can be small.
|
||||||
|
*/
|
||||||
|
private static final int INITIAL_CLIENTS_ARRAY_SIZE = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more clients forming the continuous range [startId, endId].
|
||||||
|
* <p>When a client is added, the IntRange may merge with one or more
|
||||||
|
* adjacent IntRanges to form a single combined IntRange.
|
||||||
|
* <p>When a client is removed, the IntRange may divide into several
|
||||||
|
* non-contiguous IntRanges.
|
||||||
|
*/
|
||||||
|
private class IntRange {
|
||||||
|
int startId;
|
||||||
|
int endId;
|
||||||
|
// sorted by earliest start id
|
||||||
|
final ArrayList<ClientRange> clients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IntRange with a single client.
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
* @param client the client requesting the enabled range
|
||||||
|
*/
|
||||||
|
IntRange(int startId, int endId, String client) {
|
||||||
|
this.startId = startId;
|
||||||
|
this.endId = endId;
|
||||||
|
clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE);
|
||||||
|
clients.add(new ClientRange(startId, endId, client));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IntRange for an existing ClientRange.
|
||||||
|
* @param clientRange the initial ClientRange to add
|
||||||
|
*/
|
||||||
|
IntRange(ClientRange clientRange) {
|
||||||
|
startId = clientRange.startId;
|
||||||
|
endId = clientRange.endId;
|
||||||
|
clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE);
|
||||||
|
clients.add(clientRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IntRange from an existing IntRange. This is used for
|
||||||
|
* removing a ClientRange, because new IntRanges may need to be created
|
||||||
|
* for any gaps that open up after the ClientRange is removed. A copy
|
||||||
|
* is made of the elements of the original IntRange preceding the element
|
||||||
|
* that is being removed. The following elements will be added to this
|
||||||
|
* IntRange or to a new IntRange when a gap is found.
|
||||||
|
* @param intRange the original IntRange to copy elements from
|
||||||
|
* @param numElements the number of elements to copy from the original
|
||||||
|
*/
|
||||||
|
IntRange(IntRange intRange, int numElements) {
|
||||||
|
this.startId = intRange.startId;
|
||||||
|
this.endId = intRange.endId;
|
||||||
|
this.clients = new ArrayList<ClientRange>(intRange.clients.size());
|
||||||
|
for (int i=0; i < numElements; i++) {
|
||||||
|
this.clients.add(intRange.clients.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert new ClientRange in order by start id.
|
||||||
|
* <p>If the new ClientRange is known to be sorted before or after the
|
||||||
|
* existing ClientRanges, or at a particular index, it can be added
|
||||||
|
* to the clients array list directly, instead of via this method.
|
||||||
|
* <p>Note that this can be changed from linear to binary search if the
|
||||||
|
* number of clients grows large enough that it would make a difference.
|
||||||
|
* @param range the new ClientRange to insert
|
||||||
|
*/
|
||||||
|
void insert(ClientRange range) {
|
||||||
|
int len = clients.size();
|
||||||
|
for (int i=0; i < len; i++) {
|
||||||
|
ClientRange nextRange = clients.get(i);
|
||||||
|
if (range.startId <= nextRange.startId) {
|
||||||
|
// ignore duplicate ranges from the same client
|
||||||
|
if (!range.equals(nextRange)) {
|
||||||
|
clients.add(i, range);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clients.add(range); // append to end of list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message id range for a single client.
|
||||||
|
*/
|
||||||
|
private class ClientRange {
|
||||||
|
final int startId;
|
||||||
|
final int endId;
|
||||||
|
final String client;
|
||||||
|
|
||||||
|
ClientRange(int startId, int endId, String client) {
|
||||||
|
this.startId = startId;
|
||||||
|
this.endId = endId;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o != null && o instanceof ClientRange) {
|
||||||
|
ClientRange other = (ClientRange) o;
|
||||||
|
return startId == other.startId &&
|
||||||
|
endId == other.endId &&
|
||||||
|
client.equals(other.client);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (startId * 31 + endId) * 31 + client.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of integer ranges, one per client, sorted by start id.
|
||||||
|
*/
|
||||||
|
private ArrayList<IntRange> mRanges = new ArrayList<IntRange>();
|
||||||
|
|
||||||
|
protected IntRangeManager() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable a range for the specified client and update ranges
|
||||||
|
* if necessary. If {@link #finishUpdate} returns failure,
|
||||||
|
* false is returned and the range is not added.
|
||||||
|
*
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
* @param client the client requesting the enabled range
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
public synchronized boolean enableRange(int startId, int endId, String client) {
|
||||||
|
int len = mRanges.size();
|
||||||
|
|
||||||
|
// empty range list: add the initial IntRange
|
||||||
|
if (len == 0) {
|
||||||
|
if (tryAddSingleRange(startId, endId, true)) {
|
||||||
|
mRanges.add(new IntRange(startId, endId, client));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int startIndex = 0; startIndex < len; startIndex++) {
|
||||||
|
IntRange range = mRanges.get(startIndex);
|
||||||
|
if (startId < range.startId) {
|
||||||
|
// test if new range completely precedes this range
|
||||||
|
// note that [1, 4] and [5, 6] coalesce to [1, 6]
|
||||||
|
if ((endId + 1) < range.startId) {
|
||||||
|
// insert new int range before previous first range
|
||||||
|
if (tryAddSingleRange(startId, endId, true)) {
|
||||||
|
mRanges.add(startIndex, new IntRange(startId, endId, client));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
} else if (endId <= range.endId) {
|
||||||
|
// extend the start of this range
|
||||||
|
if (tryAddSingleRange(startId, range.startId - 1, true)) {
|
||||||
|
range.startId = startId;
|
||||||
|
range.clients.add(0, new ClientRange(startId, endId, client));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// find last range that can coalesce into the new combined range
|
||||||
|
for (int endIndex = startIndex+1; endIndex < len; endIndex++) {
|
||||||
|
IntRange endRange = mRanges.get(endIndex);
|
||||||
|
if ((endId + 1) < endRange.startId) {
|
||||||
|
// try to add entire new range
|
||||||
|
if (tryAddSingleRange(startId, endId, true)) {
|
||||||
|
range.startId = startId;
|
||||||
|
range.endId = endId;
|
||||||
|
// insert new ClientRange before existing ranges
|
||||||
|
range.clients.add(0, new ClientRange(startId, endId, client));
|
||||||
|
// coalesce range with following ranges up to endIndex-1
|
||||||
|
// remove each range after adding its elements, so the index
|
||||||
|
// of the next range to join is always startIndex+1.
|
||||||
|
// i is the index if no elements were removed: we only care
|
||||||
|
// about the number of loop iterations, not the value of i.
|
||||||
|
int joinIndex = startIndex + 1;
|
||||||
|
for (int i = joinIndex; i < endIndex; i++) {
|
||||||
|
IntRange joinRange = mRanges.get(joinIndex);
|
||||||
|
range.clients.addAll(joinRange.clients);
|
||||||
|
mRanges.remove(joinRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
} else if (endId <= endRange.endId) {
|
||||||
|
// add range from start id to start of last overlapping range,
|
||||||
|
// values from endRange.startId to endId are already enabled
|
||||||
|
if (tryAddSingleRange(startId, endRange.startId - 1, true)) {
|
||||||
|
range.startId = startId;
|
||||||
|
range.endId = endRange.endId;
|
||||||
|
// insert new ClientRange before existing ranges
|
||||||
|
range.clients.add(0, new ClientRange(startId, endId, client));
|
||||||
|
// coalesce range with following ranges up to endIndex
|
||||||
|
// remove each range after adding its elements, so the index
|
||||||
|
// of the next range to join is always startIndex+1.
|
||||||
|
// i is the index if no elements were removed: we only care
|
||||||
|
// about the number of loop iterations, not the value of i.
|
||||||
|
int joinIndex = startIndex + 1;
|
||||||
|
for (int i = joinIndex; i <= endIndex; i++) {
|
||||||
|
IntRange joinRange = mRanges.get(joinIndex);
|
||||||
|
range.clients.addAll(joinRange.clients);
|
||||||
|
mRanges.remove(joinRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endId extends past all existing IntRanges: combine them all together
|
||||||
|
if (tryAddSingleRange(startId, endId, true)) {
|
||||||
|
range.startId = startId;
|
||||||
|
range.endId = endId;
|
||||||
|
// insert new ClientRange before existing ranges
|
||||||
|
range.clients.add(0, new ClientRange(startId, endId, client));
|
||||||
|
// coalesce range with following ranges up to len-1
|
||||||
|
// remove each range after adding its elements, so the index
|
||||||
|
// of the next range to join is always startIndex+1.
|
||||||
|
// i is the index if no elements were removed: we only care
|
||||||
|
// about the number of loop iterations, not the value of i.
|
||||||
|
int joinIndex = startIndex + 1;
|
||||||
|
for (int i = joinIndex; i < len; i++) {
|
||||||
|
IntRange joinRange = mRanges.get(joinIndex);
|
||||||
|
range.clients.addAll(joinRange.clients);
|
||||||
|
mRanges.remove(joinRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((startId + 1) <= range.endId) {
|
||||||
|
if (endId <= range.endId) {
|
||||||
|
// completely contained in existing range; no radio changes
|
||||||
|
range.insert(new ClientRange(startId, endId, client));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// find last range that can coalesce into the new combined range
|
||||||
|
for (int endIndex = startIndex+1; endIndex < len; endIndex++) {
|
||||||
|
IntRange endRange = mRanges.get(endIndex);
|
||||||
|
if ((endId + 1) < endRange.startId) {
|
||||||
|
// add range from range.endId+1 to endId,
|
||||||
|
// values from startId to range.endId are already enabled
|
||||||
|
if (tryAddSingleRange(range.endId + 1, endId, true)) {
|
||||||
|
range.endId = endId;
|
||||||
|
// insert new ClientRange in place
|
||||||
|
range.insert(new ClientRange(startId, endId, client));
|
||||||
|
// coalesce range with following ranges up to endIndex-1
|
||||||
|
// remove each range after adding its elements, so the index
|
||||||
|
// of the next range to join is always startIndex+1.
|
||||||
|
// i is the index if no elements were removed: we only care
|
||||||
|
// about the number of loop iterations, not the value of i.
|
||||||
|
int joinIndex = startIndex + 1;
|
||||||
|
for (int i = joinIndex; i < endIndex; i++) {
|
||||||
|
IntRange joinRange = mRanges.get(joinIndex);
|
||||||
|
range.clients.addAll(joinRange.clients);
|
||||||
|
mRanges.remove(joinRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
} else if (endId <= endRange.endId) {
|
||||||
|
// add range from range.endId+1 to start of last overlapping range,
|
||||||
|
// values from endRange.startId to endId are already enabled
|
||||||
|
if (tryAddSingleRange(range.endId + 1, endRange.startId - 1, true)) {
|
||||||
|
range.endId = endRange.endId;
|
||||||
|
// insert new ClientRange in place
|
||||||
|
range.insert(new ClientRange(startId, endId, client));
|
||||||
|
// coalesce range with following ranges up to endIndex
|
||||||
|
// remove each range after adding its elements, so the index
|
||||||
|
// of the next range to join is always startIndex+1.
|
||||||
|
// i is the index if no elements were removed: we only care
|
||||||
|
// about the number of loop iterations, not the value of i.
|
||||||
|
int joinIndex = startIndex + 1;
|
||||||
|
for (int i = joinIndex; i <= endIndex; i++) {
|
||||||
|
IntRange joinRange = mRanges.get(joinIndex);
|
||||||
|
range.clients.addAll(joinRange.clients);
|
||||||
|
mRanges.remove(joinRange);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// append new range after existing IntRanges
|
||||||
|
if (tryAddSingleRange(startId, endId, true)) {
|
||||||
|
mRanges.add(new IntRange(startId, endId, client));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable a range for the specified client and update ranges
|
||||||
|
* if necessary. If {@link #finishUpdate} returns failure,
|
||||||
|
* false is returned and the range is not removed.
|
||||||
|
*
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
* @param client the client requesting to disable the range
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
public synchronized boolean disableRange(int startId, int endId, String client) {
|
||||||
|
int len = mRanges.size();
|
||||||
|
|
||||||
|
for (int i=0; i < len; i++) {
|
||||||
|
IntRange range = mRanges.get(i);
|
||||||
|
if (startId < range.startId) {
|
||||||
|
return false; // not found
|
||||||
|
} else if (endId <= range.endId) {
|
||||||
|
// found the IntRange that encloses the client range, if any
|
||||||
|
// search for it in the clients list
|
||||||
|
ArrayList<ClientRange> clients = range.clients;
|
||||||
|
|
||||||
|
// handle common case of IntRange containing one ClientRange
|
||||||
|
int crLength = clients.size();
|
||||||
|
if (crLength == 1) {
|
||||||
|
ClientRange cr = clients.get(0);
|
||||||
|
if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) {
|
||||||
|
// disable range in radio then remove the entire IntRange
|
||||||
|
if (tryAddSingleRange(startId, endId, false)) {
|
||||||
|
mRanges.remove(i);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false; // failed to update radio
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false; // not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// several ClientRanges: remove one, potentially splitting into many IntRanges.
|
||||||
|
// Save the original start and end id for the original IntRange
|
||||||
|
// in case the radio update fails and we have to revert it. If the
|
||||||
|
// update succeeds, we remove the client range and insert the new IntRanges.
|
||||||
|
int largestEndId = Integer.MIN_VALUE; // largest end identifier found
|
||||||
|
boolean updateStarted = false;
|
||||||
|
|
||||||
|
for (int crIndex=0; crIndex < crLength; crIndex++) {
|
||||||
|
ClientRange cr = clients.get(crIndex);
|
||||||
|
if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) {
|
||||||
|
// found the ClientRange to remove, check if it's the last in the list
|
||||||
|
if (crIndex == crLength - 1) {
|
||||||
|
if (range.endId == largestEndId) {
|
||||||
|
// no channels to remove from radio; return success
|
||||||
|
clients.remove(crIndex);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// disable the channels at the end and lower the end id
|
||||||
|
if (tryAddSingleRange(largestEndId + 1, range.endId, false)) {
|
||||||
|
clients.remove(crIndex);
|
||||||
|
range.endId = largestEndId;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the IntRange so that we can remove elements and modify the
|
||||||
|
// start and end id's in the copy, leaving the original unmodified
|
||||||
|
// until after the radio update succeeds
|
||||||
|
IntRange rangeCopy = new IntRange(range, crIndex);
|
||||||
|
|
||||||
|
if (crIndex == 0) {
|
||||||
|
// removing the first ClientRange, so we may need to increase
|
||||||
|
// the start id of the IntRange.
|
||||||
|
// We know there are at least two ClientRanges in the list,
|
||||||
|
// so clients.get(1) should always succeed.
|
||||||
|
int nextStartId = clients.get(1).startId;
|
||||||
|
if (nextStartId != range.startId) {
|
||||||
|
startUpdate();
|
||||||
|
updateStarted = true;
|
||||||
|
addRange(range.startId, nextStartId - 1, false);
|
||||||
|
rangeCopy.startId = nextStartId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through remaining ClientRanges, creating new IntRanges when
|
||||||
|
// there is a gap in the sequence. After radio update succeeds,
|
||||||
|
// remove the original IntRange and append newRanges to mRanges.
|
||||||
|
// Otherwise, leave the original IntRange in mRanges and return false.
|
||||||
|
ArrayList<IntRange> newRanges = new ArrayList<IntRange>();
|
||||||
|
newRanges.add(rangeCopy);
|
||||||
|
|
||||||
|
IntRange currentRange = rangeCopy;
|
||||||
|
for (int nextIndex = crIndex + 1; nextIndex < crLength; nextIndex++) {
|
||||||
|
ClientRange nextCr = clients.get(nextIndex);
|
||||||
|
if (nextCr.startId > largestEndId + 1) {
|
||||||
|
if (!updateStarted) {
|
||||||
|
startUpdate();
|
||||||
|
updateStarted = true;
|
||||||
|
}
|
||||||
|
addRange(largestEndId + 1, nextCr.startId - 1, false);
|
||||||
|
currentRange.endId = largestEndId;
|
||||||
|
currentRange = new IntRange(nextCr);
|
||||||
|
} else {
|
||||||
|
currentRange.clients.add(nextCr);
|
||||||
|
}
|
||||||
|
if (nextCr.endId > largestEndId) {
|
||||||
|
largestEndId = nextCr.endId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateStarted) {
|
||||||
|
if (!finishUpdate()) {
|
||||||
|
return false; // failed to update radio
|
||||||
|
} else {
|
||||||
|
// remove the original IntRange and insert newRanges in place.
|
||||||
|
mRanges.remove(crIndex);
|
||||||
|
mRanges.addAll(crIndex, newRanges);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not the ClientRange to remove; save highest end ID seen so far
|
||||||
|
if (cr.endId > largestEndId) {
|
||||||
|
largestEndId = cr.endId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a complete update operation (enable all ranges). Useful
|
||||||
|
* after a radio reset. Calls {@link #startUpdate}, followed by zero or
|
||||||
|
* more calls to {@link #addRange}, followed by {@link #finishUpdate}.
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean updateRanges() {
|
||||||
|
startUpdate();
|
||||||
|
Iterator<IntRange> iterator = mRanges.iterator();
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
IntRange range = iterator.next();
|
||||||
|
int start = range.startId;
|
||||||
|
int end = range.endId;
|
||||||
|
// accumulate ranges of [startId, endId]
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
IntRange nextNode = iterator.next();
|
||||||
|
// [startIdA, endIdA], [endIdA + 1, endIdB] -> [startIdA, endIdB]
|
||||||
|
if (nextNode.startId <= (end + 1)) {
|
||||||
|
if (nextNode.endId > end) {
|
||||||
|
end = nextNode.endId;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addRange(start, end, true);
|
||||||
|
start = nextNode.startId;
|
||||||
|
end = nextNode.endId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add final range
|
||||||
|
addRange(start, end, true);
|
||||||
|
}
|
||||||
|
return finishUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable a single range of message identifiers.
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
* @param selected true to enable range, false to disable range
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean tryAddSingleRange(int startId, int endId, boolean selected) {
|
||||||
|
startUpdate();
|
||||||
|
addRange(startId, endId, selected);
|
||||||
|
return finishUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the list of enabled ranges has changed. This will be
|
||||||
|
* followed by zero or more calls to {@link #addRange} followed by
|
||||||
|
* a call to {@link #finishUpdate}.
|
||||||
|
*/
|
||||||
|
protected abstract void startUpdate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after {@link #startUpdate} to indicate a range of enabled
|
||||||
|
* or disabled values.
|
||||||
|
*
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
* @param selected true to enable range, false to disable range
|
||||||
|
*/
|
||||||
|
protected abstract void addRange(int startId, int endId, boolean selected);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to indicate the end of a range update started by the
|
||||||
|
* previous call to {@link #startUpdate}.
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
protected abstract boolean finishUpdate();
|
||||||
|
}
|
54
telephony/java/com/android/internal/telephony/SMSDispatcher.java
Executable file → Normal file
54
telephony/java/com/android/internal/telephony/SMSDispatcher.java
Executable file → Normal file
@ -32,11 +32,9 @@ import android.database.Cursor;
|
|||||||
import android.database.SQLException;
|
import android.database.SQLException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncResult;
|
import android.os.AsyncResult;
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.StatFs;
|
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.provider.Telephony;
|
import android.provider.Telephony;
|
||||||
import android.provider.Telephony.Sms.Intents;
|
import android.provider.Telephony.Sms.Intents;
|
||||||
@ -908,37 +906,6 @@ public abstract class SMSDispatcher extends Handler {
|
|||||||
*/
|
*/
|
||||||
protected abstract void sendMultipartSms (SmsTracker tracker);
|
protected abstract void sendMultipartSms (SmsTracker tracker);
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate or deactivate cell broadcast SMS.
|
|
||||||
*
|
|
||||||
* @param activate
|
|
||||||
* 0 = activate, 1 = deactivate
|
|
||||||
* @param response
|
|
||||||
* Callback message is empty on completion
|
|
||||||
*/
|
|
||||||
public abstract void activateCellBroadcastSms(int activate, Message response);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query the current configuration of cell broadcast SMS.
|
|
||||||
*
|
|
||||||
* @param response
|
|
||||||
* Callback message contains the configuration from the modem on completion
|
|
||||||
* @see #setCellBroadcastConfig
|
|
||||||
*/
|
|
||||||
public abstract void getCellBroadcastSmsConfig(Message response);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure cell broadcast SMS.
|
|
||||||
*
|
|
||||||
* @param configValuesArray
|
|
||||||
* The first element defines the number of triples that follow.
|
|
||||||
* A triple is made up of the service category, the language identifier
|
|
||||||
* and a boolean that specifies whether the category is set active.
|
|
||||||
* @param response
|
|
||||||
* Callback message is empty on completion
|
|
||||||
*/
|
|
||||||
public abstract void setCellBroadcastConfig(int[] configValuesArray, Message response);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send an acknowledge message.
|
* Send an acknowledge message.
|
||||||
* @param success indicates that last message was successfully received.
|
* @param success indicates that last message was successfully received.
|
||||||
@ -1066,14 +1033,21 @@ public abstract class SMSDispatcher extends Handler {
|
|||||||
|
|
||||||
protected abstract void handleBroadcastSms(AsyncResult ar);
|
protected abstract void handleBroadcastSms(AsyncResult ar);
|
||||||
|
|
||||||
protected void dispatchBroadcastPdus(byte[][] pdus) {
|
protected void dispatchBroadcastPdus(byte[][] pdus, boolean isEmergencyMessage) {
|
||||||
Intent intent = new Intent("android.provider.telephony.SMS_CB_RECEIVED");
|
if (isEmergencyMessage) {
|
||||||
intent.putExtra("pdus", pdus);
|
Intent intent = new Intent(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
|
||||||
|
intent.putExtra("pdus", pdus);
|
||||||
|
if (Config.LOGD)
|
||||||
|
Log.d(TAG, "Dispatching " + pdus.length + " emergency SMS CB pdus");
|
||||||
|
|
||||||
if (Config.LOGD)
|
dispatch(intent, "android.permission.RECEIVE_EMERGENCY_BROADCAST");
|
||||||
Log.d(TAG, "Dispatching " + pdus.length + " SMS CB pdus");
|
} else {
|
||||||
|
Intent intent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
|
||||||
|
intent.putExtra("pdus", pdus);
|
||||||
|
if (Config.LOGD)
|
||||||
|
Log.d(TAG, "Dispatching " + pdus.length + " SMS CB pdus");
|
||||||
|
|
||||||
dispatch(intent, "android.permission.RECEIVE_SMS");
|
dispatch(intent, "android.permission.RECEIVE_SMS");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1121,7 +1121,8 @@ public class CDMAPhone extends PhoneBase {
|
|||||||
* @param response Callback message is empty on completion
|
* @param response Callback message is empty on completion
|
||||||
*/
|
*/
|
||||||
public void activateCellBroadcastSms(int activate, Message response) {
|
public void activateCellBroadcastSms(int activate, Message response) {
|
||||||
mSMS.activateCellBroadcastSms(activate, response);
|
Log.e(LOG_TAG, "[CDMAPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1130,7 +1131,8 @@ public class CDMAPhone extends PhoneBase {
|
|||||||
* @param response Callback message is empty on completion
|
* @param response Callback message is empty on completion
|
||||||
*/
|
*/
|
||||||
public void getCellBroadcastSmsConfig(Message response) {
|
public void getCellBroadcastSmsConfig(Message response) {
|
||||||
mSMS.getCellBroadcastSmsConfig(response);
|
Log.e(LOG_TAG, "[CDMAPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1139,7 +1141,8 @@ public class CDMAPhone extends PhoneBase {
|
|||||||
* @param response Callback message is empty on completion
|
* @param response Callback message is empty on completion
|
||||||
*/
|
*/
|
||||||
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
|
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
|
||||||
mSMS.setCellBroadcastConfig(configValuesArray, response);
|
Log.e(LOG_TAG, "[CDMAPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -274,7 +274,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
|||||||
if (cursorCount != totalSegments - 1) {
|
if (cursorCount != totalSegments - 1) {
|
||||||
// We don't have all the parts yet, store this one away
|
// We don't have all the parts yet, store this one away
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("date", new Long(0));
|
values.put("date", (long) 0);
|
||||||
values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index));
|
values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index));
|
||||||
values.put("address", address);
|
values.put("address", address);
|
||||||
values.put("reference_number", referenceNumber);
|
values.put("reference_number", referenceNumber);
|
||||||
@ -483,24 +483,6 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void activateCellBroadcastSms(int activate, Message response) {
|
|
||||||
mCm.setCdmaBroadcastActivation((activate == 0), response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void getCellBroadcastSmsConfig(Message response) {
|
|
||||||
mCm.getCdmaBroadcastConfig(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void setCellBroadcastConfig(int[] configValuesArray, Message response) {
|
|
||||||
mCm.setCdmaBroadcastConfig(configValuesArray, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void handleBroadcastSms(AsyncResult ar) {
|
protected void handleBroadcastSms(AsyncResult ar) {
|
||||||
// Not supported
|
// Not supported
|
||||||
Log.e(TAG, "Error! Not implemented for CDMA.");
|
Log.e(TAG, "Error! Not implemented for CDMA.");
|
||||||
|
@ -203,6 +203,18 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
|
// Not implemented
|
||||||
|
Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
|
// Not implemented
|
||||||
|
Log.e(LOG_TAG, "Error! Not implemented for CDMA.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected void log(String msg) {
|
protected void log(String msg) {
|
||||||
Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg);
|
Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg);
|
||||||
}
|
}
|
||||||
|
@ -1427,16 +1427,35 @@ public class GSMPhone extends PhoneBase {
|
|||||||
return this.mIccFileHandler;
|
return this.mIccFileHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate or deactivate cell broadcast SMS.
|
||||||
|
*
|
||||||
|
* @param activate 0 = activate, 1 = deactivate
|
||||||
|
* @param response Callback message is empty on completion
|
||||||
|
*/
|
||||||
public void activateCellBroadcastSms(int activate, Message response) {
|
public void activateCellBroadcastSms(int activate, Message response) {
|
||||||
Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
|
Log.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query the current configuration of cdma cell broadcast SMS.
|
||||||
|
*
|
||||||
|
* @param response Callback message is empty on completion
|
||||||
|
*/
|
||||||
public void getCellBroadcastSmsConfig(Message response) {
|
public void getCellBroadcastSmsConfig(Message response) {
|
||||||
Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
|
Log.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
|
/**
|
||||||
Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
|
* Configure cdma cell broadcast SMS.
|
||||||
|
*
|
||||||
|
* @param response Callback message is empty on completion
|
||||||
|
*/
|
||||||
|
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
|
||||||
|
Log.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
|
||||||
|
response.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCspPlmnEnabled() {
|
public boolean isCspPlmnEnabled() {
|
||||||
|
34
telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
Executable file → Normal file
34
telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
Executable file → Normal file
@ -392,30 +392,6 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void activateCellBroadcastSms(int activate, Message response) {
|
|
||||||
// Unless CBS is implemented for GSM, this point should be unreachable.
|
|
||||||
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
|
|
||||||
response.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void getCellBroadcastSmsConfig(Message response){
|
|
||||||
// Unless CBS is implemented for GSM, this point should be unreachable.
|
|
||||||
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
|
|
||||||
response.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public void setCellBroadcastConfig(int[] configValuesArray, Message response) {
|
|
||||||
// Unless CBS is implemented for GSM, this point should be unreachable.
|
|
||||||
Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
|
|
||||||
response.recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int resultToCause(int rc) {
|
private int resultToCause(int rc) {
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case Activity.RESULT_OK:
|
case Activity.RESULT_OK:
|
||||||
@ -507,9 +483,10 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This map holds incomplete concatenated messages waiting for assembly
|
// This map holds incomplete concatenated messages waiting for assembly
|
||||||
private HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
|
private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
|
||||||
new HashMap<SmsCbConcatInfo, byte[][]>();
|
new HashMap<SmsCbConcatInfo, byte[][]>();
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void handleBroadcastSms(AsyncResult ar) {
|
protected void handleBroadcastSms(AsyncResult ar) {
|
||||||
try {
|
try {
|
||||||
byte[][] pdus = null;
|
byte[][] pdus = null;
|
||||||
@ -521,9 +498,9 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
|||||||
for (int j = i; j < i + 8 && j < receivedPdu.length; j++) {
|
for (int j = i; j < i + 8 && j < receivedPdu.length; j++) {
|
||||||
int b = receivedPdu[j] & 0xff;
|
int b = receivedPdu[j] & 0xff;
|
||||||
if (b < 0x10) {
|
if (b < 0x10) {
|
||||||
sb.append("0");
|
sb.append('0');
|
||||||
}
|
}
|
||||||
sb.append(Integer.toHexString(b)).append(" ");
|
sb.append(Integer.toHexString(b)).append(' ');
|
||||||
}
|
}
|
||||||
Log.d(TAG, sb.toString());
|
Log.d(TAG, sb.toString());
|
||||||
}
|
}
|
||||||
@ -568,7 +545,8 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
|||||||
pdus[0] = receivedPdu;
|
pdus[0] = receivedPdu;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchBroadcastPdus(pdus);
|
boolean isEmergencyMessage = SmsCbHeader.isEmergencyMessage(header.messageIdentifier);
|
||||||
|
dispatchBroadcastPdus(pdus, isEmergencyMessage);
|
||||||
|
|
||||||
// Remove messages that are out of scope to prevent the map from
|
// Remove messages that are out of scope to prevent the map from
|
||||||
// growing indefinitely, containing incomplete messages that were
|
// growing indefinitely, containing incomplete messages that were
|
||||||
|
@ -27,6 +27,7 @@ import android.util.Log;
|
|||||||
import com.android.internal.telephony.IccConstants;
|
import com.android.internal.telephony.IccConstants;
|
||||||
import com.android.internal.telephony.IccSmsInterfaceManager;
|
import com.android.internal.telephony.IccSmsInterfaceManager;
|
||||||
import com.android.internal.telephony.IccUtils;
|
import com.android.internal.telephony.IccUtils;
|
||||||
|
import com.android.internal.telephony.IntRangeManager;
|
||||||
import com.android.internal.telephony.SMSDispatcher;
|
import com.android.internal.telephony.SMSDispatcher;
|
||||||
import com.android.internal.telephony.SmsRawData;
|
import com.android.internal.telephony.SmsRawData;
|
||||||
|
|
||||||
@ -53,6 +54,9 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
private HashMap<Integer, HashSet<String>> mCellBroadcastSubscriptions =
|
private HashMap<Integer, HashSet<String>> mCellBroadcastSubscriptions =
|
||||||
new HashMap<Integer, HashSet<String>>();
|
new HashMap<Integer, HashSet<String>>();
|
||||||
|
|
||||||
|
private CellBroadcastRangeManager mCellBroadcastRangeManager =
|
||||||
|
new CellBroadcastRangeManager();
|
||||||
|
|
||||||
private static final int EVENT_LOAD_DONE = 1;
|
private static final int EVENT_LOAD_DONE = 1;
|
||||||
private static final int EVENT_UPDATE_DONE = 2;
|
private static final int EVENT_UPDATE_DONE = 2;
|
||||||
private static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
|
private static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
|
||||||
@ -213,7 +217,15 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean enableCellBroadcast(int messageIdentifier) {
|
public boolean enableCellBroadcast(int messageIdentifier) {
|
||||||
if (DBG) log("enableCellBroadcast");
|
return enableCellBroadcastRange(messageIdentifier, messageIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean disableCellBroadcast(int messageIdentifier) {
|
||||||
|
return disableCellBroadcastRange(messageIdentifier, messageIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
|
if (DBG) log("enableCellBroadcastRange");
|
||||||
|
|
||||||
Context context = mPhone.getContext();
|
Context context = mPhone.getContext();
|
||||||
|
|
||||||
@ -223,30 +235,22 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
|
|
||||||
String client = context.getPackageManager().getNameForUid(
|
String client = context.getPackageManager().getNameForUid(
|
||||||
Binder.getCallingUid());
|
Binder.getCallingUid());
|
||||||
HashSet<String> clients = mCellBroadcastSubscriptions.get(messageIdentifier);
|
|
||||||
|
|
||||||
if (clients == null) {
|
if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
|
||||||
// This is a new message identifier
|
log("Failed to add cell broadcast subscription for MID range " + startMessageId
|
||||||
clients = new HashSet<String>();
|
+ " to " + endMessageId + " from client " + client);
|
||||||
mCellBroadcastSubscriptions.put(messageIdentifier, clients);
|
return false;
|
||||||
|
|
||||||
if (!updateCellBroadcastConfig()) {
|
|
||||||
mCellBroadcastSubscriptions.remove(messageIdentifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clients.add(client);
|
|
||||||
|
|
||||||
if (DBG)
|
if (DBG)
|
||||||
log("Added cell broadcast subscription for MID " + messageIdentifier
|
log("Added cell broadcast subscription for MID range " + startMessageId
|
||||||
+ " from client " + client);
|
+ " to " + endMessageId + " from client " + client);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean disableCellBroadcast(int messageIdentifier) {
|
public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
|
||||||
if (DBG) log("disableCellBroadcast");
|
if (DBG) log("disableCellBroadcastRange");
|
||||||
|
|
||||||
Context context = mPhone.getContext();
|
Context context = mPhone.getContext();
|
||||||
|
|
||||||
@ -256,39 +260,56 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
|
|
||||||
String client = context.getPackageManager().getNameForUid(
|
String client = context.getPackageManager().getNameForUid(
|
||||||
Binder.getCallingUid());
|
Binder.getCallingUid());
|
||||||
HashSet<String> clients = mCellBroadcastSubscriptions.get(messageIdentifier);
|
|
||||||
|
|
||||||
if (clients != null && clients.remove(client)) {
|
if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
|
||||||
if (DBG)
|
log("Failed to remove cell broadcast subscription for MID range " + startMessageId
|
||||||
log("Removed cell broadcast subscription for MID " + messageIdentifier
|
+ " to " + endMessageId + " from client " + client);
|
||||||
+ " from client " + client);
|
return false;
|
||||||
|
|
||||||
if (clients.isEmpty()) {
|
|
||||||
mCellBroadcastSubscriptions.remove(messageIdentifier);
|
|
||||||
updateCellBroadcastConfig();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (DBG)
|
||||||
|
log("Removed cell broadcast subscription for MID range " + startMessageId
|
||||||
|
+ " to " + endMessageId + " from client " + client);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateCellBroadcastConfig() {
|
class CellBroadcastRangeManager extends IntRangeManager {
|
||||||
Set<Integer> messageIdentifiers = mCellBroadcastSubscriptions.keySet();
|
private ArrayList<SmsBroadcastConfigInfo> mConfigList =
|
||||||
|
new ArrayList<SmsBroadcastConfigInfo>();
|
||||||
|
|
||||||
if (messageIdentifiers.size() > 0) {
|
/**
|
||||||
SmsBroadcastConfigInfo[] configs =
|
* Called when the list of enabled ranges has changed. This will be
|
||||||
new SmsBroadcastConfigInfo[messageIdentifiers.size()];
|
* followed by zero or more calls to {@link #addRange} followed by
|
||||||
int i = 0;
|
* a call to {@link #finishUpdate}.
|
||||||
|
*/
|
||||||
|
protected void startUpdate() {
|
||||||
|
mConfigList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
for (int messageIdentifier : messageIdentifiers) {
|
/**
|
||||||
configs[i++] = new SmsBroadcastConfigInfo(messageIdentifier, messageIdentifier,
|
* Called after {@link #startUpdate} to indicate a range of enabled
|
||||||
SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, true);
|
* values.
|
||||||
|
* @param startId the first id included in the range
|
||||||
|
* @param endId the last id included in the range
|
||||||
|
*/
|
||||||
|
protected void addRange(int startId, int endId, boolean selected) {
|
||||||
|
mConfigList.add(new SmsBroadcastConfigInfo(startId, endId,
|
||||||
|
SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to indicate the end of a range update started by the
|
||||||
|
* previous call to {@link #startUpdate}.
|
||||||
|
*/
|
||||||
|
protected boolean finishUpdate() {
|
||||||
|
if (mConfigList.isEmpty()) {
|
||||||
|
return setCellBroadcastActivation(false);
|
||||||
|
} else {
|
||||||
|
SmsBroadcastConfigInfo[] configs =
|
||||||
|
mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
|
||||||
|
return setCellBroadcastConfig(configs) && setCellBroadcastActivation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return setCellBroadcastConfig(configs) && setCellBroadcastActivation(true);
|
|
||||||
} else {
|
|
||||||
return setCellBroadcastActivation(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +335,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
|
|||||||
|
|
||||||
private boolean setCellBroadcastActivation(boolean activate) {
|
private boolean setCellBroadcastActivation(boolean activate) {
|
||||||
if (DBG)
|
if (DBG)
|
||||||
log("Calling setCellBroadcastActivation(" + activate + ")");
|
log("Calling setCellBroadcastActivation(" + activate + ')');
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
|
Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
|
||||||
|
@ -30,11 +30,11 @@ package com.android.internal.telephony.gsm;
|
|||||||
* and 9.4.4.2.3 for UMTS.
|
* and 9.4.4.2.3 for UMTS.
|
||||||
* All other values can be treated as empty CBM data coding scheme.
|
* All other values can be treated as empty CBM data coding scheme.
|
||||||
*
|
*
|
||||||
* selected false means message types specified in <fromServiceId, toServiceId>
|
* selected false means message types specified in {@code <fromServiceId, toServiceId>}
|
||||||
* and <fromCodeScheme, toCodeScheme>are not accepted, while true means accepted.
|
* and {@code <fromCodeScheme, toCodeScheme>} are not accepted, while true means accepted.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SmsBroadcastConfigInfo {
|
public final class SmsBroadcastConfigInfo {
|
||||||
private int fromServiceId;
|
private int fromServiceId;
|
||||||
private int toServiceId;
|
private int toServiceId;
|
||||||
private int fromCodeScheme;
|
private int fromCodeScheme;
|
||||||
@ -46,11 +46,11 @@ public class SmsBroadcastConfigInfo {
|
|||||||
*/
|
*/
|
||||||
public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme,
|
public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme,
|
||||||
int toScheme, boolean selected) {
|
int toScheme, boolean selected) {
|
||||||
setFromServiceId(fromId);
|
fromServiceId = fromId;
|
||||||
setToServiceId(toId);
|
toServiceId = toId;
|
||||||
setFromCodeScheme(fromScheme);
|
fromCodeScheme = fromScheme;
|
||||||
setToCodeScheme(toScheme);
|
toCodeScheme = toScheme;
|
||||||
this.setSelected(selected);
|
this.selected = selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,8 +126,8 @@ public class SmsBroadcastConfigInfo {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SmsBroadcastConfigInfo: Id [" +
|
return "SmsBroadcastConfigInfo: Id [" +
|
||||||
getFromServiceId() + "," + getToServiceId() + "] Code [" +
|
fromServiceId + ',' + toServiceId + "] Code [" +
|
||||||
getFromCodeScheme() + "," + getToCodeScheme() + "] " +
|
fromCodeScheme + ',' + toCodeScheme + "] " +
|
||||||
(isSelected() ? "ENABLED" : "DISABLED");
|
(selected ? "ENABLED" : "DISABLED");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package com.android.internal.telephony.gsm;
|
package com.android.internal.telephony.gsm;
|
||||||
|
|
||||||
public class SmsCbHeader {
|
import android.telephony.SmsCbConstants;
|
||||||
|
|
||||||
|
public class SmsCbHeader implements SmsCbConstants {
|
||||||
/**
|
/**
|
||||||
* Length of SMS-CB header
|
* Length of SMS-CB header
|
||||||
*/
|
*/
|
||||||
@ -107,4 +109,72 @@ public class SmsCbHeader {
|
|||||||
nrOfPages = 1;
|
nrOfPages = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the specified message ID is an emergency (PWS) message type.
|
||||||
|
* This method is static and takes an argument so that it can be used by
|
||||||
|
* CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU.
|
||||||
|
* @param id the message identifier to check
|
||||||
|
* @return true if the message is emergency type; false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isEmergencyMessage(int id) {
|
||||||
|
return id >= MESSAGE_ID_PWS_FIRST_IDENTIFIER && id <= MESSAGE_ID_PWS_LAST_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the specified message ID is an ETWS emergency message type.
|
||||||
|
* This method is static and takes an argument so that it can be used by
|
||||||
|
* CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU.
|
||||||
|
* @param id the message identifier to check
|
||||||
|
* @return true if the message is ETWS emergency type; false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isEtwsMessage(int id) {
|
||||||
|
return (id & MESSAGE_ID_ETWS_TYPE_MASK) == MESSAGE_ID_ETWS_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the specified message ID is a CMAS emergency message type.
|
||||||
|
* This method is static and takes an argument so that it can be used by
|
||||||
|
* CellBroadcastReceiver, which stores message ID's in SQLite rather than PDU.
|
||||||
|
* @param id the message identifier to check
|
||||||
|
* @return true if the message is CMAS emergency type; false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isCmasMessage(int id) {
|
||||||
|
return id >= MESSAGE_ID_CMAS_FIRST_IDENTIFIER && id <= MESSAGE_ID_CMAS_LAST_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the specified message code indicates an ETWS popup alert.
|
||||||
|
* This method is static and takes an argument so that it can be used by
|
||||||
|
* CellBroadcastReceiver, which stores message codes in SQLite rather than PDU.
|
||||||
|
* This method assumes that the message ID has already been checked for ETWS type.
|
||||||
|
*
|
||||||
|
* @param messageCode the message code to check
|
||||||
|
* @return true if the message code indicates a popup alert should be displayed
|
||||||
|
*/
|
||||||
|
public static boolean isEtwsPopupAlert(int messageCode) {
|
||||||
|
return (messageCode & MESSAGE_CODE_ETWS_ACTIVATE_POPUP) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the specified message code indicates an ETWS emergency user alert.
|
||||||
|
* This method is static and takes an argument so that it can be used by
|
||||||
|
* CellBroadcastReceiver, which stores message codes in SQLite rather than PDU.
|
||||||
|
* This method assumes that the message ID has already been checked for ETWS type.
|
||||||
|
*
|
||||||
|
* @param messageCode the message code to check
|
||||||
|
* @return true if the message code indicates an emergency user alert
|
||||||
|
*/
|
||||||
|
public static boolean isEtwsEmergencyUserAlert(int messageCode) {
|
||||||
|
return (messageCode & MESSAGE_CODE_ETWS_EMERGENCY_USER_ALERT) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SmsCbHeader{GS=" + geographicalScope + ", messageCode=0x" +
|
||||||
|
Integer.toHexString(messageCode) + ", updateNumber=" + updateNumber +
|
||||||
|
", messageIdentifier=0x" + Integer.toHexString(messageIdentifier) +
|
||||||
|
", DCS=0x" + Integer.toHexString(dataCodingScheme) +
|
||||||
|
", page " + pageIndex + " of " + nrOfPages + '}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user