package com.android.bluetooth.tests; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import org.apache.http.message.BasicHeaderValueFormatter; import android.preference.PreferenceFragment; import android.test.AndroidTestCase; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.android.bluetooth.map.BluetoothMapAppParams; import com.android.bluetooth.map.BluetoothMapUtils.TYPE; import com.android.bluetooth.map.BluetoothMapSmsPdu; import com.android.bluetooth.map.BluetoothMapbMessage; import com.android.bluetooth.map.BluetoothMapbMessageMms; import com.android.bluetooth.map.BluetoothMapbMessageSms; import org.apache.http.message.BasicHeaderValueFormatter; import org.apache.http.message.BasicHeaderElement; /*** * * Test cases for the bMessage class. (encoding and decoding) * */ public class BluetoothMapbMessageTest extends AndroidTestCase { protected static String TAG = "BluetoothMapbMessageTest"; protected static final boolean D = true; public BluetoothMapbMessageTest() { super(); } /*** * Test encoding of a simple SMS text message (UTF8). This validates most parameters. */ public void testSmsEncodeText() { BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); String str1 = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:UNREAD\r\n" + "TYPE:SMS_GSM\r\n" + "FOLDER:telecom/msg/inbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Casper Bonde\r\n" + "N:Bonde,Casper\r\n" + "TEL:+4512345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Jens Hansen\r\n" + "N:\r\n" + "TEL:+4512345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "CHARSET:UTF-8\r\n" + "LENGTH:45\r\n" + "BEGIN:MSG\r\n" + "This is a short message\r\n" + "END:MSG\r\n" + "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; String encoded; String[] phone = {"+4512345678", "+4587654321"}; String[] email = {"casper@email.add", "bonde@email.add"}; msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email); msg.addRecipient("", "Jens Hansen", phone, email); msg.setFolder("inbox"); msg.setSmsBody("This is a short message"); msg.setStatus(false); msg.setType(TYPE.SMS_GSM); try { encoded = new String(msg.encode()); if(D) Log.d(TAG, encoded); assertTrue(str1.equals(encoded)); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed.", true); } } /*** * Test native Deliver PDU encoding (decoding not possible), based on the example in the MAP 1.1 specification. * The difference between this PDU, and the one in the specification: * - The invalid SC address 0191 is replaced with no address 00 * - The "No more messages flag" is set (bit 2 in the second byte) * - The phone number type is changed from private 91 to international 81 * - The time is changed to local time, since the time zone cannot be controlled through the API */ public void testSmsEncodeNativeDeliverPdu() { BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss"); Date date = new Date(System.currentTimeMillis()); String timeStr = format.format(date); // Format to YYMMDDTHHMMSS UTC time ByteArrayOutputStream scTime = new ByteArrayOutputStream(7); StringBuilder scTimeSb = new StringBuilder(); byte[] timeChars; try { timeChars = timeStr.getBytes("US-ASCII"); } catch (UnsupportedEncodingException e1) { assertTrue("Failed to extract bytes from string using US-ASCII", true); return; } for(int i = 0, n = timeStr.length(); i < n; i+=2) { scTime.write((timeChars[i+1]-0x30) << 4 | (timeChars[i]-0x30)); // Offset from ascii char to decimal value } Calendar cal = Calendar.getInstance(); int offset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (15 * 60 * 1000); /* offset in quarters of an hour */ String offsetString; if(offset < 0) { offsetString = String.format("%1$02d", -(offset)); char[] offsetChars = offsetString.toCharArray(); scTime.write((offsetChars[1]-0x30) << 4 | 0x40 | (offsetChars[0]-0x30)); } else { offsetString = String.format("%1$02d", offset); char[] offsetChars = offsetString.toCharArray(); scTime.write((offsetChars[1]-0x30) << 4 | (offsetChars[0]-0x30)); } byte[] scTimeData = scTime.toByteArray(); for(int i = 0; i < scTimeData.length; i++) { scTimeSb.append(Integer.toString((scTimeData[i] >> 4) & 0x0f,16)); // MS-nibble first scTimeSb.append(Integer.toString( scTimeData[i] & 0x0f,16)); } if(D) Log.v(TAG, "Generated time string: " + scTimeSb.toString()); String expected = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:UNREAD\r\n" + "TYPE:SMS_GSM\r\n" + "FOLDER:telecom/msg/inbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Casper Bonde\r\n" + "N:Bonde,Casper\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Jens Hansen\r\n" + "N:\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "ENCODING:G-7BIT\r\n" + "LENGTH:94\r\n" + "BEGIN:MSG\r\n" + "00040E81009498214365870000" + scTimeSb.toString() + "11CC32FD34079DDF20737A8E4EBBCF21\r\n" + "END:MSG\r\n" + "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; String encoded; String[] phone = {"00498912345678", "+4587654321"}; String[] email = {"casper@email.add", "bonde@email.add"}; msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email); msg.addRecipient("", "Jens Hansen", phone, email); msg.setFolder("inbox"); /* TODO: extract current time, and build the expected string */ msg.setSmsBodyPdus(BluetoothMapSmsPdu.getDeliverPdus("Let's go fishing!", "00498912345678", date.getTime())); msg.setStatus(false); msg.setType(TYPE.SMS_GSM); try { byte[] encodedBytes = msg.encode(); // InputStream is = new ByteArrayInputStream(encodedBytes); encoded = new String(encodedBytes); // BluetoothMapbMessage newMsg = BluetoothMapbMessage.parse(is, BluetoothMapAppParams.CHARSET_NATIVE); // String decoded = ((BluetoothMapbMessageSms) newMsg).getSmsBody(); if(D) Log.d(TAG, "\nExpected: \n" + expected); if(D) Log.d(TAG, "\nEncoded: \n" + encoded); // if(D) Log.d(TAG, "\nDecoded: \n" + decoded); assertTrue(expected.equalsIgnoreCase(encoded)); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed.", true); } } /*** * Test native Submit PDU encoding and decoding, based on the example in the MAP 1.1 specification. * The difference between this PDU, and the one in the specification: * - The invalid SC address 0191 is replaced with no address 00 * - The PDU is converted to a submit PDU by adding the TP-MR and removing the service center time stamp. * - The phone number type is changed from private 91 to international 81 */ public void testSmsEncodeDecodeNativeSubmitPdu() { BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); String expected = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:UNREAD\r\n" + "TYPE:SMS_GSM\r\n" + "FOLDER:telecom/msg/outbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Casper Bonde\r\n" + "N:Bonde,Casper\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Jens Hansen\r\n" + "N:\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "ENCODING:G-7BIT\r\n" + "LENGTH:82\r\n" + "BEGIN:MSG\r\n" + /*Length 11 */ "0001000E8100949821436587000011CC32FD34079DDF20737A8E4EBBCF21\r\n" + /* Length 62 */ "END:MSG\r\n" + /* Length 9 */ "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; String encoded; String[] phone = {"00498912345678", "+4587654321"}; String[] email = {"casper@email.add", "bonde@email.add"}; msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email); msg.addRecipient("", "Jens Hansen", phone, email); msg.setFolder("outbox"); /* TODO: extract current time, and build the expected string */ msg.setSmsBodyPdus(BluetoothMapSmsPdu.getSubmitPdus("Let's go fishing!", "00498912345678")); msg.setStatus(false); msg.setType(TYPE.SMS_GSM); try { byte[] encodedBytes = msg.encode(); InputStream is = new ByteArrayInputStream(encodedBytes); encoded = new String(encodedBytes); BluetoothMapbMessage newMsg = BluetoothMapbMessage.parse(is, BluetoothMapAppParams.CHARSET_NATIVE); String decoded = ((BluetoothMapbMessageSms) newMsg).getSmsBody(); if(D) Log.d(TAG, "\nCalling encoder on decoded message to log its content"); newMsg.encode(); if(D) Log.d(TAG, "\nExpected: \n" + expected); if(D) Log.d(TAG, "\nEncoded: \n" + encoded); if(D) Log.d(TAG, "\nDecoded: \n" + decoded); assertTrue("The encoded bMessage do not match the expected.", expected.equalsIgnoreCase(encoded)); assertTrue("The decoded text is \"" + decoded + "\" - expected \"Let's go fishing!\"", decoded.equalsIgnoreCase("Let's go fishing!")); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed.", true); } } /*** * Test native Submit PDU encoding and decoding, based on the example in the MAP 1.1 specification. * The difference between this PDU, and the one in the specification: * - The invalid SC address 0191 is replaced with no address 00 * - The PDU is converted to a submit PDU by adding the TP-MR and removing the service center time stamp. * - The phone number type is changed from private 91 to international 81 */ public void testSmsEncodeDecodeNativeSubmitPduWithSc() { BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); String encoded = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:UNREAD\r\n" + "TYPE:SMS_GSM\r\n" + "FOLDER:telecom/msg/outbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Casper Bonde\r\n" + "N:Bonde,Casper\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Jens Hansen\r\n" + "N:\r\n" + "TEL:00498912345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "ENCODING:G-7BIT\r\n" + "LENGTH:58 \r\n" + "BEGIN:MSG\r\n" + /*Length 11 */ "018001000B912184254590F500000346F61B\r\n" + /* Length 38 */ "END:MSG\r\n" + /* Length 9 */ "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; try { String expected = "Flo"; InputStream is = new ByteArrayInputStream(encoded.getBytes("UTF-8")); BluetoothMapbMessage newMsg = BluetoothMapbMessage.parse(is, BluetoothMapAppParams.CHARSET_NATIVE); String decoded = ((BluetoothMapbMessageSms) newMsg).getSmsBody(); if(D) Log.d(TAG, "\nEncoded: \n" + encoded); if(D) Log.d(TAG, "\nDecoded: \n" + decoded); assertTrue("Decoded string (" + decoded + ") did not match expected (" + expected + ")", expected.equals(decoded)); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed.", false); } } /*** * Validate that the folder is correctly truncated to 512 bytes, if a longer folder path * is supplied. */ public void testFolderLengthTruncation() { String folder = ""; int levelCount = 0; while(folder.length()<640) folder += "/folder" + levelCount++; String expected = folder.substring(folder.length()-512, folder.length()); BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); msg.setFolder(folder); msg.setStatus(false); msg.setType(TYPE.SMS_GSM); try { byte[] encoded = msg.encode(); InputStream is = new ByteArrayInputStream(encoded); if(D) Log.d(TAG, new String(encoded)); BluetoothMapbMessage newMsg = BluetoothMapbMessage.parse(is, BluetoothMapAppParams.CHARSET_UTF8); assertTrue("Wrong length expected 512, got " + expected.length(), expected.length() == 512); Log.d(TAG, "expected: " + expected); Log.d(TAG, "newMsg.getFolder(): " + newMsg.getFolder()); assertTrue("Folder string did not match", expected.equals(newMsg.getFolder())); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed", false); } } /*** * Test multipart message decoding. */ public void testSmsMultipartDecode() { BluetoothMapbMessageSms msg = new BluetoothMapbMessageSms(); String encoded = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:READ\r\n" + "TYPE:SMS_GSM\r\n" + "FOLDER:/telecom/msg/outbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:2.1\r\n" + "N:12485254094 \r\n" + "TEL:12485254094\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:2.1\r\n" + "N:+12485254095 \r\n" + "TEL:+12485254095\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "ENCODING:G-7BIT\r\n" + "LENGTH:762\r\n" + "BEGIN:MSG\r\n" + "018041000B912184254590F50000A0050003010301A8E8F41C949E83C220F69B0E7A9B41F7B79C3C07D1DF20F35BDE068541E3B77B1CA697DD617A990C6A97E7F3F0B90C0ABBC9203ABA0C32A7E5733A889E6E9741F437888E2E83E66537B92C07A5DBED32391DA697D97990FB4D4F9BF3A07619B476BFEFA03B3A4C07E5DF7550585E06B9DF74D0BC2E2F83F2EF3A681C7683C86F509A0EBABFEB\r\n" + "END:MSG\r\n" + "BEGIN:MSG\r\n" + "018041000B912184254590F50000A0050003010302C820767A5D06D1D16550DA4D2FBBC96532485E1EA7E1E9B29B0E82B3CBE17919644EBBC9A0779D0EA2A3CB20735A3EA783E8E8B4FB0CA2BF41E437C8FDA683E6757919947FD741E3B01B447E83D274D0FD5D679341ECB7BD0C4AD341F7F01C44479741E6B47C4E0791C379D0DB0C6AE741F2F2BCDE2E83CC6F3928FFAECB41E57638CD06A5E7\r\n" + "END:MSG\r\n" + "BEGIN:MSG\r\n" + "018041000B912184254590F500001A050003010303DC6F3A685E979741F9771D340EBB41E437\r\n" + "END:MSG\r\n" + "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; try { InputStream is = new ByteArrayInputStream(encoded.getBytes("UTF-8")); BluetoothMapbMessage newMsg = BluetoothMapbMessage.parse(is, BluetoothMapAppParams.CHARSET_NATIVE); String decoded = ((BluetoothMapbMessageSms) newMsg).getSmsBody(); if(D) Log.d(TAG, "\nEncoded: \n" + encoded); if(D) Log.d(TAG, "\nDecoded: \n" + decoded); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Decoding failed.",e); assertTrue("Decoding failed.", false); } } /*** * Test encoding of a simple MMS text message (UTF8). This validates most parameters. */ public void testMmsEncodeText() { BluetoothMapbMessageMms msg = new BluetoothMapbMessageMms(); String str1 = "BEGIN:BMSG\r\n" + "VERSION:1.0\r\n" + "STATUS:UNREAD\r\n" + "TYPE:MMS\r\n" + "FOLDER:telecom/msg/inbox\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Casper Bonde\r\n" + "N:Bonde,Casper\r\n" + "TEL:+4512345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BENV\r\n" + "BEGIN:VCARD\r\n" + "VERSION:3.0\r\n" + "FN:Jørn Hansen\r\n" + "N:\r\n" + "TEL:+4512345678\r\n" + "TEL:+4587654321\r\n" + "EMAIL:casper@email.add\r\n" + "EMAIL:bonde@email.add\r\n" + "END:VCARD\r\n" + "BEGIN:BBODY\r\n" + "CHARSET:UTF-8\r\n" + "LENGTH:45\r\n" + "BEGIN:MSG\r\n" + "This is a short message\r\n" + "END:MSG\r\n" + "END:BBODY\r\n" + "END:BENV\r\n" + "END:BMSG\r\n"; String encoded; String[] phone = {"+4512345678", "+4587654321"}; String[] email = {"casper@email.add", "bonde@email.add"}; msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email); msg.addRecipient("", "Jørn Hansen", phone, email); msg.setFolder("inbox"); msg.setIncludeAttachments(false); msg.addTo("Jørn Hansen", "bonde@email.add"); msg.addCc("Jens Hansen", "bonde@email.add"); msg.addFrom("Jørn Hansen", "bonde@email.add"); BluetoothMapbMessageMms.MimePart part = msg.addMimePart(); part.mPartName = "partNameText"; part.mContentType ="dsfajfdlk/text/asdfafda"; try { part.mData = new String("This is a short message\r\n").getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { if(D) Log.e(TAG, "UnsupportedEncodingException should never happen???", e); assertTrue(false); } part = msg.addMimePart(); part.mPartName = "partNameimage"; part.mContentType = "dsfajfdlk/image/asdfafda"; part.mData = null; msg.setStatus(false); msg.setType(TYPE.MMS); try { encoded = new String(msg.encode()); if(D) Log.d(TAG, encoded); assertTrue(str1.equals(encoded)); } catch (UnsupportedEncodingException e) { Log.d(TAG, "Encoding failed.",e); assertTrue("Encoding failed.", true); } } public void testHeaderEncode() { BasicHeaderElement header = new BasicHeaderElement("To","Jørgen "); String headerStr = BasicHeaderValueFormatter.formatHeaderElement(header, true, BasicHeaderValueFormatter.DEFAULT); if(D) Log.i(TAG, "The encoded header: " + headerStr); } }