Use only UTF-8 for fetching a message.

Currently the API lets the users fetch SMS using either UTF-8 or native
SMS-PDU format. SMS-PDU is not supported by the String() class (also its
more complicated than just a simple string encoding since it contains
recipient etc information). Besides, the library does not decode such
messages and leaves it to the user to handle them. Currently it decodes
it as the default character set on device which is incorrect behavior.
Hence in this change we ensure that the API can only be used with UTF-8
which makes the conversion of Strings consistent.

NOTE: It's OK to avoid supporting native charset since it is not
mandatory in MAPv12 spec.

Change-Id: Ic10a82ff69f848cb3f6e80353d3e63ce3910d306
(cherry picked from commit 4b4d3f8260c9b4476f900ee7b08ee66450624081)
diff --git a/src/android/bluetooth/client/map/BluetoothMapBmessage.java b/src/android/bluetooth/client/map/BluetoothMapBmessage.java
index 84e4c75..e06b033 100644
--- a/src/android/bluetooth/client/map/BluetoothMapBmessage.java
+++ b/src/android/bluetooth/client/map/BluetoothMapBmessage.java
@@ -159,6 +159,7 @@
             json.put("status", mBmsgStatus);
             json.put("type", mBmsgType);
             json.put("folder", mBmsgFolder);
+            json.put("charset", mBbodyCharset);
             json.put("message", mMessage);
         } catch (JSONException e) {
             // do nothing
diff --git a/src/android/bluetooth/client/map/BluetoothMapBmessageParser.java b/src/android/bluetooth/client/map/BluetoothMapBmessageParser.java
index ef75e7b..d4da25c 100644
--- a/src/android/bluetooth/client/map/BluetoothMapBmessageParser.java
+++ b/src/android/bluetooth/client/map/BluetoothMapBmessageParser.java
@@ -33,11 +33,13 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.text.ParseException;
 
 class BluetoothMapBmessageParser {
 
     private final static String TAG = "BluetoothMapBmessageParser";
+    private final boolean DBG = false;
 
     private final static String CRLF = "\r\n";
 
@@ -75,6 +77,10 @@
     static public BluetoothMapBmessage createBmessage(String str) {
         BluetoothMapBmessageParser p = new BluetoothMapBmessageParser();
 
+        if (DBG) {
+            Log.d(TAG, "actual wired contents: " + str);
+        }
+
         try {
             p.parse(str);
         } catch (IOException e) {
@@ -291,6 +297,17 @@
         } while (!prop.equals(BEGIN_MSG));
 
         /*
+         * check that the charset is always set to UTF-8. We expect only text transfer (in lieu with
+         * the MAPv12 specifying only RFC2822 (text only) for MMS/EMAIL and SMS do not support
+         * non-text content. If the charset is not set to UTF-8, it is safe to set the message as
+         * empty. We force the getMessage (see BluetoothMasClient) to only call getMessage with
+         * UTF-8 as the MCE is not obliged to support native charset.
+         */
+        if (!mBmsg.mBbodyCharset.equals("UTF-8")) {
+            Log.e(TAG, "The charset was not set to charset UTF-8: " + mBmsg.mBbodyCharset);
+        }
+
+        /*
          * <bmessage-body-content>::={ "BEGIN:MSG"<CRLF> 'message'<CRLF>
          * "END:MSG"<CRLF> }
          */
@@ -314,7 +331,11 @@
 
         if (prop != null) {
             if (prop.equals(END_MSG)) {
-                mBmsg.mMessage = new String(data, 0, messageLen);
+                if (mBmsg.mBbodyCharset.equals("UTF-8")) {
+                    mBmsg.mMessage = new String(data, 0, messageLen, StandardCharsets.UTF_8);
+                } else {
+                    mBmsg.mMessage = null;
+                }
             } else {
                 /* Handle possible exception for incorrect LENGTH value
                  * from MSE while parsing  GET Message response */
@@ -346,7 +367,11 @@
                 throw expected(END_MSG);
             }
 
-            mBmsg.mMessage = remng.substring(0, messageLen);
+            if (mBmsg.mBbodyCharset.equals("UTF-8")) {
+                mBmsg.mMessage = remng.substring(0, messageLen);
+            } else {
+                mBmsg.mMessage = null;
+            }
         }
 
         prop = mParser.next();
diff --git a/src/android/bluetooth/client/map/BluetoothMasClient.java b/src/android/bluetooth/client/map/BluetoothMasClient.java
index 7f71693..87f5a38 100644
--- a/src/android/bluetooth/client/map/BluetoothMasClient.java
+++ b/src/android/bluetooth/client/map/BluetoothMasClient.java
@@ -962,7 +962,7 @@
      * @return <code>true</code> if request has been sent, <code>false</code>
      *         otherwise
      */
-    public boolean getMessage(String handle, CharsetType charset, boolean attachment) {
+    public boolean getMessage(String handle, boolean attachment) {
         if (mObexSession == null) {
             return false;
         }
@@ -974,8 +974,10 @@
             return false;
         }
 
-        BluetoothMasRequest request = new BluetoothMasRequestGetMessage(handle, charset,
-                attachment);
+        // Since we support only text messaging via Bluetooth, it is OK to restrict the requests to
+        // force conversion to UTF-8.
+        BluetoothMasRequest request =
+            new BluetoothMasRequestGetMessage(handle, CharsetType.UTF_8, attachment);
         return mObexSession.makeRequest(request);
     }
 
diff --git a/src/android/bluetooth/client/map/BluetoothMasRequestGetMessage.java b/src/android/bluetooth/client/map/BluetoothMasRequestGetMessage.java
index b50fd0f..923bff0 100644
--- a/src/android/bluetooth/client/map/BluetoothMasRequestGetMessage.java
+++ b/src/android/bluetooth/client/map/BluetoothMasRequestGetMessage.java
@@ -25,6 +25,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 
 import javax.obex.ClientSession;
 import javax.obex.HeaderSet;
@@ -69,7 +71,17 @@
             Log.e(TAG, "I/O exception while reading response", e);
         }
 
-        String bmsg = baos.toString();
+        // Convert the input stream using UTF-8 since the attributes in the payload are all encoded
+        // according to it. The actual message body may need to be transcoded depending on
+        // charset/encoding defined for body-content.
+        String bmsg;
+        try {
+            bmsg = baos.toString(StandardCharsets.UTF_8.name());
+        } catch (UnsupportedEncodingException ex) {
+            Log.e(TAG,
+                "Coudn't decode the bmessage with UTF-8. Something must be really messed up.");
+            return;
+        }
 
         mBmessage = BluetoothMapBmessageParser.createBmessage(bmsg);