Loading src/java/android/provider/Telephony.java +22 −0 Original line number Diff line number Diff line Loading @@ -923,6 +923,28 @@ public final class Telephony { public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; /** * Broadcast Action: A new text based mock SMS message has been received * by the device. For development purpose only. The intent will have the * following extra values:</p> * * <ul> * <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs * that make up the message.</li> * </ul></p> * or</p> * <ul> * <li><em>scAddress</em> - The mock SC address. xe: +01123456789.</li> * <li><em>senderAddr</em> - The mock sender address. xe: +01123456789.</li> * <li><em>msg</em> - The mock message. Multiple SMS are sent if the * length of the message exceed the SMS maximum length.</li> * </ul> * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String MOCK_SMS_RECEIVED_ACTION = "android.provider.Telephony.MOCK_SMS_RECEIVED"; /** * Broadcast Action: A new WAP PUSH message has been received by the * device. This intent will only be delivered to the default Loading src/java/com/android/internal/telephony/ImsSMSDispatcher.java +303 −0 Original line number Diff line number Diff line Loading @@ -20,16 +20,34 @@ package com.android.internal.telephony; import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import android.Manifest; import android.app.Activity; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.provider.Telephony.Sms.Intents; import android.telephony.PhoneNumberUtils; import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.telephony.SmsMessage.SubmitPdu; import android.text.TextUtils; import android.util.Log; import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; Loading @@ -47,6 +65,8 @@ public class ImsSMSDispatcher extends SMSDispatcher { protected GsmInboundSmsHandler mGsmInboundSmsHandler; protected CdmaInboundSmsHandler mCdmaInboundSmsHandler; private MockSmsDispatcher mMockSmsDispatcher; /** true if IMS is registered and sms is supported, false otherwise.*/ private boolean mIms = false; Loading Loading @@ -83,6 +103,10 @@ public class ImsSMSDispatcher extends SMSDispatcher { Thread broadcastThread = new Thread(new SmsBroadcastUndelivered(phone.getContext(), mGsmInboundSmsHandler, mCdmaInboundSmsHandler)); broadcastThread.start(); // Register the mock SMS receiver to simulate the reception of SMS mMockSmsDispatcher = new MockSmsDispatcher(); mMockSmsDispatcher.registerReceiver(); } Loading @@ -104,6 +128,7 @@ public class ImsSMSDispatcher extends SMSDispatcher { mCdmaDispatcher.dispose(); mGsmInboundSmsHandler.dispose(); mCdmaInboundSmsHandler.dispose(); mMockSmsDispatcher.unregisterReceiver(); } /** Loading Loading @@ -412,4 +437,282 @@ public class ImsSMSDispatcher extends SMSDispatcher { } return true; } /** * A private class that allow simulating the receive of SMS.<br/> * <br/> * A developer must use {@link Context#sendBroadcast(Intent)}, using the action * {@link Intents#MOCK_SMS_RECEIVED_ACTION}. The application requires * {@linkplain "android.permission.SEND_MOCK_SMS"} permission.<br/> * <br/> * This receiver should be used in the next way:<br/> * <pre> * Intent in = new Intent(Intents.MOCK_SMS_RECEIVED_ACTION); * in.putExtra("scAddr", "+01123456789"); * in.putExtra("senderAddr", "+01123456789"); * in.putExtra("msg", "This is a mock SMS message."); * sendBroadcast(in); * </pre><br/> * or<br/> * <pre> * String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; * byte[][] pdus = new byte[1][]; * pdus[0] = HexDump.hexStringToByteArray(pdu); * Intent in = new Intent(Intents.MOCK_SMS_RECEIVED_ACTION); * intent.putExtra("pdus", pdus); * sendBroadcast(in); * </pre><br/> */ private final class MockSmsDispatcher extends BroadcastReceiver { private static final String TAG = "MockSmsReceiver"; private static final String MOCK_ADDRESS = "+01123456789"; private static final String SEND_MOCK_SMS_PERMISSION = "android.permission.SEND_MOCK_SMS"; /** * Method that register the MockSmsReceiver class as a BroadcastReceiver */ public final void registerReceiver() { try { Handler handler = new Handler(); IntentFilter filter = new IntentFilter(); filter.addAction(Intents.MOCK_SMS_RECEIVED_ACTION); mContext.registerReceiver(this, filter, SEND_MOCK_SMS_PERMISSION, handler); Log.d(TAG, "Registered MockSmsReceiver"); } catch (Exception ex) { Log.e(TAG, "Failed to register MockSmsReceiver", ex); } } /** * Method that unregister the MockSmsReceiver class as a BroadcastReceiver */ public final void unregisterReceiver() { try { mContext.unregisterReceiver(this); } catch (Exception ex) { Log.e(TAG, "Failed to unregister MockSmsReceiver", ex); } } /** * {@inheritDoc} */ @Override public final void onReceive(Context context, Intent intent) { Log.d(TAG, "New mock SMS reception request. Intent: " + intent); String action = intent.getAction(); if (!Intents.MOCK_SMS_RECEIVED_ACTION.equals(action)) { return; } try { // Check that developer option is enabled, and mock // messages are allowed boolean allowMockSMS = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ALLOW_MOCK_SMS, 0) == 1; if (!allowMockSMS) { // Mock SMS is not allowed. Log.w(TAG, "Mock SMS is not allowed. Enable Mock SMS on " + "Settings/Delevelopment."); return; } // Check that the device supports the telephony subsystem PackageManager packageManager = mContext.getPackageManager(); if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { // Telephony is not supported Log.w(TAG, "Mock SMS is not allowed because telephony is not supported."); return; } // Extract PDUs List<byte[][]> msgs = new ArrayList<byte[][]>(); Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); if (messages != null && messages.length > 0) { // Use the PDUs from the intent byte[][] pdus = new byte[messages.length][]; for (int i = 0; i < messages.length; i++) { pdus[i] = (byte[]) messages[i]; } msgs.add(pdus); } else { // Build the PDUs from SMS data String scAddress = intent.getStringExtra("scAddr"); String senderAddress = intent.getStringExtra("senderAddr"); String msg = intent.getStringExtra("msg"); // Check that values are valid. Otherwise fill will default values if (TextUtils.isEmpty(scAddress)) { scAddress = MOCK_ADDRESS; } if (TextUtils.isEmpty(senderAddress)) { senderAddress = MOCK_ADDRESS; } if (TextUtils.isEmpty(msg)) { msg = "This is a mock SMS message."; } Log.d(TAG, String.format( "Mock SMS. scAddress: %s, senderAddress: %s, msg: %s", scAddress, senderAddress, msg)); // Fragment the text in message according to SMS length List<String> fragmentMsgs = android.telephony.SmsMessage.fragmentText(msg); for (String fragmentMsg : fragmentMsgs) { msgs.add(getPdus(scAddress, senderAddress, fragmentMsg)); } } // How messages are going to send? Log.d(TAG, String.format("Mock SMS. Number of msg: %d", msgs.size())); // Send messages for (byte[][] pdus : msgs) { dispatch(pdus, android.telephony.SmsMessage.FORMAT_3GPP); } } catch (Exception ex) { Log.e(TAG, "Failed to dispatch SMS", ex); } } private void dispatch(byte[][] pdus, String format) { Intent intent = new Intent(Intents.SMS_DELIVER_ACTION); // Direct the intent to only the default SMS app. If we can't find a default SMS app // then sent it to all broadcast receivers. ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); if (componentName != null) { // Deliver SMS message only to this receiver intent.setComponent(componentName); Log.w(TAG, "Delivering SMS to: " + componentName.getPackageName() + " " + componentName.getClassName()); } intent.putExtra("pdus", pdus); intent.putExtra("format", format); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS, AppOpsManager.OP_RECEIVE_SMS, null, null, Activity.RESULT_OK, null, null); } /** * Method that convert the basic SMS string data to a PDUs messages * * @param scAddress The mock the SC address * @param senderAddress The mock the sender address * @param msg The mock message body * @return byte[] The array of bytes of the PDU */ private byte[][] getPdus(String scAddress, String senderAddress, String msg) { // Get a SubmitPdu (use a phone number to get a valid pdu) SubmitPdu submitPdu = android.telephony.SmsMessage.getSubmitPdu( scAddress, MOCK_ADDRESS, msg, false); // Translate the submit data to a received PDU int dataLen = android.telephony.SmsMessage.calculateLength(msg, true)[1]; // Locate protocol + data encoding scheme byte[] pds = {(byte)0, (byte)0, (byte)dataLen}; int dataPos = new String(submitPdu.encodedMessage).indexOf(new String(pds), 4) + 2; // Set arrays dimension byte[] encSc = submitPdu.encodedScAddress; byte[] encMsg = new byte[submitPdu.encodedMessage.length - dataPos]; System.arraycopy( submitPdu.encodedMessage, dataPos, encMsg, 0, submitPdu.encodedMessage.length - dataPos); byte[] encSender = null; // Check if the senderAddress is a vanish number if (!PhoneNumberUtils.isWellFormedSmsAddress(senderAddress)) { try { byte[] sender7BitPacked = GsmAlphabet.stringToGsm7BitPacked(senderAddress); encSender = new byte[2 + sender7BitPacked.length - 1]; encSender[0] = (byte)((sender7BitPacked.length - 1) * 2); encSender[1] = (byte)0xD0; // Alphabetic sender System.arraycopy(sender7BitPacked, 1, encSender, 2, sender7BitPacked.length - 1); } catch (EncodeException e) { Log.e(TAG, "Failed to decode sender address. Using default.", e); encSender = new byte[dataPos - 4]; System.arraycopy( submitPdu.encodedMessage, 2, encSender, 0, dataPos - 4); } } else { encSender = new byte[dataPos - 4]; System.arraycopy( submitPdu.encodedMessage, 2, encSender, 0, dataPos - 4); } byte[] encTs = bcdTimestamp(); byte[] pdu = new byte[ encSc.length + 1 + /** SMS-DELIVER **/ encSender.length + 2 + /** Protocol + Data Encoding Scheme **/ encTs.length + encMsg.length]; // Copy the SC address int c = 0; System.arraycopy(encSc, 0, pdu, c, encSc.length); c+=encSc.length; // SMS-DELIVER pdu[c] = 0x04; c++; // Sender System.arraycopy(encSender, 0, pdu, c, encSender.length); c+=encSender.length; // Protocol + Data encoding scheme pdu[c] = 0x00; c++; pdu[c] = 0x00; c++; // Timestamp System.arraycopy(encTs, 0, pdu, c, encTs.length); c+=encTs.length; // Message System.arraycopy(encMsg, 0, pdu, c, encMsg.length); // Return the PDUs return new byte[][]{pdu}; } /** * Method that return the current timestamp in a BCD format * * @return byte[] The BCD timestamp */ private byte[] bcdTimestamp() { Calendar c = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yy"); //$NON-NLS-1$ SimpleDateFormat sdf2 = new SimpleDateFormat("Z"); //$NON-NLS-1$ byte year = (byte)Integer.parseInt( String.valueOf(Integer.parseInt(sdf.format(c.getTime()))), 16); byte month = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.MONTH) + 1), 16); byte day = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.DAY_OF_MONTH)), 16); byte hour = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.HOUR)), 16); byte minute = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.MINUTE)), 16); byte second = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.SECOND)), 16); String tz = sdf2.format(c.getTime()).substring(1); int timezone = Integer.parseInt(tz) / 100; if (timezone < 0) { timezone += 0x80; } byte[] data = {year, month, day, hour, minute, second, 0}; byte[] ts = IccUtils.hexStringToBytes(IccUtils.bcdToString(data, 0, data.length)); ts[6] = (byte)Integer.parseInt(String.valueOf(timezone), 16); return ts; } } } Loading
src/java/android/provider/Telephony.java +22 −0 Original line number Diff line number Diff line Loading @@ -923,6 +923,28 @@ public final class Telephony { public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; /** * Broadcast Action: A new text based mock SMS message has been received * by the device. For development purpose only. The intent will have the * following extra values:</p> * * <ul> * <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs * that make up the message.</li> * </ul></p> * or</p> * <ul> * <li><em>scAddress</em> - The mock SC address. xe: +01123456789.</li> * <li><em>senderAddr</em> - The mock sender address. xe: +01123456789.</li> * <li><em>msg</em> - The mock message. Multiple SMS are sent if the * length of the message exceed the SMS maximum length.</li> * </ul> * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String MOCK_SMS_RECEIVED_ACTION = "android.provider.Telephony.MOCK_SMS_RECEIVED"; /** * Broadcast Action: A new WAP PUSH message has been received by the * device. This intent will only be delivered to the default Loading
src/java/com/android/internal/telephony/ImsSMSDispatcher.java +303 −0 Original line number Diff line number Diff line Loading @@ -20,16 +20,34 @@ package com.android.internal.telephony; import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import android.Manifest; import android.app.Activity; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.provider.Telephony.Sms.Intents; import android.telephony.PhoneNumberUtils; import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.telephony.SmsMessage.SubmitPdu; import android.text.TextUtils; import android.util.Log; import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; Loading @@ -47,6 +65,8 @@ public class ImsSMSDispatcher extends SMSDispatcher { protected GsmInboundSmsHandler mGsmInboundSmsHandler; protected CdmaInboundSmsHandler mCdmaInboundSmsHandler; private MockSmsDispatcher mMockSmsDispatcher; /** true if IMS is registered and sms is supported, false otherwise.*/ private boolean mIms = false; Loading Loading @@ -83,6 +103,10 @@ public class ImsSMSDispatcher extends SMSDispatcher { Thread broadcastThread = new Thread(new SmsBroadcastUndelivered(phone.getContext(), mGsmInboundSmsHandler, mCdmaInboundSmsHandler)); broadcastThread.start(); // Register the mock SMS receiver to simulate the reception of SMS mMockSmsDispatcher = new MockSmsDispatcher(); mMockSmsDispatcher.registerReceiver(); } Loading @@ -104,6 +128,7 @@ public class ImsSMSDispatcher extends SMSDispatcher { mCdmaDispatcher.dispose(); mGsmInboundSmsHandler.dispose(); mCdmaInboundSmsHandler.dispose(); mMockSmsDispatcher.unregisterReceiver(); } /** Loading Loading @@ -412,4 +437,282 @@ public class ImsSMSDispatcher extends SMSDispatcher { } return true; } /** * A private class that allow simulating the receive of SMS.<br/> * <br/> * A developer must use {@link Context#sendBroadcast(Intent)}, using the action * {@link Intents#MOCK_SMS_RECEIVED_ACTION}. The application requires * {@linkplain "android.permission.SEND_MOCK_SMS"} permission.<br/> * <br/> * This receiver should be used in the next way:<br/> * <pre> * Intent in = new Intent(Intents.MOCK_SMS_RECEIVED_ACTION); * in.putExtra("scAddr", "+01123456789"); * in.putExtra("senderAddr", "+01123456789"); * in.putExtra("msg", "This is a mock SMS message."); * sendBroadcast(in); * </pre><br/> * or<br/> * <pre> * String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; * byte[][] pdus = new byte[1][]; * pdus[0] = HexDump.hexStringToByteArray(pdu); * Intent in = new Intent(Intents.MOCK_SMS_RECEIVED_ACTION); * intent.putExtra("pdus", pdus); * sendBroadcast(in); * </pre><br/> */ private final class MockSmsDispatcher extends BroadcastReceiver { private static final String TAG = "MockSmsReceiver"; private static final String MOCK_ADDRESS = "+01123456789"; private static final String SEND_MOCK_SMS_PERMISSION = "android.permission.SEND_MOCK_SMS"; /** * Method that register the MockSmsReceiver class as a BroadcastReceiver */ public final void registerReceiver() { try { Handler handler = new Handler(); IntentFilter filter = new IntentFilter(); filter.addAction(Intents.MOCK_SMS_RECEIVED_ACTION); mContext.registerReceiver(this, filter, SEND_MOCK_SMS_PERMISSION, handler); Log.d(TAG, "Registered MockSmsReceiver"); } catch (Exception ex) { Log.e(TAG, "Failed to register MockSmsReceiver", ex); } } /** * Method that unregister the MockSmsReceiver class as a BroadcastReceiver */ public final void unregisterReceiver() { try { mContext.unregisterReceiver(this); } catch (Exception ex) { Log.e(TAG, "Failed to unregister MockSmsReceiver", ex); } } /** * {@inheritDoc} */ @Override public final void onReceive(Context context, Intent intent) { Log.d(TAG, "New mock SMS reception request. Intent: " + intent); String action = intent.getAction(); if (!Intents.MOCK_SMS_RECEIVED_ACTION.equals(action)) { return; } try { // Check that developer option is enabled, and mock // messages are allowed boolean allowMockSMS = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ALLOW_MOCK_SMS, 0) == 1; if (!allowMockSMS) { // Mock SMS is not allowed. Log.w(TAG, "Mock SMS is not allowed. Enable Mock SMS on " + "Settings/Delevelopment."); return; } // Check that the device supports the telephony subsystem PackageManager packageManager = mContext.getPackageManager(); if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { // Telephony is not supported Log.w(TAG, "Mock SMS is not allowed because telephony is not supported."); return; } // Extract PDUs List<byte[][]> msgs = new ArrayList<byte[][]>(); Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); if (messages != null && messages.length > 0) { // Use the PDUs from the intent byte[][] pdus = new byte[messages.length][]; for (int i = 0; i < messages.length; i++) { pdus[i] = (byte[]) messages[i]; } msgs.add(pdus); } else { // Build the PDUs from SMS data String scAddress = intent.getStringExtra("scAddr"); String senderAddress = intent.getStringExtra("senderAddr"); String msg = intent.getStringExtra("msg"); // Check that values are valid. Otherwise fill will default values if (TextUtils.isEmpty(scAddress)) { scAddress = MOCK_ADDRESS; } if (TextUtils.isEmpty(senderAddress)) { senderAddress = MOCK_ADDRESS; } if (TextUtils.isEmpty(msg)) { msg = "This is a mock SMS message."; } Log.d(TAG, String.format( "Mock SMS. scAddress: %s, senderAddress: %s, msg: %s", scAddress, senderAddress, msg)); // Fragment the text in message according to SMS length List<String> fragmentMsgs = android.telephony.SmsMessage.fragmentText(msg); for (String fragmentMsg : fragmentMsgs) { msgs.add(getPdus(scAddress, senderAddress, fragmentMsg)); } } // How messages are going to send? Log.d(TAG, String.format("Mock SMS. Number of msg: %d", msgs.size())); // Send messages for (byte[][] pdus : msgs) { dispatch(pdus, android.telephony.SmsMessage.FORMAT_3GPP); } } catch (Exception ex) { Log.e(TAG, "Failed to dispatch SMS", ex); } } private void dispatch(byte[][] pdus, String format) { Intent intent = new Intent(Intents.SMS_DELIVER_ACTION); // Direct the intent to only the default SMS app. If we can't find a default SMS app // then sent it to all broadcast receivers. ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); if (componentName != null) { // Deliver SMS message only to this receiver intent.setComponent(componentName); Log.w(TAG, "Delivering SMS to: " + componentName.getPackageName() + " " + componentName.getClassName()); } intent.putExtra("pdus", pdus); intent.putExtra("format", format); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); mContext.sendOrderedBroadcast(intent, Manifest.permission.RECEIVE_SMS, AppOpsManager.OP_RECEIVE_SMS, null, null, Activity.RESULT_OK, null, null); } /** * Method that convert the basic SMS string data to a PDUs messages * * @param scAddress The mock the SC address * @param senderAddress The mock the sender address * @param msg The mock message body * @return byte[] The array of bytes of the PDU */ private byte[][] getPdus(String scAddress, String senderAddress, String msg) { // Get a SubmitPdu (use a phone number to get a valid pdu) SubmitPdu submitPdu = android.telephony.SmsMessage.getSubmitPdu( scAddress, MOCK_ADDRESS, msg, false); // Translate the submit data to a received PDU int dataLen = android.telephony.SmsMessage.calculateLength(msg, true)[1]; // Locate protocol + data encoding scheme byte[] pds = {(byte)0, (byte)0, (byte)dataLen}; int dataPos = new String(submitPdu.encodedMessage).indexOf(new String(pds), 4) + 2; // Set arrays dimension byte[] encSc = submitPdu.encodedScAddress; byte[] encMsg = new byte[submitPdu.encodedMessage.length - dataPos]; System.arraycopy( submitPdu.encodedMessage, dataPos, encMsg, 0, submitPdu.encodedMessage.length - dataPos); byte[] encSender = null; // Check if the senderAddress is a vanish number if (!PhoneNumberUtils.isWellFormedSmsAddress(senderAddress)) { try { byte[] sender7BitPacked = GsmAlphabet.stringToGsm7BitPacked(senderAddress); encSender = new byte[2 + sender7BitPacked.length - 1]; encSender[0] = (byte)((sender7BitPacked.length - 1) * 2); encSender[1] = (byte)0xD0; // Alphabetic sender System.arraycopy(sender7BitPacked, 1, encSender, 2, sender7BitPacked.length - 1); } catch (EncodeException e) { Log.e(TAG, "Failed to decode sender address. Using default.", e); encSender = new byte[dataPos - 4]; System.arraycopy( submitPdu.encodedMessage, 2, encSender, 0, dataPos - 4); } } else { encSender = new byte[dataPos - 4]; System.arraycopy( submitPdu.encodedMessage, 2, encSender, 0, dataPos - 4); } byte[] encTs = bcdTimestamp(); byte[] pdu = new byte[ encSc.length + 1 + /** SMS-DELIVER **/ encSender.length + 2 + /** Protocol + Data Encoding Scheme **/ encTs.length + encMsg.length]; // Copy the SC address int c = 0; System.arraycopy(encSc, 0, pdu, c, encSc.length); c+=encSc.length; // SMS-DELIVER pdu[c] = 0x04; c++; // Sender System.arraycopy(encSender, 0, pdu, c, encSender.length); c+=encSender.length; // Protocol + Data encoding scheme pdu[c] = 0x00; c++; pdu[c] = 0x00; c++; // Timestamp System.arraycopy(encTs, 0, pdu, c, encTs.length); c+=encTs.length; // Message System.arraycopy(encMsg, 0, pdu, c, encMsg.length); // Return the PDUs return new byte[][]{pdu}; } /** * Method that return the current timestamp in a BCD format * * @return byte[] The BCD timestamp */ private byte[] bcdTimestamp() { Calendar c = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yy"); //$NON-NLS-1$ SimpleDateFormat sdf2 = new SimpleDateFormat("Z"); //$NON-NLS-1$ byte year = (byte)Integer.parseInt( String.valueOf(Integer.parseInt(sdf.format(c.getTime()))), 16); byte month = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.MONTH) + 1), 16); byte day = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.DAY_OF_MONTH)), 16); byte hour = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.HOUR)), 16); byte minute = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.MINUTE)), 16); byte second = (byte)Integer.parseInt(String.valueOf(c.get(Calendar.SECOND)), 16); String tz = sdf2.format(c.getTime()).substring(1); int timezone = Integer.parseInt(tz) / 100; if (timezone < 0) { timezone += 0x80; } byte[] data = {year, month, day, hour, minute, second, 0}; byte[] ts = IccUtils.hexStringToBytes(IccUtils.bcdToString(data, 0, data.length)); ts[6] = (byte)Integer.parseInt(String.valueOf(timezone), 16); return ts; } } }