am e9428c35: am 7677468e: am 884362fe: am ada9e950: am 727741cd: Merge "Use pathPrefix filter instead of path for /btopp content" into jb-mr1-dev
* commit 'e9428c35344af989f9e643964a81e2dc0ce1ffe1':
Use pathPrefix filter instead of path for /btopp content
diff --git a/Android.mk b/Android.mk
index b0606df..4c24df9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,7 +10,7 @@
LOCAL_CERTIFICATE := platform
LOCAL_JNI_SHARED_LIBRARIES := libbluetooth_jni
-LOCAL_JAVA_LIBRARIES := javax.obex
+LOCAL_JAVA_LIBRARIES := javax.obex telephony-common mms-common
LOCAL_STATIC_JAVA_LIBRARIES := com.android.vcard
LOCAL_REQUIRED_MODULES := libbluetooth_jni bluetooth.default
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0c9857d..55c40a7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,6 +50,14 @@
<uses-permission android:name="android.permission.MANAGE_USERS"/>
<uses-permission android:name="com.google.android.gallery3d.permission.GALLERY_PROVIDER"/>
<uses-permission android:name="com.android.gallery3d.permission.GALLERY_PROVIDER"/>
+ <uses-permission android:name="android.permission.MMS_SEND_OUTBOX_MSG"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.WRITE_SMS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<!-- For PBAP Owner Vcard Info -->
<uses-permission android:name="android.permission.READ_PROFILE"/>
@@ -222,6 +230,14 @@
</receiver>
<service
android:process="@string/process"
+ android:name=".map.BluetoothMapService"
+ android:enabled="@bool/profile_supported_map" >
+ <intent-filter>
+ <action android:name="android.bluetooth.IBluetoothMap" />
+ </intent-filter>
+ </service>
+ <service
+ android:process="@string/process"
android:name = ".gatt.GattService"
android:enabled="@bool/profile_supported_gatt">
<intent-filter>
diff --git a/jni/com_android_bluetooth_avrcp.cpp b/jni/com_android_bluetooth_avrcp.cpp
index 6ff5cfa..c077bc6 100644
--- a/jni/com_android_bluetooth_avrcp.cpp
+++ b/jni/com_android_bluetooth_avrcp.cpp
@@ -26,9 +26,12 @@
#include <string.h>
namespace android {
+static jmethodID method_getRcFeatures;
static jmethodID method_getPlayStatus;
static jmethodID method_getElementAttr;
static jmethodID method_registerNotification;
+static jmethodID method_volumeChangeCallback;
+static jmethodID method_handlePassthroughCmd;
static const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
static jobject mCallbacksObj = NULL;
@@ -46,6 +49,26 @@
return true;
}
+static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr, btrc_remote_features_t features) {
+ ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
+ if (!checkCallbackThread()) {
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+ return;
+ }
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for connection state");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
static void btavrcp_get_play_status_callback() {
ALOGI("%s", __FUNCTION__);
@@ -92,8 +115,35 @@
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
+static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype) {
+ ALOGI("%s", __FUNCTION__);
+
+ if (!checkCallbackThread()) {
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, (jint)volume,
+ (jint)ctype);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
+static void btavrcp_passthrough_command_callback(int id, int pressed) {
+ ALOGI("%s", __FUNCTION__);
+
+ if (!checkCallbackThread()) {
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, (jint)id,
+ (jint)pressed);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
sizeof(sBluetoothAvrcpCallbacks),
+ btavrcp_remote_features_callback,
btavrcp_get_play_status_callback,
NULL,
NULL,
@@ -102,10 +152,14 @@
NULL,
NULL,
btavrcp_get_element_attr_callback,
- btavrcp_register_notification_callback
+ btavrcp_register_notification_callback,
+ btavrcp_volume_change_callback,
+ btavrcp_passthrough_command_callback
};
static void classInitNative(JNIEnv* env, jclass clazz) {
+ method_getRcFeatures =
+ env->GetMethodID(clazz, "getRcFeatures", "([BI)V");
method_getPlayStatus =
env->GetMethodID(clazz, "getPlayStatus", "()V");
@@ -115,6 +169,12 @@
method_registerNotification =
env->GetMethodID(clazz, "registerNotification", "(II)V");
+ method_volumeChangeCallback =
+ env->GetMethodID(clazz, "volumeChangeCallback", "(II)V");
+
+ method_handlePassthroughCmd =
+ env->GetMethodID(clazz, "handlePassthroughCmd", "(II)V");
+
ALOGI("%s: succeeds", __FUNCTION__);
}
@@ -318,6 +378,22 @@
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
+static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume) {
+ bt_status_t status;
+
+ //TODO: delete test code
+ ALOGI("%s: jint: %d, uint8_t: %u", __FUNCTION__, volume, (uint8_t) volume);
+
+ ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
+ if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+
+ if ((status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed set_volume, status: %d", status);
+ }
+
+ return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+}
+
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
{"initNative", "()V", (void *) initNative},
@@ -330,6 +406,8 @@
(void *) registerNotificationRspTrackChangeNative},
{"registerNotificationRspPlayPosNative", "(II)Z",
(void *) registerNotificationRspPlayPosNative},
+ {"setVolumeNative", "(I)Z",
+ (void *) setVolumeNative}
};
int register_com_android_bluetooth_avrcp(JNIEnv* env)
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index f6dde86..28de5ea 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -21,6 +21,7 @@
#include "utils/misc.h"
#include "cutils/properties.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/Log.h"
#include <string.h>
#include <pthread.h>
@@ -904,6 +905,20 @@
return -1;
}
+static jboolean configHciSnoopLogNative(JNIEnv* env, jobject obj, jboolean enable) {
+ ALOGV("%s:",__FUNCTION__);
+
+ jboolean result = JNI_FALSE;
+
+ if (!sBluetoothInterface) return result;
+
+ int ret = sBluetoothInterface->config_hci_snoop_log(enable);
+
+ result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+
+ return result;
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"classInitNative", "()V", (void *) classInitNative},
@@ -926,7 +941,8 @@
{"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative},
{"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative},
{"createSocketChannelNative", "(ILjava/lang/String;[BII)I",
- (void*) createSocketChannelNative}
+ (void*) createSocketChannelNative},
+ {"configHciSnoopLogNative", "(Z)Z", (void*) configHciSnoopLogNative}
};
int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env)
diff --git a/jni/com_android_bluetooth_gatt.cpp b/jni/com_android_bluetooth_gatt.cpp
index 207e643..854a925 100644
--- a/jni/com_android_bluetooth_gatt.cpp
+++ b/jni/com_android_bluetooth_gatt.cpp
@@ -44,14 +44,14 @@
#define UUID_PARAMS(uuid_ptr) \
uuid_lsb(uuid_ptr), uuid_msb(uuid_ptr)
-#define CHAR_ID_PARAMS(char_ptr) \
- char_ptr->inst_id, \
- UUID_PARAMS((&char_ptr->uuid))
+#define GATT_ID_PARAMS(attr_ptr) \
+ attr_ptr->inst_id, \
+ UUID_PARAMS((&attr_ptr->uuid))
#define SRVC_ID_PARAMS(srvc_ptr) \
(srvc_ptr->is_primary ? \
BTGATT_SERVICE_TYPE_PRIMARY : BTGATT_SERVICE_TYPE_SECONDARY), \
- CHAR_ID_PARAMS((&srvc_ptr->id))
+ GATT_ID_PARAMS((&srvc_ptr->id))
static void set_uuid(uint8_t* uuid, jlong uuid_msb, jlong uuid_lsb)
@@ -158,6 +158,7 @@
static jmethodID method_onGetIncludedService;
static jmethodID method_onRegisterForNotifications;
static jmethodID method_onReadRemoteRssi;
+static jmethodID method_onClientListen;
/**
* Server callback methods
@@ -273,24 +274,24 @@
}
void btgattc_get_characteristic_cb(int conn_id, int status,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
int char_prop)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetCharacteristic
- , conn_id, status, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id)
+ , conn_id, status, SRVC_ID_PARAMS(srvc_id), GATT_ID_PARAMS(char_id)
, char_prop);
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
void btgattc_get_descriptor_cb(int conn_id, int status,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
- bt_uuid_t *descr_id)
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *descr_id)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetDescriptor
- , conn_id, status, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id)
- , UUID_PARAMS(descr_id));
+ , conn_id, status, SRVC_ID_PARAMS(srvc_id), GATT_ID_PARAMS(char_id)
+ , GATT_ID_PARAMS(descr_id));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
@@ -304,11 +305,11 @@
}
void btgattc_register_for_notification_cb(int conn_id, int registered, int status,
- btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id)
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRegisterForNotifications
- , conn_id, status, registered, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id));
+ , conn_id, status, registered, SRVC_ID_PARAMS(srvc_id), GATT_ID_PARAMS(char_id));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
@@ -327,7 +328,7 @@
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNotify
, conn_id, address, SRVC_ID_PARAMS((&p_data->srvc_id))
- , CHAR_ID_PARAMS((&p_data->char_id)), p_data->is_notify, jb);
+ , GATT_ID_PARAMS((&p_data->char_id)), p_data->is_notify, jb);
sCallbackEnv->DeleteLocalRef(address);
sCallbackEnv->DeleteLocalRef(jb);
@@ -352,7 +353,7 @@
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadCharacteristic
, conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id))
- , CHAR_ID_PARAMS((&p_data->char_id)), p_data->value_type, jb);
+ , GATT_ID_PARAMS((&p_data->char_id)), p_data->value_type, jb);
sCallbackEnv->DeleteLocalRef(jb);
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
@@ -362,7 +363,7 @@
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteCharacteristic
, conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id))
- , CHAR_ID_PARAMS((&p_data->char_id)));
+ , GATT_ID_PARAMS((&p_data->char_id)));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
@@ -390,7 +391,7 @@
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadDescriptor
, conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id))
- , CHAR_ID_PARAMS((&p_data->char_id)), UUID_PARAMS((&p_data->descr_id))
+ , GATT_ID_PARAMS((&p_data->char_id)), GATT_ID_PARAMS((&p_data->descr_id))
, p_data->value_type, jb);
sCallbackEnv->DeleteLocalRef(jb);
@@ -402,7 +403,8 @@
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteDescriptor
, conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id))
- , CHAR_ID_PARAMS((&p_data->char_id)), UUID_PARAMS((&p_data->descr_id)));
+ , GATT_ID_PARAMS((&p_data->char_id))
+ , GATT_ID_PARAMS((&p_data->descr_id)));
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
@@ -421,6 +423,14 @@
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
}
+void btgattc_listen_cb(int status, int client_if)
+{
+ CHECK_CALLBACK_ENV
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientListen
+ , status, client_if);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
static const btgatt_client_callbacks_t sGattClientCallbacks = {
btgattc_register_app_cb,
btgattc_scan_result_cb,
@@ -438,7 +448,8 @@
btgattc_read_descriptor_cb,
btgattc_write_descriptor_cb,
btgattc_execute_write_cb,
- btgattc_remote_rssi_cb
+ btgattc_remote_rssi_cb,
+ btgattc_listen_cb
};
@@ -645,11 +656,11 @@
method_onExecuteCompleted = env->GetMethodID(clazz, "onExecuteCompleted", "(II)V");
method_onSearchCompleted = env->GetMethodID(clazz, "onSearchCompleted", "(II)V");
method_onSearchResult = env->GetMethodID(clazz, "onSearchResult", "(IIIJJ)V");
- method_onReadDescriptor = env->GetMethodID(clazz, "onReadDescriptor", "(IIIIJJIJJJJI[B)V");
- method_onWriteDescriptor = env->GetMethodID(clazz, "onWriteDescriptor", "(IIIIJJIJJJJ)V");
+ method_onReadDescriptor = env->GetMethodID(clazz, "onReadDescriptor", "(IIIIJJIJJIJJI[B)V");
+ method_onWriteDescriptor = env->GetMethodID(clazz, "onWriteDescriptor", "(IIIIJJIJJIJJ)V");
method_onNotify = env->GetMethodID(clazz, "onNotify", "(ILjava/lang/String;IIJJIJJZ[B)V");
method_onGetCharacteristic = env->GetMethodID(clazz, "onGetCharacteristic", "(IIIIJJIJJI)V");
- method_onGetDescriptor = env->GetMethodID(clazz, "onGetDescriptor", "(IIIIJJIJJJJ)V");
+ method_onGetDescriptor = env->GetMethodID(clazz, "onGetDescriptor", "(IIIIJJIJJIJJ)V");
method_onGetIncludedService = env->GetMethodID(clazz, "onGetIncludedService", "(IIIIJJIIJJ)V");
method_onRegisterForNotifications = env->GetMethodID(clazz, "onRegisterForNotifications", "(IIIIIJJIJJ)V");
method_onReadRemoteRssi = env->GetMethodID(clazz, "onReadRemoteRssi", "(ILjava/lang/String;II)V");
@@ -669,6 +680,7 @@
method_onAttributeRead= env->GetMethodID(clazz, "onAttributeRead", "(Ljava/lang/String;IIIIZ)V");
method_onAttributeWrite= env->GetMethodID(clazz, "onAttributeWrite", "(Ljava/lang/String;IIIIIZZ[B)V");
method_onExecuteWrite= env->GetMethodID(clazz, "onExecuteWrite", "(Ljava/lang/String;III)V");
+ method_onClientListen = env->GetMethodID(clazz, "onClientListen", "(II)V");
info("classInitNative: Success!");
}
@@ -816,7 +828,7 @@
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
@@ -834,6 +846,7 @@
jlong service_id_uuid_lsb, jlong service_id_uuid_msb,
jint char_id_inst_id,
jlong char_id_uuid_lsb, jlong char_id_uuid_msb,
+ jint descr_id_inst_id,
jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb)
{
if (!sGattIf) return;
@@ -843,12 +856,13 @@
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
- bt_uuid_t descr_id;
- set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
+ btgatt_gatt_id_t descr_id;
+ descr_id.inst_id = (uint8_t) descr_id_inst_id;
+ set_uuid(descr_id.uuid.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
if (descr_id_uuid_lsb == 0)
{
@@ -898,7 +912,7 @@
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
@@ -910,6 +924,7 @@
jlong service_id_uuid_lsb, jlong service_id_uuid_msb,
jint char_id_inst_id,
jlong char_id_uuid_lsb, jlong char_id_uuid_msb,
+ jint descr_id_inst_id,
jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb,
jint authReq)
{
@@ -920,12 +935,13 @@
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
- bt_uuid_t descr_id;
- set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
+ btgatt_gatt_id_t descr_id;
+ descr_id.inst_id = (uint8_t) descr_id_inst_id;
+ set_uuid(descr_id.uuid.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
sGattIf->client->read_descriptor(conn_id, &srvc_id, &char_id, &descr_id, authReq);
}
@@ -944,7 +960,7 @@
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
@@ -969,22 +985,29 @@
jlong service_id_uuid_lsb, jlong service_id_uuid_msb,
jint char_id_inst_id,
jlong char_id_uuid_lsb, jlong char_id_uuid_msb,
+ jint descr_id_inst_id,
jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb,
jint write_type, jint auth_req, jbyteArray value)
{
if (!sGattIf) return;
+ if (value == NULL) {
+ warn("gattClientWriteDescriptorNative() ignoring NULL array");
+ return;
+ }
+
btgatt_srvc_id_t srvc_id;
srvc_id.id.inst_id = (uint8_t) service_id_inst_id;
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
- bt_uuid_t descr_id;
- set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
+ btgatt_gatt_id_t descr_id;
+ descr_id.inst_id = (uint8_t) descr_id_inst_id;
+ set_uuid(descr_id.uuid.uu, descr_id_uuid_msb, descr_id_uuid_lsb);
uint16_t len = (uint16_t) env->GetArrayLength(value);
jbyte *p_value = env->GetByteArrayElements(value, NULL);
@@ -1010,7 +1033,7 @@
srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0);
set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb);
- btgatt_char_id_t char_id;
+ btgatt_gatt_id_t char_id;
char_id.inst_id = (uint8_t) char_id_inst_id;
set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb);
@@ -1035,6 +1058,27 @@
sGattIf->client->read_remote_rssi(clientif, &bda);
}
+static void gattClientListenNative(JNIEnv *env, jobject object,
+ jint client_if, jboolean start)
+{
+ if (!sGattIf) return;
+ sGattIf->client->listen(client_if, start);
+}
+
+static void gattSetAdvDataNative(JNIEnv *env, jobject object, jint client_if, jboolean setScanRsp,
+ jboolean inclName, jboolean inclTxPower, jint minInterval, jint maxInterval, jint appearance,
+ jbyteArray manufacturerData)
+{
+ if (!sGattIf) return;
+ jbyte* arr_data = env->GetByteArrayElements(manufacturerData, 0);
+ uint16_t arr_len = (uint16_t) env->GetArrayLength(manufacturerData);
+
+ sGattIf->client->set_adv_data(client_if, setScanRsp, inclName, inclTxPower,
+ minInterval, maxInterval, appearance, arr_len, (char*)arr_data);
+
+ env->ReleaseByteArrayElements(manufacturerData, arr_data, JNI_ABORT);
+}
+
/**
* Native server functions
@@ -1239,15 +1283,16 @@
{"gattClientRefreshNative", "(ILjava/lang/String;)V", (void *) gattClientRefreshNative},
{"gattClientSearchServiceNative", "(IZJJ)V", (void *) gattClientSearchServiceNative},
{"gattClientGetCharacteristicNative", "(IIIJJIJJ)V", (void *) gattClientGetCharacteristicNative},
- {"gattClientGetDescriptorNative", "(IIIJJIJJJJ)V", (void *) gattClientGetDescriptorNative},
+ {"gattClientGetDescriptorNative", "(IIIJJIJJIJJ)V", (void *) gattClientGetDescriptorNative},
{"gattClientGetIncludedServiceNative", "(IIIJJIIJJ)V", (void *) gattClientGetIncludedServiceNative},
{"gattClientReadCharacteristicNative", "(IIIJJIJJI)V", (void *) gattClientReadCharacteristicNative},
- {"gattClientReadDescriptorNative", "(IIIJJIJJJJI)V", (void *) gattClientReadDescriptorNative},
+ {"gattClientReadDescriptorNative", "(IIIJJIJJIJJI)V", (void *) gattClientReadDescriptorNative},
{"gattClientWriteCharacteristicNative", "(IIIJJIJJII[B)V", (void *) gattClientWriteCharacteristicNative},
- {"gattClientWriteDescriptorNative", "(IIIJJIJJJJII[B)V", (void *) gattClientWriteDescriptorNative},
+ {"gattClientWriteDescriptorNative", "(IIIJJIJJIJJII[B)V", (void *) gattClientWriteDescriptorNative},
{"gattClientExecuteWriteNative", "(IZ)V", (void *) gattClientExecuteWriteNative},
{"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IIJJIJJZ)V", (void *) gattClientRegisterForNotificationsNative},
{"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", (void *) gattClientReadRemoteRssiNative},
+ {"gattClientListenNative", "(IZ)V", (void *) gattClientListenNative},
{"gattServerRegisterAppNative", "(JJ)V", (void *) gattServerRegisterAppNative},
{"gattServerUnregisterAppNative", "(I)V", (void *) gattServerUnregisterAppNative},
@@ -1264,6 +1309,7 @@
{"gattServerSendNotificationNative", "(III[B)V", (void *) gattServerSendNotificationNative},
{"gattServerSendResponseNative", "(IIIIII[BI)V", (void *) gattServerSendResponseNative},
+ {"gattSetAdvDataNative", "(IZZZIII[B)V", (void *) gattSetAdvDataNative},
{"gattTestNative", "(IJJLjava/lang/String;IIIII)V", (void *) gattTestNative},
};
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index be51cc5..d51b94e 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Kanselleer"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Skakel aan"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Lêeroordrag"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" wil <xliff:g id="FILE">%2$s</xliff:g> vir jou stuur (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Aanvaar die lêer?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" wil <xliff:g id="FILE">%2$s</xliff:g> vir jou stuur (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Aanvaar die lêer?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Wys af"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Aanvaar"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Maak toe"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Onbekende lêer"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Daar is geen program om hierdie tipe lêer te hanteer nie. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Daar is geen program om hierdie tipe lêer te hanteer nie. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Geen lêers nie"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Die lêer bestaan nie. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Die lêer bestaan nie. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Wag asseblief…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Skakel tans Bluetooth aan…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Die lêer sal ontvang word. Kontroleer vordering in die Kennisgewings-paneel."</string>
diff --git a/res/values-af/strings_map.xml b/res/values-af/strings_map.xml
new file mode 100644
index 0000000..0ac25e1
--- /dev/null
+++ b/res/values-af/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Tik sessiesleutel in vir %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-sessiesleutel word benodig"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Die tyd het verstryk om verbinding met %1$s te aanvaar"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Die tyd om die sessiesleutel vir %1$s in te tik, het uitgetel"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex-stawingsversoek"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sessiesleutel"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Tik sessiesleutel in vir %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Motortoebehore"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Onbekende naam"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"My naam"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 914854b..82222ba 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -30,10 +30,10 @@
<string name="bt_enable_title" msgid="8657832550503456572"></string>
<string name="bt_enable_line1" msgid="7203551583048149">"የብሉቱዝ አገልግሎት ለመጠቀም፣ መጀመሪያ ብሉቱዝን ያብሩ።"</string>
<string name="bt_enable_line2" msgid="4341936569415937994">"ብሉቱዝ አሁን ይብራ?"</string>
- <string name="bt_enable_cancel" msgid="1988832367505151727">"ይቅር"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"ሰርዝ"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"አብራ"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"ፋይልሰደዳ"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>) ሊልኩልዎ ይፈልጋሉ፡ "\n\n" ፋይል ይቀበሉ?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>) ሊልኩልዎ ይፈልጋሉ፡ \n\n ፋይል ይቀበሉ?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"አትቀበል"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"ተቀበል"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"እሺ"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"ዝጋ"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"እሺ"</string>
<string name="unknown_file" msgid="6092727753965095366">"ያልታወቀ ፋይል"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"ይህን ዓይነቱን ፋይል ለማስተናገድ የሚችል መተግበሪያ የለም:: "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"ይህን ዓይነቱን ፋይል ለማስተናገድ የሚችል መተግበሪያ የለም:: \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"ምንም ፋይሎች የሉም፡፡"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"ፋይል የለም:: "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"ፋይል የለም:: \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"እባክዎ ይጠብቁ…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"ብሉቱዝ በማብራት ላይ..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"ፋይሉ ይደርሳል።በማሳወቂያ ውስን ቦታ ውስጥ ሂደቱን ይመልከቱ።"</string>
diff --git a/res/values-am/strings_map.xml b/res/values-am/strings_map.xml
new file mode 100644
index 0000000..064a88e
--- /dev/null
+++ b/res/values-am/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"ለ%1$s የክፍለ ጊዜ ቁልፍ ይተይቡ"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"የብሉቱዝ ክፍለ ጊዜ ቁልፍ ያስፈልጋል"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"ከ%1$s ግንኙነት ለመቀበል ጊዜው አብቅቶ ነበር።"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"ከ%1$s ጋር የክፍለ ጊዜ ቁልፍ ለማስገባት ጊዜው አለቆ ነበር።"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex ማረጋገጫ ጥያቄ"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"የክፍለ ጊዜ ቁልፍ"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"ለ%1$s የክፍለ ጊዜ ቁልፍ ይተይቡ"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"የመኪና መሣሪያ"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"ያልታወቀ ስም"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"የእኔ ስም"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 537e8fa..a98dda7 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permlab_bluetoothShareManager" msgid="311492132450338925">"الدخول إلى إدارة التنزيل."</string>
- <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"للسماح للتطبيق بالدخول إلى إدارة BluetoothShare واستخدامها لنقل الملفات."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"للسماح للتطبيق بالدخول إلى إدارة BluetoothShare واستخدامها لنقل الملفات."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"إضافة وصول جهاز بلوتوث إلى القائمة البيضاء."</string>
<string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"يسمح للتطبيق مؤقتًا بإضافة جهاز بلوتوث إلى القائمة البيضاء مما يتيح لذلك الجهاز إرسال ملفات إلى هذا الجهاز بدون تأكيد المستخدم."</string>
<string name="permlab_handoverStatus" msgid="7316032998801933554">"استلام عمليات البث المتعلقة بنقل إمكانية التحكم عبر البلوتوث."</string>
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"إلغاء"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"تشغيل"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"نقل الملف"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"يريد \"<xliff:g id="SENDER">%1$s</xliff:g>\" إرسال <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) لك. "\n\n" هل تقبل الملف؟"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"يريد \"<xliff:g id="SENDER">%1$s</xliff:g>\" إرسال <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) لك. \n\n هل تقبل الملف؟"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"رفض"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"قبول"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"موافق"</string>
@@ -73,19 +73,19 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"إغلاق"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"موافق"</string>
<string name="unknown_file" msgid="6092727753965095366">"ملف غير معروف"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"ليس هناك تطبيق لمعالجة هذا النوع من الملفات. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"ليس هناك تطبيق لمعالجة هذا النوع من الملفات. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"ليست هناك أية ملفات"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"الملف غير موجود. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"الملف غير موجود. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"يرجى الانتظار…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"جارٍ تشغيل البلوتوث..."</string>
- <string name="bt_toast_1" msgid="972182708034353383">"سيتم استلام الملف. تحقق من التقدم في لوحة التنبيهات."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"سيتم استلام الملف. تحقق من التقدم في لوحة الإشعارات."</string>
<string name="bt_toast_2" msgid="8602553334099066582">"لا يمكن تلقي الملف."</string>
<string name="bt_toast_3" msgid="6707884165086862518">"تم إيقاف استلام الملف من \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
<string name="bt_toast_4" msgid="4678812947604395649">"إرسال الملف إلى \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
<string name="bt_toast_5" msgid="2846870992823019494">"إرسال <xliff:g id="NUMBER">%1$s</xliff:g> من الملفات إلى \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
<string name="bt_toast_6" msgid="1855266596936622458">"تم إيقاف إرسال الملف إلى \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
- <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"لا توجد مساحة كافية على وحدة تخزين USB لحفظ الملف من \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
- <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"لا توجد مساحة كافية على بطاقة SD لحفظ الملف من \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"لا توجد مساحة كافية على وحدة تخزين USB لحفظ الملف من \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"لا توجد مساحة كافية على بطاقة SD لحفظ الملف من \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
<string name="bt_sm_2_2" msgid="2965243265852680543">"المساحة اللازمة: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="ErrorTooManyRequests" msgid="8578277541472944529">"تتم حاليًا معالجة طلبات كثيرة جدًا. حاول مرة أخرى لاحقًا."</string>
<string name="status_pending" msgid="2503691772030877944">"لم يبدأ نقل الملف بعد."</string>
@@ -95,8 +95,8 @@
<string name="status_forbidden" msgid="613956401054050725">"تم حظر النقل بواسطة الجهاز الهدف."</string>
<string name="status_canceled" msgid="6664490318773098285">"تم إلغاء النقل بواسطة المستخدم."</string>
<string name="status_file_error" msgid="3671917770630165299">"مشكلة في وحدة التخزين."</string>
- <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"ليس هناك وحدة تخزين USB."</string>
- <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"ليس هناك بطاقة SD. أدرج بطاقة SD لحفظ الملفات المنقولة."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"ليس هناك وحدة تخزين USB."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"ليس هناك بطاقة SD. أدرج بطاقة SD لحفظ الملفات المنقولة."</string>
<string name="status_connection_error" msgid="947681831523219891">"لم يتم الاتصال بنجاح."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"لا يمكن معالجة الطلب بشكل صحيح."</string>
<string name="status_unknown_error" msgid="8156660554237824912">"خطأ غير معروف."</string>
diff --git a/res/values-ar/strings_map.xml b/res/values-ar/strings_map.xml
new file mode 100644
index 0000000..baed8c0
--- /dev/null
+++ b/res/values-ar/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"اكتب مفتاح الجلسة لـ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"يلزم مفتاح جلسة البلوتوث"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"انتهت مهلة قبول الاتصال مع %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"انتهت مهلة إدخال مفتاح الجلسة مع %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"طلب مصادقة Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"مفتاح الجلسة"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"اكتب مفتاح الجلسة لـ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"مجموعة أدوات السيارة"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"اسم غير معروف"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"اسمي"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ar/strings_pbap.xml b/res/values-ar/strings_pbap.xml
index c41a2b1..7dee306 100644
--- a/res/values-ar/strings_pbap.xml
+++ b/res/values-ar/strings_pbap.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"اكتب مفتاح الجلسة لـ %1$s"</string>
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"اكتب مفتاح الجلسة لـ %1$s"</string>
<string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"يلزم مفتاح جلسة البلوتوث"</string>
- <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"انتهت مهلة قبول الاتصال مع %1$s"</string>
- <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"انتهت مهلة إدخال مفتاح الجلسة مع %1$s"</string>
- <string name="auth_notif_ticker" msgid="1575825798053163744">"طلب مصادقة Obex"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"انتهت مهلة قبول الاتصال مع %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"انتهت مهلة إدخال مفتاح الجلسة مع %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"طلب مصادقة Obex"</string>
<string name="auth_notif_title" msgid="7599854855681573258">"مفتاح الجلسة"</string>
- <string name="auth_notif_message" msgid="6667218116427605038">"اكتب مفتاح الجلسة لـ %1$s"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"اكتب مفتاح الجلسة لـ %1$s"</string>
<string name="defaultname" msgid="4821590500649090078">"مجموعة أدوات السيارة"</string>
<string name="unknownName" msgid="2841414754740600042">"اسم غير معروف"</string>
<string name="localPhoneName" msgid="2349001318925409159">"اسمي"</string>
diff --git a/res/values-ar/test_strings.xml b/res/values-ar/test_strings.xml
index 6f5d316..1b2b49c 100644
--- a/res/values-ar/test_strings.xml
+++ b/res/values-ar/test_strings.xml
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hello" msgid="1740533743008967039">"مرحبًا بالضيوف، TestActivity"</string>
+ <string name="hello" msgid="1740533743008967039">"مرحبًا بالضيوف، TestActivity"</string>
<string name="app_name" msgid="1203877025577761792">"مشاركة البلوتوث"</string>
<string name="insert_record" msgid="1450997173838378132">"إدراج سجل"</string>
<string name="update_record" msgid="2480425402384910635">"تأكيد السجل"</string>
- <string name="ack_record" msgid="6716152390978472184">"سجل Ack"</string>
+ <string name="ack_record" msgid="6716152390978472184">"سجل Ack"</string>
<string name="deleteAll_record" msgid="4383349788485210582">"حذف السجل كله"</string>
<string name="ok_button" msgid="6519033415223065454">"موافق"</string>
<string name="delete_record" msgid="4645040331967533724">"حذف السجل"</string>
- <string name="start_server" msgid="9034821924409165795">"بدء الخادم TCP"</string>
- <string name="notify_server" msgid="4369106744022969655">"إعلام الخادم TCP"</string>
+ <string name="start_server" msgid="9034821924409165795">"بدء الخادم TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"إعلام الخادم TCP"</string>
</resources>
diff --git a/res/values-az-rAZ/strings_map.xml b/res/values-az-rAZ/strings_map.xml
new file mode 100644
index 0000000..0b8584e
--- /dev/null
+++ b/res/values-az-rAZ/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s üçün seans açarı daxil edin"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth seans açarı tələb olunur"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s ilə bağlantı qəbul edərkən fasilə yarandı"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s ilə seans açarını daxil edərkən fasilə yarandı"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex təsdiqləmə sorğusu"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Seans Açarı"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s üçün seans açarı daxil edin"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Maşın dəsti"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Naməlum ad"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mənim adım"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-az/strings_map.xml b/res/values-az/strings_map.xml
new file mode 100644
index 0000000..0b8584e
--- /dev/null
+++ b/res/values-az/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s üçün seans açarı daxil edin"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth seans açarı tələb olunur"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s ilə bağlantı qəbul edərkən fasilə yarandı"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s ilə seans açarını daxil edərkən fasilə yarandı"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex təsdiqləmə sorğusu"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Seans Açarı"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s üçün seans açarı daxil edin"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Maşın dəsti"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Naməlum ad"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mənim adım"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 74b93e7..7b3810b 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Адмяніць"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Уключыць"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Перадача файлаў"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Адпраўнік \"<xliff:g id="SENDER">%1$s</xliff:g>\" хоча адправіць вам файл <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Прыняць?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Адпраўнік \"<xliff:g id="SENDER">%1$s</xliff:g>\" хоча адправіць вам файл <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Прыняць?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Адхіліць"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Прыняць"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ОК"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Закрыць"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"ОК"</string>
<string name="unknown_file" msgid="6092727753965095366">"Невядомы файл"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Няма прыкладанняў для апрацоўкі файлаў гэтага тыпу. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Няма прыкладанняў для апрацоўкі файлаў гэтага тыпу. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"няма файла"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не існуе. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не існуе. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Чакайце..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Уключэнне Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Файл будзе атрыманы. Сачыце за прагрэсам на панэлі апавяшчэнняў."</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 62e2e0f..216ad2e 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Отказ"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Включване"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Прехвърляне на файл"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>“ иска да ви изпрати <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Приемате ли файла?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>“ иска да ви изпрати <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Приемате ли файла?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Отхвърляне"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Приемане"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Затваряне"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Неизвестен файл"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Няма приложение, което работи с този тип файлове. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Няма приложение, което работи с този тип файлове. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Няма файл"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Файлът не съществува. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Файлът не съществува. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Моля, изчакайте…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth се включва..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Файлът ще бъде получен. Проверете хода в панела за известия."</string>
diff --git a/res/values-bg/strings_map.xml b/res/values-bg/strings_map.xml
new file mode 100644
index 0000000..7e7250a
--- /dev/null
+++ b/res/values-bg/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Въведете ключ за сесия за %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Изисква се ключ за сесия с Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Времето за изчакване за приемане на връзката с/ъс %1$s изтече"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Времето за изчакване за въвеждане на ключ за сесия със %1$s изтече"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Заявка за удостоверяване на Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ключ за сесия"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Въведете ключ за сесия за %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Комплект за автомобил"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Неизвестно име"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Моето име"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index e585b94..b922e64 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancel·la"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activa"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferència del fitxer"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" et vol enviar <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Acceptes el fitxer?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" et vol enviar <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Acceptes el fitxer?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Rebutja"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accepta"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"D\'acord"</string>
@@ -42,7 +42,7 @@
<string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Vols rebre aquest fitxer?"</string>
<string name="incoming_file_toast_msg" msgid="1733710749992901811">"Està entrant un fitxer d\'un altre dispositiu. Confirma que vols rebre el fitxer."</string>
<string name="notification_receiving" msgid="4674648179652543984">"Ús compartit de Bluetooth: s\'està rebent <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_received" msgid="3324588019186687985">"Ús compartit de Bluetooth: s\'ha rebut <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Compartir amb Bluetooth: <xliff:g id="FILE">%1$s</xliff:g> rebut"</string>
<string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth compartit: fitxer <xliff:g id="FILE">%1$s</xliff:g> no rebut"</string>
<string name="notification_sending" msgid="3035748958534983833">"Ús compartit de Bluetooth: s\'està enviant <xliff:g id="FILE">%1$s</xliff:g>"</string>
<string name="notification_sent" msgid="9218710861333027778">"Ús compartit de Bluetooth: s\'ha enviat <xliff:g id="FILE">%1$s</xliff:g>"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Tanca"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"D\'acord"</string>
<string name="unknown_file" msgid="6092727753965095366">"Fitxer desconegut"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"No hi ha cap aplicació per gestionar aquest tipus de fitxer. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"No hi ha cap aplicació per gestionar aquest tipus de fitxer. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Cap fitxer"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"El fitxer no existeix. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"El fitxer no existeix. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Espereu…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"S\'està activant el Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"El fitxer es rebrà. Comproveu-ne el progrés al tauler de notificacions."</string>
@@ -100,7 +100,7 @@
<string name="status_connection_error" msgid="947681831523219891">"Connexió incorrecta."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"La sol·licitud no es pot processar correctament."</string>
<string name="status_unknown_error" msgid="8156660554237824912">"Error desconegut."</string>
- <string name="btopp_live_folder" msgid="7967791481444474554">"S\'ha rebut Bluetooth"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Rebut per Bluetooth"</string>
<string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g>: recepció completa."</string>
<string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g>: enviament complet."</string>
<string name="inbound_history_title" msgid="6940914942271327563">"Transferències d\'entrada"</string>
diff --git a/res/values-ca/strings_map.xml b/res/values-ca/strings_map.xml
new file mode 100644
index 0000000..e63faa2
--- /dev/null
+++ b/res/values-ca/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Introdueix la clau de sessió per a %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Es necessita la clau de sessió Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"S\'ha esgotat el temps per acceptar la connexió amb %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"S\'ha esgotat el temps per a l\'entrada de la clau de sessió amb %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Sol·licitud d\'autenticació Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Clau de sessió"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Introdueix la clau de sessió per a %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Equip per a l\'automòbil"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nom desconegut"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"El meu nom"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 8805e2a..50e5da8 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Zrušit"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Zapnout"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Přenos souborů"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Uživatel <xliff:g id="SENDER">%1$s</xliff:g> se vám pokouší odeslat soubor <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Chcete soubor přijmout?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Uživatel <xliff:g id="SENDER">%1$s</xliff:g> se vám pokouší odeslat soubor <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Chcete soubor přijmout?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Odmítnout"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Přijmout"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Zavřít"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Neznámý soubor"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Žádná aplikace nedokáže s tímto typem souboru pracovat. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Žádná aplikace nedokáže s tímto typem souboru pracovat. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Žádný soubor"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Soubor neexistuje. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Soubor neexistuje. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Čekejte prosím..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Zapínání Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Proběhne přijímání souboru. Průběh můžete sledovat na panelu Oznámení."</string>
diff --git a/res/values-cs/strings_map.xml b/res/values-cs/strings_map.xml
new file mode 100644
index 0000000..f8ee413
--- /dev/null
+++ b/res/values-cs/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Zadejte klíč relace pro zařízení %1$s."</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Je požadován klíč relace Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Časový limit pro přijetí spojení se zařízením %1$s vypršel."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Časový limit zadání klíče relace pro %1$s vypršel."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Požadavek ověření Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Klíč relace"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Zadejte klíč relace pro zařízení %1$s."</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Sada handsfree do auta"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Neznámý název"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mé jméno"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index ae13ba5..ef515d3 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Annuller"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Slå til"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Filoverførsel"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vil sende <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) til dig. "\n\n" Vil du modtage filen?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vil sende <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) til dig. \n\n Vil du modtage filen?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Afvis"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accepter"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,12 +73,12 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Luk"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Ukendt fil"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Der er ingen app til at håndtere denne filtype. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Der er ingen app til at håndtere denne filtype. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ingen fil"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen findes ikke. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen findes ikke. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Vent..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Aktiverer Bluetooth..."</string>
- <string name="bt_toast_1" msgid="972182708034353383">"Filen modtages. Se status i meddelelsespanelet."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"Filen modtages. Se status i underretningspanelet."</string>
<string name="bt_toast_2" msgid="8602553334099066582">"Filen kan ikke modtages."</string>
<string name="bt_toast_3" msgid="6707884165086862518">"Modtagelse af fil fra \"<xliff:g id="SENDER">%1$s</xliff:g>\" stoppet"</string>
<string name="bt_toast_4" msgid="4678812947604395649">"Sender filen til \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
diff --git a/res/values-da/strings_map.xml b/res/values-da/strings_map.xml
new file mode 100644
index 0000000..3adec1c
--- /dev/null
+++ b/res/values-da/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Indtast sessionsnøgle til %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-sessionsnøgle kræves"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Der var timeout ved forbindelsen med %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Der opstod timeout i indgangssessionnøgle med %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Anmodning om Obex-godkendelse"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sessionstast"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Indtast sessionsnøgle til %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Bilsæt"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Ukendt navn"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mit navn"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 8d01f8e..fe1194f 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -18,8 +18,8 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Auf Download-Manager zugreifen"</string>
<string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Ermöglicht der App, auf den Bluetooth-Weiterleitungs-Manager zuzugreifen und diesen für die Übertragung von Dateien zu verwenden."</string>
- <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Bluetooth-Gerät für Zugriff zur Whitelist hinzufügen"</string>
- <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Ermöglicht der App, ein Bluetooth-Gerät vorübergehend zur Whitelist hinzuzufügen, sodass es ohne Bestätigung des Nutzers Dateien an dieses Gerät senden kann"</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Bluetooth-Gerät für Zugriff zur weißen Liste hinzufügen"</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Ermöglicht der App, ein Bluetooth-Gerät vorübergehend zur weißen Liste hinzuzufügen, sodass es ohne Bestätigung des Nutzers Dateien an dieses Gerät senden kann"</string>
<string name="permlab_handoverStatus" msgid="7316032998801933554">"Bluetooth-Broadcasts zur Übertragung empfangen"</string>
<string name="permdesc_handoverStatus" msgid="4752738070064786310">"Ermöglicht den Empfang von Statusinformationen zur Übertragung per Bluetooth"</string>
<string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Abbrechen"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Aktivieren"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Dateiübertragung"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" möchte Ihnen <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) senden. "\n\n" Datei annehmen?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" möchte Ihnen <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) senden. \n\n Datei annehmen?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Ablehnen"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Akzeptieren"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Schließen"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Unbekannte Datei"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Dieser Dateityp kann von keiner App verarbeitet werden. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Dieser Dateityp kann von keiner App verarbeitet werden. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Keine Datei"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Die Datei ist nicht vorhanden. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Die Datei ist nicht vorhanden. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Bitte warten..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth wird aktiviert..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Die Datei wird empfangen. Überprüfen Sie den Fortschritt in der Benachrichtigungskonsole."</string>
diff --git a/res/values-de/strings_map.xml b/res/values-de/strings_map.xml
new file mode 100644
index 0000000..ed6f4ed
--- /dev/null
+++ b/res/values-de/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Sitzungsschlüssel für %1$s eingeben"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-Sitzungsschlüssel erforderlich"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Die Zeit zum Verbindungsaufbau mit %1$s ist abgelaufen."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Die Zeit zur Eingabe des Sitzungsschlüssels bei %1$s ist abgelaufen."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"OBEX-Authentifizierungsanfrage"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sitzungsschlüssel"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Sitzungsschlüssel für %1$s eingeben"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Unbekannter Name"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mein Name"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 3f3c834..014756c 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Ακύρωση"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Ενεργοποίηση"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Μεταφορά αρχείου"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Ο αποστολέας \"<xliff:g id="SENDER">%1$s</xliff:g>\" θέλει να σας στείλει το <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Αποδοχή του αρχείου;"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Ο αποστολέας \"<xliff:g id="SENDER">%1$s</xliff:g>\" θέλει να σας στείλει το <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Αποδοχή του αρχείου;"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Απόρριψη"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Αποδοχή"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Κλείσιμο"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"ΟΚ"</string>
<string name="unknown_file" msgid="6092727753965095366">"Άγνωστο αρχείο"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Δεν υπάρχει καμία εφαρμογή για τη διαχείριση αυτού του τύπου αρχείου. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Δεν υπάρχει καμία εφαρμογή για τη διαχείριση αυτού του τύπου αρχείου. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Κανένα αρχείο"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Το αρχείο δεν υπάρχει. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Το αρχείο δεν υπάρχει. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Περιμένετε..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Ενεργοποίηση Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Θα γίνει λήψη του αρχείου. Ελέγξτε την πρόοδο στο πλαίσιο \"Ειδοποιήσεις\"."</string>
diff --git a/res/values-el/strings_map.xml b/res/values-el/strings_map.xml
new file mode 100644
index 0000000..62cf54d
--- /dev/null
+++ b/res/values-el/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Πληκτρολογήστε το κλειδί περιόδου σύνδεσης για %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Απαιτείται κλειδί περιόδου σύνδεσης Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Έγινε λήξη χρονικού ορίου για την αποδοχή της σύνδεσης με %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Έγινε λήξη χρονικού ορίου για την εισαγωγή κλειδιού περιόδου σύνδεσης με %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Αίτημα ελέγχου ταυτότητας Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Κλειδί περιόδου σύνδεσης"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Πληκτρολογήστε το κλειδί περιόδου σύνδεσης για %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Κιτ αυτοκινήτου"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Άγνωστο όνομα"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Το όνομά μου"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 47ebdee..6141acf 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancel"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Turn on"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"File transfer"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" wants to send you <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Accept the file?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" wants to send you <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Accept the file?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Decline"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accept"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Close"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Unknown file"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"There\'s no app to handle this type of file. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"There\'s no app to handle this type of file. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"No file"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"The file doesn\'t exist. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"The file doesn\'t exist. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Please wait…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Turning on Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"The file will be received. Check progress in the Notifications panel."</string>
diff --git a/res/values-en-rGB/strings_map.xml b/res/values-en-rGB/strings_map.xml
new file mode 100644
index 0000000..0807e6e
--- /dev/null
+++ b/res/values-en-rGB/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Type session key for %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth session key required"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"There was time out to accept connection with %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"There was time out to input session key with %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex authentication request"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Session Key"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Type session key for %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Car Kit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Unknown name"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"My name"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..6141acf
--- /dev/null
+++ b/res/values-en-rIN/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Access download manager."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Allows the application to access the Bluetooth Share manager and to use it to transfer files."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Whitelist bluetooth device access."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Allows the app to temporarily whitelist a Bluetooth device, allowing that device to send files to this device without user confirmation."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"Receive BT handover transfer broadcasts."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Allows receiving handover transfer status information from Bluetooth."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Unknown device"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Unknown"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Aeroplane mode"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"You can\'t use Bluetooth in Aeroplane mode."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"To use Bluetooth services, you must first turn on Bluetooth."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Turn on Bluetooth now?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Cancel"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Turn on"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"File transfer"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" wants to send you <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Accept the file?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Decline"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accept"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"There was a timeout while accepting an incoming file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth share: Incoming file"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Do you want to receive this file?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Incoming file from another device. Confirm that you want to receive this file."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Bluetooth share: Receiving <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Bluetooth share: Received <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth share: File <xliff:g id="FILE">%1$s</xliff:g> not received"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Bluetooth share: Sending <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Bluetooth share: Sent <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100% complete"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetooth share: File <xliff:g id="FILE">%1$s</xliff:g> not sent"</string>
+ <string name="download_title" msgid="3353228219772092586">"File transfer"</string>
+ <string name="download_line1" msgid="4926604799202134144">"From: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"File size: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Receiving file…"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Stop"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Hide"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"File not received"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Reason: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"File received"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Open"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"To: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"File type: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Sending file…"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"File sent"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"The file wasn\'t sent to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\"."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"File: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Try again"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Close"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Unknown file"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"There\'s no app to handle this type of file. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"No file"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"The file doesn\'t exist. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Please wait…"</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Turning on Bluetooth…"</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"The file will be received. Check progress in the Notifications panel."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"The file can\'t be received."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"Stopped receiving file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"Sending file to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"Sending <xliff:g id="NUMBER">%1$s</xliff:g> files to \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"Stopped sending file to \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"There isn\'t enough space in USB storage to save the file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"There isn\'t enough space on the SD card to save the file from \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Space needed: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Too many requests are being processed. Try again later."</string>
+ <string name="status_pending" msgid="2503691772030877944">"File transfer not started yet"</string>
+ <string name="status_running" msgid="6562808920311008696">"File transfer is ongoing."</string>
+ <string name="status_success" msgid="239573225847565868">"File transfer completed successfully."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Content isn\'t supported."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"Transfer forbidden by target device."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Transfer cancelled by user."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Storage issue"</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"No USB storage."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"No SD card. Insert an SD card to save transferred files."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Connection unsuccessful."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Request can\'t be handled correctly."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Unknown error."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth received"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Received complete."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Sent complete."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Inbound transfers"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Outbound transfers"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"Browser history is empty."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"All items will be cleared from the list."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetooth share: Sent files"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth share: Received files"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> successful, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> unsuccessful."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Clear list"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"Open"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Clear from list"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Clear"</string>
+</resources>
diff --git a/res/values-en-rIN/strings_map.xml b/res/values-en-rIN/strings_map.xml
new file mode 100644
index 0000000..0807e6e
--- /dev/null
+++ b/res/values-en-rIN/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Type session key for %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth session key required"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"There was time out to accept connection with %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"There was time out to input session key with %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex authentication request"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Session Key"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Type session key for %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Car Kit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Unknown name"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"My name"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-en-rIN/strings_pbap.xml b/res/values-en-rIN/strings_pbap.xml
new file mode 100644
index 0000000..e22854e
--- /dev/null
+++ b/res/values-en-rIN/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"Type session key for %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Bluetooth session key required"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"There was time out to accept connection with %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"There was time out to input session key with %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Obex authentication request"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Session Key"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"Type session key for %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Car Kit"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Unknown name"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"My name"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-en-rIN/test_strings.xml b/res/values-en-rIN/test_strings.xml
new file mode 100644
index 0000000..5eea26e
--- /dev/null
+++ b/res/values-en-rIN/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Hello World, TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"Bluetooth Share"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Insert record"</string>
+ <string name="update_record" msgid="2480425402384910635">"Confirm record"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Ack record"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Delete all record"</string>
+ <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Delete record"</string>
+ <string name="start_server" msgid="9034821924409165795">"Start TCP server"</string>
+ <string name="notify_server" msgid="4369106744022969655">"Notify TCP server"</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index c44c55e..ad6130f 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancelar"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activar"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferencia de archivo"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" desea enviarte <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" ¿Aceptas el archivo?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" desea enviarte <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n ¿Aceptas el archivo?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Rechazar"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Aceptar"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Aceptar"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Cerrar"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Aceptar"</string>
<string name="unknown_file" msgid="6092727753965095366">"Archivo desconocido"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"No hay ninguna aplicación que pueda procesar este tipo de archivo. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"No hay ninguna aplicación que pueda procesar este tipo de archivo. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"No hay archivos"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"El archivo no existe. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"El archivo no existe. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Por favor, espera..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Activando Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"El archivo será recibido. Verifica el progreso en el panel de notificaciones."</string>
diff --git a/res/values-es-rUS/strings_map.xml b/res/values-es-rUS/strings_map.xml
new file mode 100644
index 0000000..cb57328
--- /dev/null
+++ b/res/values-es-rUS/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Escribe la clave de la sesión para %1$s."</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Se requiere la clave de la sesión de Bluetooth."</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Se agotó el tiempo de espera para aceptar la conexión con %1$s."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Se agotó el tiempo de espera para ingresar la clave de la sesión con %1$s."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Solicitud de autenticación de Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Clave de la sesión"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Escribe la clave de la sesión para %1$s."</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit de automóvil"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nombre desconocido"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mi nombre"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 5921493..eec8148 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancelar"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activar"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferencia de archivos"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" quiere enviarte <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" ¿Aceptas el archivo?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" quiere enviarte <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>). \n\n ¿Aceptas el archivo?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Rechazar"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Aceptar"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Aceptar"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Cerrar"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Aceptar"</string>
<string name="unknown_file" msgid="6092727753965095366">"Archivo desconocido"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"No hay ninguna aplicación que pueda procesar este tipo de archivo. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"No hay ninguna aplicación que pueda procesar este tipo de archivo. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"No hay archivos."</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"El archivo no existe. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"El archivo no existe. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Por favor, espera..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Activando Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Se recibirá el archivo. Comprueba el progreso en la barra de notificaciones."</string>
diff --git a/res/values-es/strings_map.xml b/res/values-es/strings_map.xml
new file mode 100644
index 0000000..cae85e1
--- /dev/null
+++ b/res/values-es/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Introducir clave de sesión para %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Se necesita la clave de sesión de Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Se ha agotado el tiempo para aceptar la conexión con %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Se ha agotado el tiempo para introducir la clave de sesión con %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Solicitud de autenticación de Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Clave de sesión"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Introducir clave de sesión para %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nombre desconocido"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mi nombre"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..a762536
--- /dev/null
+++ b/res/values-et-rEE/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Pääs allalaadimishalduri juurde."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Võimaldab rakendusel pääseda BluetoothShare\'i haldurisse ja kasutada seda failide edastamiseks."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Lubage Bluetooth-seadme juurdepääs."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Lubab rakendusel lisada Bluetooth-seadme ajutiselt lubatud seadmete loendisse, mis võimaldab seadmel saata faile sellesse seadmesse ilma kasutaja kinnituseta."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"Võta vastu BT-üleandmise edastusi."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Võimaldab võtta vastu Bluetoothi üleandmise olekuteavet."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Tundmatu seade"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Tundmatu"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Lennurežiim"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Te ei saa Bluetoothi lennukirežiimis kasutada."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Bluetoothi teenuste kasutamiseks peate esmalt Bluetoothi sisse lülitama."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Lülitan Bluetoothi kohe sisse?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Tühista"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Lülita sisse"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"Failiedastus"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> soovib teile saata faili <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Võtan faili vastu?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Keeldu"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Nõustun"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"Esines ajalõpp sissetuleva faili aktsepteerimisel saatjalt „<xliff:g id="SENDER">%1$s</xliff:g>”"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetoothi jagamine: sissetulev fail"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Kas soovite selle faili vastu võtta?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Sissetulev fail teisest seadmest. Kinnitage, et soovite selle faili vastu võtta."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Bluetoothi jagamine: faili <xliff:g id="FILE">%1$s</xliff:g> vastuvõtmine"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Bluetoothi jagamine: <xliff:g id="FILE">%1$s</xliff:g> vastu võetud"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Bluetoothi jagamine: faili <xliff:g id="FILE">%1$s</xliff:g> pole saadud"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Bluetoothi jagamine: faili <xliff:g id="FILE">%1$s</xliff:g> saatmine"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Bluetoothi jagamine: fail <xliff:g id="FILE">%1$s</xliff:g> saadetud"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100% lõpetatud"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetoothi jagamine: faili <xliff:g id="FILE">%1$s</xliff:g> ei saadetud"</string>
+ <string name="download_title" msgid="3353228219772092586">"Failiedastus"</string>
+ <string name="download_line1" msgid="4926604799202134144">"Saatja: „<xliff:g id="SENDER">%1$s</xliff:g>”"</string>
+ <string name="download_line2" msgid="5876973543019417712">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"Faili suurus: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Faili vastuvõtmine ..."</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Peata"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Peida"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"Faili ei saadud"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Põhjus: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"Fail vastu võetud"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Ava"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"Saaja: „<xliff:g id="RECIPIENT">%1$s</xliff:g>”"</string>
+ <string name="upload_line3" msgid="4920689672457037437">"Faili tüüp: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Faili saatmine ..."</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"Fail saadetud"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"Faili ei saadetud kasutajale „<xliff:g id="RECIPIENT">%1$s</xliff:g>”."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Proovige uuesti"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Sulge"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Tundmatu fail"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Seda tüüpi faili käsitlemiseks pole sobivat rakendust. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"Fail puudub"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Faili ei ole olemas. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Palun oodake ..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Bluetoothi sisselülitamine ..."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"Fail võetakse vastu. Vaadake edenemist teatiste paneelil."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"Faili ei saa vastu võtta."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"Faili vastuvõtmine saatjalt „<xliff:g id="SENDER">%1$s</xliff:g>” peatatud"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"Faili saatmine saajale „<xliff:g id="RECIPIENT">%1$s</xliff:g>”"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"<xliff:g id="NUMBER">%1$s</xliff:g> faili saatmine saajale „<xliff:g id="RECIPIENT">%2$s</xliff:g>”"</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"Faili saatmine saajale „<xliff:g id="RECIPIENT">%1$s</xliff:g>” peatatud"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"USB-mäluseadmes pole saatjalt „<xliff:g id="SENDER">%1$s</xliff:g>” saadud faili salvestamiseks piisavalt ruumi"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"SD-kaardil pole saatjalt „<xliff:g id="SENDER">%1$s</xliff:g>” saadud faili salvestamiseks piisavalt ruumi"</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Vajalik ruum: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Liiga palju taotlusi on töötlemisel. Proovige hiljem uuesti."</string>
+ <string name="status_pending" msgid="2503691772030877944">"Failiedastust pole veel käivitatud."</string>
+ <string name="status_running" msgid="6562808920311008696">"Failiedastus on pooleli."</string>
+ <string name="status_success" msgid="239573225847565868">"Failiedastuse lõpuleviimine õnnestus."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Sisu ei toetata."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"Sihtseade on edastuse keelanud."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Kasutaja tühistas edastuse."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Probleem talletamisega."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"USB-mäluseadet ei leita."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"SD-kaart puudub. Edastatud failide salvestamiseks sisestage SD-kaart."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Ühendus ebaõnnestus."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Taotlust ei saa õigesti käsitleda."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Tundmatu viga."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth vastu võetud"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> vastuvõtmine lõpetatud."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> saatmine lõpetatud."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Sissetulevad edastused"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Väljuvad edastused"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"Edastusajalugu on tühi."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Kõik üksused eemaldatakse loendist."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetoothi jagamine: saadetud failid"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetoothi jagamine: vastuvõetud failid"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> õnnestus, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> ebaõnnestus."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Tühjendage loend"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"Ava"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Eemaldage loendist"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Kustuta"</string>
+</resources>
diff --git a/res/values-et-rEE/strings_map.xml b/res/values-et-rEE/strings_map.xml
new file mode 100644
index 0000000..8fe1642
--- /dev/null
+++ b/res/values-et-rEE/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Sisestage seansivõti seadmele %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Vajalik Bluetoothi seansivõti"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Esines ajalõpp ühenduse aktsepteerimiseks seadmega %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Esines ajalõpp seansivõtme sisestamiseks seadmele %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obexi autentimise taotlus"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Seansivõti"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Sisestage seansivõti seadmele %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Autokomplekt"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Tundmatu nimi"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Minu nimi"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-et-rEE/strings_pbap.xml b/res/values-et-rEE/strings_pbap.xml
new file mode 100644
index 0000000..0346c28
--- /dev/null
+++ b/res/values-et-rEE/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"Sisestage seansivõti failile %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Vajalik Bluetoothi seansivõti"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"Esines ajalõpp ühenduse aktsepteerimiseks seadmega %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"Esines ajalõpp sisendseansivõtmele failiga %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Obexi autentimise taotlus"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Seansivõti"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"Sisestage seansivõti failile %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Autokomplekt"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Tundmatu nimi"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"Minu nimi"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-et-rEE/test_strings.xml b/res/values-et-rEE/test_strings.xml
new file mode 100644
index 0000000..9da0688
--- /dev/null
+++ b/res/values-et-rEE/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Tere, maailm, TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"Bluetoothi jagamine"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Sisestage kirje"</string>
+ <string name="update_record" msgid="2480425402384910635">"Kinnita kirje"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Acki kirje"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Kustuta kõik kirjed"</string>
+ <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Kustuta kirje"</string>
+ <string name="start_server" msgid="9034821924409165795">"Käivita TCP-server"</string>
+ <string name="notify_server" msgid="4369106744022969655">"Teavita TCP-serverit"</string>
+</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 13ef94a..a762536 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Tühista"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Lülita sisse"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Failiedastus"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> soovib teile saata faili <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Võtan faili vastu?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> soovib teile saata faili <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Võtan faili vastu?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Keeldu"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Nõustun"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Sulge"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Tundmatu fail"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Seda tüüpi faili käsitlemiseks pole sobivat rakendust. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Seda tüüpi faili käsitlemiseks pole sobivat rakendust. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Fail puudub"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Faili ei ole olemas. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Faili ei ole olemas. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Palun oodake ..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetoothi sisselülitamine ..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Fail võetakse vastu. Vaadake edenemist teatiste paneelil."</string>
diff --git a/res/values-et/strings_map.xml b/res/values-et/strings_map.xml
new file mode 100644
index 0000000..8fe1642
--- /dev/null
+++ b/res/values-et/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Sisestage seansivõti seadmele %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Vajalik Bluetoothi seansivõti"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Esines ajalõpp ühenduse aktsepteerimiseks seadmega %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Esines ajalõpp seansivõtme sisestamiseks seadmele %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obexi autentimise taotlus"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Seansivõti"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Sisestage seansivõti seadmele %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Autokomplekt"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Tundmatu nimi"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Minu nimi"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index bf30321..7fc53fa 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -16,8 +16,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"دسترسی به Download Manager."</string>
- <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"به برنامه برای دسترسی به مدیر BluetoothShare و استفاده از آن برای انتقال فایلها اجازه میدهد."</string>
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"دسترسی به Download Manager."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"به برنامه برای دسترسی به مدیر BluetoothShare و استفاده از آن برای انتقال فایلها اجازه میدهد."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"دسترسی دستگاه موجود در لیست سفید بلوتوث."</string>
<string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"به برنامه اجازه میدهد تا موقتاً یک دستگاه بلوتوث را در لیست سفید وارد کند، و به آن دستگاه اجازه میدهد بدون تأیید کاربر به این دستگاه فایل ارسال کند."</string>
<string name="permlab_handoverStatus" msgid="7316032998801933554">"دریافت پخشهای عمومی انتقالی از بلوتوث."</string>
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"لغو"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"روشن کردن"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"انتقال فایل"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" میخواهد <xliff:g id="FILE">%2$s</xliff:g> را به شما ارسال کند. (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" فایل را میپذیرید؟"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" میخواهد <xliff:g id="FILE">%2$s</xliff:g> را به شما ارسال کند. (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n فایل را میپذیرید؟"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"عدم پذیرش"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"پذیرش"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"تأیید"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"بستن"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"تأیید"</string>
<string name="unknown_file" msgid="6092727753965095366">"فایل ناشناس"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"هیچ برنامهای برای کار با این نوع فایل وجود ندارد."\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"هیچ برنامهای برای کار با این نوع فایل وجود ندارد.\n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"فایلی وجود ندارد"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"فایل موجود نیست. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"فایل موجود نیست. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"لطفاً منتظر بمانید…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"روشن کردن بلوتوث..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"فایل دریافت میشود: پیشرفت دریافت را در پانل اعلانها بررسی کنید."</string>
@@ -84,8 +84,8 @@
<string name="bt_toast_4" msgid="4678812947604395649">"ارسال فایل به \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
<string name="bt_toast_5" msgid="2846870992823019494">"ارسال <xliff:g id="NUMBER">%1$s</xliff:g> فایل به \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
<string name="bt_toast_6" msgid="1855266596936622458">"ارسال فایل به \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" متوقف شد"</string>
- <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"برای ذخیره فایل از \"<xliff:g id="SENDER">%1$s</xliff:g>\" فضای کافی در حافظهٔ USB موجود نیست"</string>
- <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"برای ذخیره فایل \"<xliff:g id="SENDER">%1$s</xliff:g>\" فضای کافی در کارت SD موجود نیست"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"برای ذخیره فایل از \"<xliff:g id="SENDER">%1$s</xliff:g>\" فضای کافی در حافظهٔ USB موجود نیست"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"برای ذخیره فایل \"<xliff:g id="SENDER">%1$s</xliff:g>\" فضای کافی در کارت SD موجود نیست"</string>
<string name="bt_sm_2_2" msgid="2965243265852680543">"فضای مورد نیاز: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="ErrorTooManyRequests" msgid="8578277541472944529">"درخواستهای بسیاری در حال انجام هستند. بعداً دوباره امتحان کنید."</string>
<string name="status_pending" msgid="2503691772030877944">"انتقال فایل هنوز شروع نشده است."</string>
@@ -95,8 +95,8 @@
<string name="status_forbidden" msgid="613956401054050725">"انتقال توسط دستگاه مقصد ممنوع شده است."</string>
<string name="status_canceled" msgid="6664490318773098285">"انتقال توسط کاربر لغو شد."</string>
<string name="status_file_error" msgid="3671917770630165299">"مشکل ذخیره."</string>
- <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"حافظهٔ USB وجود ندارد."</string>
- <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"هیچ کارت SD موجود نیست. برای ذخیره فایلهای منتقل شده، یک کارت SD در گوشی قرار دهید."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"حافظهٔ USB وجود ندارد."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"هیچ کارت SD موجود نیست. برای ذخیره فایلهای منتقل شده، یک کارت SD در گوشی قرار دهید."</string>
<string name="status_connection_error" msgid="947681831523219891">"اتصال ناموفق بود."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"درخواست به درستی انجام نمیشود."</string>
<string name="status_unknown_error" msgid="8156660554237824912">"خطای ناشناخته."</string>
diff --git a/res/values-fa/strings_map.xml b/res/values-fa/strings_map.xml
new file mode 100644
index 0000000..30cce9d
--- /dev/null
+++ b/res/values-fa/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"کلید جلسه را برای %1$s تایپ کنید"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"کلید جلسه بلوتوث مورد نیاز است"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"زمان پذیرش اتصال به %1$s به پایان رسید"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"زمان وارد کردن کلید جلسه با %1$s به پایان رسید"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"درخواست تأیید اعتبار Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"کلید جلسه"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"کلید جلسه را برای %1$s تایپ کنید"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"کیت خودرو"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"نام ناشناس"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"نام من"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-fa/strings_pbap.xml b/res/values-fa/strings_pbap.xml
index cd434d7..bc68a89 100644
--- a/res/values-fa/strings_pbap.xml
+++ b/res/values-fa/strings_pbap.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"تایپ کلید جلسه برای %1$s"</string>
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"تایپ کلید جلسه برای %1$s"</string>
<string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"به کلید جلسه بلوتوث نیاز است"</string>
- <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"هنگام پذیرش اتصال به %1$s وقفه زمانی ایجاد شده است"</string>
- <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"هنگام ورود کلید جلسه با %1$s وقفه زمانی ایجاد شده است"</string>
- <string name="auth_notif_ticker" msgid="1575825798053163744">"درخواست تأیید اعتبار Obex"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"هنگام پذیرش اتصال به %1$s وقفه زمانی ایجاد شده است"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"هنگام ورود کلید جلسه با %1$s وقفه زمانی ایجاد شده است"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"درخواست تأیید اعتبار Obex"</string>
<string name="auth_notif_title" msgid="7599854855681573258">"کلید جلسه"</string>
- <string name="auth_notif_message" msgid="6667218116427605038">"تایپ کلید جلسه برای %1$s"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"تایپ کلید جلسه برای %1$s"</string>
<string name="defaultname" msgid="4821590500649090078">"کیت خودرو"</string>
<string name="unknownName" msgid="2841414754740600042">"نام ناشناس"</string>
<string name="localPhoneName" msgid="2349001318925409159">"نام من"</string>
diff --git a/res/values-fa/test_strings.xml b/res/values-fa/test_strings.xml
index 49670e5..000f3f7 100644
--- a/res/values-fa/test_strings.xml
+++ b/res/values-fa/test_strings.xml
@@ -5,10 +5,10 @@
<string name="app_name" msgid="1203877025577761792">"اشتراک بلوتوث"</string>
<string name="insert_record" msgid="1450997173838378132">"درج سابقه"</string>
<string name="update_record" msgid="2480425402384910635">"تأیید سابقه"</string>
- <string name="ack_record" msgid="6716152390978472184">"سابقه Ack"</string>
+ <string name="ack_record" msgid="6716152390978472184">"سابقه Ack"</string>
<string name="deleteAll_record" msgid="4383349788485210582">"حذف همه سابقه"</string>
<string name="ok_button" msgid="6519033415223065454">"تأیید"</string>
<string name="delete_record" msgid="4645040331967533724">"حذف سابقه"</string>
- <string name="start_server" msgid="9034821924409165795">"راهاندازی سرور TCP"</string>
- <string name="notify_server" msgid="4369106744022969655">"اعلان سرور TCP"</string>
+ <string name="start_server" msgid="9034821924409165795">"راهاندازی سرور TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"اعلان سرور TCP"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 455df83..051d66c 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Peruuta"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Ota käyttöön"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Tiedostonsiirto"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> haluaa lähettää sinulle tiedoston <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Haluatko vastaanottaa tiedoston?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> haluaa lähettää sinulle tiedoston <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Haluatko vastaanottaa tiedoston?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Hylkää"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Hyväksy"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Sulje"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Tuntematon tiedosto"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Tämän tyyppisten tiedostojen käsittelyyn sopivaa sovellusta ei ole asennettu. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Tämän tyyppisten tiedostojen käsittelyyn sopivaa sovellusta ei ole asennettu. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ei tiedostoa"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Tiedostoa ei ole olemassa. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Tiedostoa ei ole olemassa. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Odota…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Otetaan Bluetooth käyttöön..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Tiedosto otetaan vastaan. Näet siirron tilan Ilmoitukset-paneelissa."</string>
diff --git a/res/values-fi/strings_map.xml b/res/values-fi/strings_map.xml
new file mode 100644
index 0000000..288e115
--- /dev/null
+++ b/res/values-fi/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Kirjoita kohteen %1$s istunnon avain"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-istunnon avain vaaditaan"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Kohteen %1$s yhteyspyyntö aikakatkaistiin"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Kohteen %1$s istunnon avaimen syöttö aikakatkaistiin"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex-todennuspyyntö"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Istunnon avain"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Kirjoita kohteen %1$s istunnon avain"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Autosarja"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Tuntematon nimi"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Oma nimi"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..1b17ae8
--- /dev/null
+++ b/res/values-fr-rCA/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Accéder au gestionnaire de téléchargement."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Permet à l\'application d\'accéder au gestionnaire BluetoothShare et de l\'utiliser pour le transfert de fichiers."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Ajouter des appareils Bluetooth à la liste blanche."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Permet à l\'application d\'ajouter temporairement un appareil Bluetooth à la liste blanche. Ainsi, celui-ci peut envoyer des fichiers à cet appareil sans que la confirmation de l\'utilisateur soit nécessaire."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"Recevoir des messages concernant les transferts Bluetooth."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Permet la réception d\'information concernant l\'état du transfert par Bluetooth."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Périphérique inconnu"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Inconnu"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Mode Avion"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Bluetooth ne peut être utilisé en mode Avion."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Vous devez activer la fonction Bluetooth pour pouvoir utiliser les services Bluetooth."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Activer Bluetooth maintenant?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Annuler"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Activer"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transfert de fichier"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" souhaite vous envoyer <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Accepter le fichier?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Refuser"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accepter"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"Expiration du délai de réception du fichier de \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Partage Bluetooth : réception de fichier"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Voulez-vous recevoir ce fichier?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Fichier entrant provenant d\'un autre appareil. Confirmez que vous souhaitez recevoir ce fichier."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Partage Bluetooth : réception de <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Partage Bluetooth : <xliff:g id="FILE">%1$s</xliff:g> reçu(s)"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Partage Bluetooth : fichier <xliff:g id="FILE">%1$s</xliff:g> non reçu"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Partage Bluetooth : envoi de <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Partage Bluetooth : <xliff:g id="FILE">%1$s</xliff:g> envoyé"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100 % effectués"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Partage Bluetooth : fichier <xliff:g id="FILE">%1$s</xliff:g> non envoyé"</string>
+ <string name="download_title" msgid="3353228219772092586">"Transfert de fichier"</string>
+ <string name="download_line1" msgid="4926604799202134144">"De : \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"Fichier : <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"Taille du fichier : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Réception de fichier en cours"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Arrêter"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Masquer"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"Fichier non reçu"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"Fichier : <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Motif : <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"Fichier reçu"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Ouvrir"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"À : \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"Type de fichier : <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Envoi de fichier en cours"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"Fichier envoyé"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"Le fichier n\'a pas été envoyé à <xliff:g id="RECIPIENT">%1$s</xliff:g>."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"Fichier : <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Réessayer"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Fermer"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Fichier inconnu"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Aucune application ne permet de gérer ce type de fichier. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"Aucun fichier"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Le fichier n\'existe pas. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Veuillez patienter…"</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Activation de Bluetooth…"</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"La réception du fichier va commencer. La progression va s\'afficher dans le panneau de notification."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"Impossible de recevoir le fichier."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"Réception du fichier de \"<xliff:g id="SENDER">%1$s</xliff:g>\" interrompue"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"Envoi du fichier à \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"Envoi de <xliff:g id="NUMBER">%1$s</xliff:g> fichiers à \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"Envoi du fichier à \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" interrompu"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"Espace insuffisant sur la mémoire de stockage USB pour l\'enregistrement du fichier de \"<xliff:g id="SENDER">%1$s</xliff:g>\"."</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"Espace insuffisant sur la carte SD pour l\'enregistrement du fichier de \"<xliff:g id="SENDER">%1$s</xliff:g>\"."</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Espace requis : <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Trop de requêtes sont en cours de traitement. Veuillez réessayer plus tard."</string>
+ <string name="status_pending" msgid="2503691772030877944">"Le transfert de fichier n\'a pas encore commencé."</string>
+ <string name="status_running" msgid="6562808920311008696">"Le transfert de fichier est en cours."</string>
+ <string name="status_success" msgid="239573225847565868">"Le transfert de fichiers s\'est déroulé correctement."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Le contenu n\'est pas compatible."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"L\'appareil cible n\'autorise pas le transfert."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Le transfert a été annulé par l\'utilisateur."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Problème de mémoire."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"Aucune mémoire de stockage USB"</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"Aucune carte SD trouvée. Insérez une carte SD pour enregistrer les fichiers transférés."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Échec de la connexion."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Impossible de traiter la demande correctement."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Erreur inconnue."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Reçu par Bluetooth"</string>
+ <string name="download_success" msgid="7036160438766730871">"Réception de <xliff:g id="FILE_SIZE">%1$s</xliff:g> terminée"</string>
+ <string name="upload_success" msgid="4014469387779648949">"Envoi de <xliff:g id="FILE_SIZE">%1$s</xliff:g> terminé"</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Transferts entrants"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Transferts sortants"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"L\'historique des transferts est vide."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Tous les éléments de la liste seront effacés."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Partage Bluetooth : fichiers envoyés"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Partage Bluetooth : fichiers reçus"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> succès, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> échoué."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Effacer la liste"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"ouvrir"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Effacer de la liste"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Effacer"</string>
+</resources>
diff --git a/res/values-fr-rCA/strings_map.xml b/res/values-fr-rCA/strings_map.xml
new file mode 100644
index 0000000..39f72cf
--- /dev/null
+++ b/res/values-fr-rCA/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Entrez la clé de session de %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Clé de session Bluetooth requise"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Délai d\'attente dépassé pour l\'acceptation de connexion à %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Délai d\'attente dépassé pour l\'entrée de la clé de session avec %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Demande d\'authentification Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Clé de session"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Entrez la clé de session de %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Trousse mains libres"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nom inconnu"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mon nom"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-fr-rCA/strings_pbap.xml b/res/values-fr-rCA/strings_pbap.xml
new file mode 100644
index 0000000..0c4c601
--- /dev/null
+++ b/res/values-fr-rCA/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"Entrer la clé de session de %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Clé de session Bluetooth requise"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"Délai d\'attente dépassé pour l\'acceptation de connexion à \"%1$s\""</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"Délai d\'attente dépassé pour la saisie de la clé de session avec %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Demande d\'authentification Obex"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Clé de session"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"Entrer la clé de session de %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Trousse mains libres"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Nom inconnu"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"Mon nom"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-fr-rCA/test_strings.xml b/res/values-fr-rCA/test_strings.xml
new file mode 100644
index 0000000..e8d36ae
--- /dev/null
+++ b/res/values-fr-rCA/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Bonjour à tous, TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"Partage Bluetooth"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Insérer l\'enregistrement"</string>
+ <string name="update_record" msgid="2480425402384910635">"Confirmer l\'enregistrement"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Enregistrement accusé de réception"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Supprimer tout l\'enregistrement"</string>
+ <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Supprimer l\'enregistrement"</string>
+ <string name="start_server" msgid="9034821924409165795">"Démarrer le serveur TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"Avertir le serveur TCP"</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index f3fb8ce..5d26fc4 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Annuler"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activer"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transfert de fichier"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" souhaite vous envoyer <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Accepter le fichier ?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" souhaite vous envoyer <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Accepter le fichier ?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Refuser"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accepter"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Fermer"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Fichier inconnu"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Aucune application ne permet de gérer ce type de fichier. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Aucune application ne permet de gérer ce type de fichier. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Aucun fichier"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Le fichier n\'existe pas. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Le fichier n\'existe pas. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Veuillez patienter..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Activation Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"La réception du fichier va commencer. La progression va s\'afficher dans le panneau de notification."</string>
diff --git a/res/values-fr/strings_map.xml b/res/values-fr/strings_map.xml
new file mode 100644
index 0000000..16985d6
--- /dev/null
+++ b/res/values-fr/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Saisir la clé de session pour \"%1$s\""</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Clé de session Bluetooth requise"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Délai d\'attente dépassé pour l\'acceptation de connexion à \"%1$s\"."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Délai d\'attente dépassé pour la saisie de la clé de session avec \"%1$s\"."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Demande d\'authentification Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Clé de session"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Saisir la clé de session pour \"%1$s\""</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit mains libres"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nom inconnu."</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mon nom"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 2f73312..b4d16fa 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -17,9 +17,9 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permlab_bluetoothShareManager" msgid="311492132450338925">"डाउनलोड प्रबंधक में पहुंच प्राप्त करें."</string>
- <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"एप्लिकेशन को BluetoothShare प्रबंधक में पहुंच प्राप्त करने और फ़ाइलों को स्थानांतरित करने के लिए उसका उपयोग करने देता है."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"ऐप्स को BluetoothShare प्रबंधक में पहुंच प्राप्त करने और फ़ाइलों को स्थानांतरित करने के लिए उसका उपयोग करने देता है."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"श्वेतसूची bluetooth उपकरण पहुंच."</string>
- <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"एप्लिकेशन को Bluetooth उपकरण को इस उपकरण पर फ़ाइल भेजने की अनुमति देकर, उपयोगकर्ता की पुष्टि के बिना अस्थायी रूप से श्वेतसूची में शामिल करने देता है."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"ऐप्स को Bluetooth उपकरण को इस उपकरण पर फ़ाइल भेजने की अनुमति देकर, उपयोगकर्ता की पुष्टि के बिना अस्थायी रूप से श्वेतसूची में शामिल करने देता है."</string>
<string name="permlab_handoverStatus" msgid="7316032998801933554">"BT हस्तांतरण के स्थानांतरण प्रसारण प्राप्त करें."</string>
<string name="permdesc_handoverStatus" msgid="4752738070064786310">"Bluetooth से हस्तांतरण के स्थानांतरण की स्थिति को प्राप्त करने देता है."</string>
<string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
@@ -33,10 +33,10 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"रद्द करें"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"चालू करें"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"फ़ाइल स्थानांतरण"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" द्वारा आपको <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) भेजी जा रही है. "\n\n" फ़ाइल स्वीकार करनी है?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" द्वारा आपको <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) भेजी जा रही है. \n\n फ़ाइल स्वीकार करनी है?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"अस्वीकारें"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"स्वीकारें"</string>
- <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ठीक"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ठीक है"</string>
<string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" से आने वाली फ़ाइल स्वीकार करते समय समयबाह्य हुआ."</string>
<string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth शेयर: आने वाली फ़ाइल"</string>
<string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"क्या आप यह फ़ाइल प्राप्त करना चाहते हैं?"</string>
@@ -59,23 +59,23 @@
<string name="download_fail_line1" msgid="3846450148862894552">"फ़ाइल प्राप्त नहीं हुई"</string>
<string name="download_fail_line2" msgid="8950394574689971071">"फ़ाइल: <xliff:g id="FILE">%1$s</xliff:g>"</string>
<string name="download_fail_line3" msgid="3451040656154861722">"कारण: <xliff:g id="REASON">%1$s</xliff:g>"</string>
- <string name="download_fail_ok" msgid="1521733664438320300">"ठीक"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"ठीक है"</string>
<string name="download_succ_line5" msgid="4509944688281573595">"फ़ाइल प्राप्त की गई"</string>
<string name="download_succ_ok" msgid="7053688246357050216">"खोलें"</string>
<string name="upload_line1" msgid="2055952074059709052">"प्रति: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
<string name="upload_line3" msgid="4920689672457037437">"फ़ाइल प्रकार: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
<string name="upload_line5" msgid="7759322537674229752">"फ़ाइल भेज रहा है…"</string>
<string name="upload_succ_line5" msgid="5687317197463383601">"फ़ाइल भेजी गई"</string>
- <string name="upload_succ_ok" msgid="7705428476405478828">"ठीक"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"ठीक है"</string>
<string name="upload_fail_line1" msgid="7899394672421491701">"फ़ाइल \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" को नहीं भेजी गई थी."</string>
<string name="upload_fail_line1_2" msgid="2108129204050841798">"फ़ाइल: <xliff:g id="FILE">%1$s</xliff:g>"</string>
<string name="upload_fail_ok" msgid="5807702461606714296">"पुन: प्रयास करें"</string>
<string name="upload_fail_cancel" msgid="9118496285835687125">"बंद करें"</string>
- <string name="bt_error_btn_ok" msgid="5965151173011534240">"ठीक"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"ठीक है"</string>
<string name="unknown_file" msgid="6092727753965095366">"अज्ञात फ़ाइल"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"इस प्रकार की फ़ाइल प्रबंधित करने के लिए कोई एप्लिकेशन नहीं है. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"इस प्रकार की फ़ाइल प्रबंधित करने के लिए कोई ऐप्स नहीं है. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"कोई फ़ाइल नहीं"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"फ़ाइल मौजूद नहीं है. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"फ़ाइल मौजूद नहीं है. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"कृपया प्रतीक्षा करें..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth चालू कर रहा है…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"फ़ाइल प्राप्त होगी. सूचनाएं फलक में प्रगति देखें."</string>
diff --git a/res/values-hi/strings_map.xml b/res/values-hi/strings_map.xml
new file mode 100644
index 0000000..85db1a5
--- /dev/null
+++ b/res/values-hi/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s के लिए सत्र कुंजी लिखें"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth सत्र कुंजी आवश्यक"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s के साथ कनेक्शन स्वीकार करने में समयबाह्य हो गया था"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s के साथ सत्र कुंजी इनपुट करने में समयबाह्य हो गया था"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex प्रमाणीकरण अनुरोध"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"सत्र कुंजी"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s के लिए सत्र कुंजी लिखें"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"कार किट"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"अज्ञात नाम"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"मेरा नाम"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-hi/test_strings.xml b/res/values-hi/test_strings.xml
index aa134ee..e6889e7 100644
--- a/res/values-hi/test_strings.xml
+++ b/res/values-hi/test_strings.xml
@@ -7,7 +7,7 @@
<string name="update_record" msgid="2480425402384910635">"रिकॉर्ड की पुष्टि करें"</string>
<string name="ack_record" msgid="6716152390978472184">"रिकॉर्ड अभिस्वीकृत करें"</string>
<string name="deleteAll_record" msgid="4383349788485210582">"सभी रिकॉर्ड हटाएं"</string>
- <string name="ok_button" msgid="6519033415223065454">"ठीक"</string>
+ <string name="ok_button" msgid="6519033415223065454">"ठीक है"</string>
<string name="delete_record" msgid="4645040331967533724">"रिकॉर्ड हटाएं"</string>
<string name="start_server" msgid="9034821924409165795">"TCP सर्वर प्रारंभ करें"</string>
<string name="notify_server" msgid="4369106744022969655">"TCP सर्वर को सूचित करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 36a1440..db7bf5d 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Odustani"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Uključi"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Prijenos datoteke"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vam želi poslati <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Prihvaćate li datoteku?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vam želi poslati <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Prihvaćate li datoteku?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Odbaci"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Prihvaćam"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"U redu"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Zatvori"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"U redu"</string>
<string name="unknown_file" msgid="6092727753965095366">"Nepoznata datoteka"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Nema aplikacija za obradu ove vrste datoteke. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Nema aplikacija za obradu ove vrste datoteke. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nema datoteke"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Datoteka ne postoji. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Datoteka ne postoji. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Pričekajte…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Uključivanje Bluetootha…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Datoteka će biti primljena. Napredak provjerite na ploči Obavijesti."</string>
diff --git a/res/values-hr/strings_map.xml b/res/values-hr/strings_map.xml
new file mode 100644
index 0000000..a31ba2c
--- /dev/null
+++ b/res/values-hr/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Upišite šifru sesije za %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Potrebna je šifra za Bluetooth sesiju"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Došlo je do prekoračenja vremena za prihvat povezivanja s korisnikom %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Došlo je do prekoračenja vremena za unos šifre sesije s korisnikom %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Zahtjev za provjeru autentičnosti Obex protokola"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Šifra sesije"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Upišite šifru sesije za %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Komplet za auto"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nepoznati naziv"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Moje ime"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 36786bf..f9aceab 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Mégse"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Bekapcsolás"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Fájlátvitel"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" a következő fájlt szeretné elküldeni: <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Fogadja?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" a következő fájlt szeretné elküldeni: <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Fogadja?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Elutasítás"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Elfogadás"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Bezárás"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Ismeretlen fájl"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Nincs alkalmazás a fájltípus kezeléséhez. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Nincs alkalmazás a fájltípus kezeléséhez. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nincs fájl"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"A fájl nem létezik. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"A fájl nem létezik. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Kérjük, várjon..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth bekapcsolása..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"A fájl fogadható. Az átvitel haladását az Értesítések párbeszédpanelen kísérheti figyelemmel."</string>
diff --git a/res/values-hu/strings_map.xml b/res/values-hu/strings_map.xml
new file mode 100644
index 0000000..2f7a0e4
--- /dev/null
+++ b/res/values-hu/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Írja be a munkamenetkulcsot a(z) %1$s eszközhöz"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Meg kell adni egy Bluetooth-munkamenetkulcsot"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Időtúllépés történt a(z) %1$s eszközhöz történő kapcsolódás során"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Időtúllépés történt a(z) %1$s programfolyamat-kulcsának bevitele során"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex azonosítási kérelem"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Munkamenetkulcs"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Írja be a munkamenetkulcsot a(z) %1$s eszközhöz"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Autós készlet"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Ismeretlen név"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Saját név"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..3ecae6b
--- /dev/null
+++ b/res/values-hy-rAM/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Օգտվել ներբեռնման կառավարչից:"</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Թույլ է տալիս, որ ծրագիրը մատչի BluetoothShare կառավարչին և այն օգտագործի ֆայլեր փոխանցելու համար:"</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Մուտք bluetooth սարքի ցուցակին:"</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Թույլ է տալիս, որ ծրագիրը ժամանակավորապես մաքրի Bluetooth սարքի ցուցակը, ինչը թույլ է տալիս, որ այդ սարքը կարողանա ֆայլեր ուղարկել տվյալ սարքին առանց օգտվողի հաստատման:"</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"Ստանալ BT փոխանցումների հեռարձակումները:"</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Թույլ է տալիս Bluetooth-ից տեղեկատվություն ստանալ փոխանցման կարգավիճակի մասին:"</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Անհայտ սարք"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Անհայտ"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Ինքնաթիռային ռեժիմ"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Դուք չեք կարող օգտվել Bluetooth-ից ինքնաթիռային ռեժիմում:"</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Bluetooth ծառայություններից օգտվելու համար նախ պետք է միացնեք Bluetooth-ը:"</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Միացնե՞լ Bluetooth-ը հիմա:"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Չեղարկել"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Միացնել"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"Ֆայլերի փոխանցում"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"«<xliff:g id="SENDER">%1$s</xliff:g>»-ը ցանկանում է ձեզ ուղարկել <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>): \n\n Ընդունե՞լ ֆայլը:"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Մերժել"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Ընդունել"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Լավ"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"«<xliff:g id="SENDER">%1$s</xliff:g>»-ից մուտքային ֆայլի ընդունման ժամանակը սպառվեց"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth համօգտագործում՝ մուտքային ֆայլ"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Ցանկանո՞ւմ եք ստանալ այս ֆայլը:"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Առկա է մուտքային ֆայլ այլ սարքից: Հաստատեք, որ ցանկանում եք ստանալ այս ֆայլը:"</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Bluetooth համօգտագործում՝ <xliff:g id="FILE">%1$s</xliff:g>-ը ստացվում է"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Bluetooth համօգտագործում՝ ստացվեց <xliff:g id="FILE">%1$s</xliff:g>-ը"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth համօգտագործում՝ <xliff:g id="FILE">%1$s</xliff:g> ֆայլը չի ստացվել"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Bluetooth համօգտագործում՝ ուղարկվում է <xliff:g id="FILE">%1$s</xliff:g>-ը"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Bluetooth համօգտագործում՝ <xliff:g id="FILE">%1$s</xliff:g>-ն ուղարկված է"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100% ավարտուն"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetooth համօգտագործում՝ <xliff:g id="FILE">%1$s</xliff:g> ֆայլը չի ուղարկվել"</string>
+ <string name="download_title" msgid="3353228219772092586">"Ֆայլերի փոխանցում"</string>
+ <string name="download_line1" msgid="4926604799202134144">"Ումից՝ «<xliff:g id="SENDER">%1$s</xliff:g>»"</string>
+ <string name="download_line2" msgid="5876973543019417712">"Ֆայլ՝ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"Ֆայլի չափը՝ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Ֆայլը ստացվում է..."</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Դադարեցնել"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Թաքցնել"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"Ֆայլը չհաջողվեց ստանալ"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"Ֆայլ՝ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Պատճառը՝ <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"Լավ"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"Ֆայլը ստացվել է"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Բացել"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"Ում՝ «<xliff:g id="RECIPIENT">%1$s</xliff:g>»"</string>
+ <string name="upload_line3" msgid="4920689672457037437">"Ֆայլի տեսակը՝ <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Ֆայլն ուղարկվում է..."</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"Ֆայլն ուղարկված է"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"Լավ"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"Ֆայլը չի ուղարկվել «<xliff:g id="RECIPIENT">%1$s</xliff:g>»-ին:"</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"Ֆայլ՝ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Կրկին փորձել"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Փակել"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"Լավ"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Անհայտ ֆայլ"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Ֆայլի այս տեսակի համար գործող ծրագիր չկա: \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"Ֆայլեր չկան"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Ֆայլը գոյություն չունի: \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Խնդրում ենք սպասել..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth-ը միանում է..."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"Դուք կստանաք ֆայլը: Առաջընթացի մասին տեղեկացեք Ծանուցումների վահանակից:"</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"Հնարավոր չէ ստանալ ֆայլը:"</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"Դադարեցվեց «<xliff:g id="SENDER">%1$s</xliff:g>»-ից ֆայլի ստացումը"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"Ֆայլն ուղարկվում է «<xliff:g id="RECIPIENT">%1$s</xliff:g>»-ին"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"<xliff:g id="NUMBER">%1$s</xliff:g> ֆայլեր ուղարկվում են «<xliff:g id="RECIPIENT">%2$s</xliff:g>»-ին"</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"Դադարեցվեց ֆայլի ուղարկումը «<xliff:g id="RECIPIENT">%1$s</xliff:g>»-ին"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"USB կրիչի վրա բավարար տեղ չկա «<xliff:g id="SENDER">%1$s</xliff:g>»-ի ֆայլի պահպանման համար"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"SD քարտի վրա բավարար տեղ չկա «<xliff:g id="SENDER">%1$s</xliff:g>»-ի ֆայլի պահպանման համար"</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Անհրաժեշտ տեղը՝ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Չափից շատ հարցումներ են մշակվում: Կրկին փորձեք ավելի ուշ:"</string>
+ <string name="status_pending" msgid="2503691772030877944">"Ֆայլի փոխանցումը դեռ չի մեկնարկել:"</string>
+ <string name="status_running" msgid="6562808920311008696">"Ֆայլի փոխանցումն ընթացքի մեջ է:"</string>
+ <string name="status_success" msgid="239573225847565868">"Ֆայլերի փոխանցումը հաջողությամբ ավարտվել է:"</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Բովանդակությունը չի աջակցվում:"</string>
+ <string name="status_forbidden" msgid="613956401054050725">"Փոխանցումն արգելված է նպատակային սարքի կողմից:"</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Փոխանցումը չեղարկվել է օգտվողի կողմից:"</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Կրիչի խնդիր:"</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"USB կրիչ չկա:"</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"SD քարտ չկա: Տեղադրեք SD քարտ` փոխանցված ֆայլերը պահպանելու համար:"</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Միացումը անհաջող էր:"</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Հարցումը հնարավոր չէ ճշգրտորեն մշակել:"</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Անհայտ սխալ:"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth-ը ստացված է"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> ստացումն ավարտված է:"</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> ուղարկումն ավարտված է:"</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Մուտքային փոխանցումներ"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Ելքային փոխանցումներ"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"Փոխանցումների պատմությունը դատարկ է:"</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Ցուցակի բոլոր տվյալները կջնջվեն:"</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetooth համօգտագործում՝ ֆայլերն ուղարկված են"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth համօգտագործում՝ ֆայլերը ստացված են"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> հաջողված, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> չհաջողված:"</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Ջնջել ցուցակը"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"Բաց"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Ջնջել ցուցակից"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Ջնջել"</string>
+</resources>
diff --git a/res/values-hy-rAM/strings_map.xml b/res/values-hy-rAM/strings_map.xml
new file mode 100644
index 0000000..91f2078
--- /dev/null
+++ b/res/values-hy-rAM/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Մուտքագրեք աշխատաշրջանի բանալին %1$s-ի համար"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Պահանջվում է Bluetooth-ի աշխատաշրջանի բանալի"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-ի հետ կապի ընդունման ժամանակը սպառվեց"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-ով աշխատաշրջանի բանալու մուտքագրման ժամանակը սպառվեց"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Կասեցնել նույնականացման հարցումը"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Աշխատաշրջանի բանալի"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Մուտքագրեք աշխատաշրջանի բանալին %1$s-ի համար"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Անհայտ անուն"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Իմ անունը"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-hy-rAM/strings_pbap.xml b/res/values-hy-rAM/strings_pbap.xml
new file mode 100644
index 0000000..18a22be
--- /dev/null
+++ b/res/values-hy-rAM/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"Մուտքագրեք աշխատաշրջանի բանալին %1$s-ի համար"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Պահանջվում է Bluetooth-ի աշխատաշրջանի բանալի"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"«%1$s»-ի հետ կապի ընդունման ժամանակը սպառվեց"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"%1$s-ով աշխատաշրջանի բանալու մուտքագրման ժամանակը սպառվեց"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Կասեցնել նույնականացման հարցումը"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Աշխատաշրջանի բանալի"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"Մուտքագրեք աշխատաշրջանի բանալի %1$s-ի համար"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Carkit"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Անհայտ անուն"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"Իմ անունը"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-hy-rAM/test_strings.xml b/res/values-hy-rAM/test_strings.xml
new file mode 100644
index 0000000..ffcd2c0
--- /dev/null
+++ b/res/values-hy-rAM/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Բարև աշխարհ, փորձնական գործողություն"</string>
+ <string name="app_name" msgid="1203877025577761792">"Bluetooth համօգտագործում"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Կատարեք գրառում"</string>
+ <string name="update_record" msgid="2480425402384910635">"Հաստատել գրառումը"</string>
+ <string name="ack_record" msgid="6716152390978472184">"ACK գրառում"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Ջնջել բոլոր գրառումները"</string>
+ <string name="ok_button" msgid="6519033415223065454">"Լավ"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Ջնջել գրառումը"</string>
+ <string name="start_server" msgid="9034821924409165795">"Մեկնարկել TCP սերվերը"</string>
+ <string name="notify_server" msgid="4369106744022969655">"Ծանուցել TCP սերվերին"</string>
+</resources>
diff --git a/res/values-hy/strings_map.xml b/res/values-hy/strings_map.xml
new file mode 100644
index 0000000..91f2078
--- /dev/null
+++ b/res/values-hy/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Մուտքագրեք աշխատաշրջանի բանալին %1$s-ի համար"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Պահանջվում է Bluetooth-ի աշխատաշրջանի բանալի"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-ի հետ կապի ընդունման ժամանակը սպառվեց"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-ով աշխատաշրջանի բանալու մուտքագրման ժամանակը սպառվեց"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Կասեցնել նույնականացման հարցումը"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Աշխատաշրջանի բանալի"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Մուտքագրեք աշխատաշրջանի բանալին %1$s-ի համար"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Անհայտ անուն"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Իմ անունը"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index f67d9ba..11d3f6a 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Batal"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Hidupkan"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transfer file"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" Ingin mengirimi Anda <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Terima file?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" Ingin mengirimi Anda <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Terima file?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Tolak"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Terima"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Oke"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Tutup"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Oke"</string>
<string name="unknown_file" msgid="6092727753965095366">"File tidak diketahui"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Tidak ada apl untuk menangani file jenis ini. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Tidak ada apl untuk menangani file jenis ini. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Tidak ada file"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"File tidak ada. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"File tidak ada. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Harap tunggu…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Menghidupkan Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"File akan diterima. Periksa kemajuan dalam panel Pemberitahuan."</string>
diff --git a/res/values-in/strings_map.xml b/res/values-in/strings_map.xml
new file mode 100644
index 0000000..3daabd9
--- /dev/null
+++ b/res/values-in/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Ketikkan kunci sesi untuk %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Perlu kunci sesi bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Waktu habis untuk menerima sambungan dengan %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Waktu habis untuk memasukkan kunci sesi dengan %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Permintaan autentikasi Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Kunci Sesi"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Ketik kunci sesi untuk %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nama tidak diketahui"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Nama saya"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 7b11df6..1f6236b 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Annulla"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Attiva"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Trasferimento file"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vuole inviarti <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Accetti il file?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" vuole inviarti <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Accetti il file?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Rifiuta"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accetta"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Chiudi"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"File sconosciuto"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Non sono disponibili applicazioni in grado di gestire questo tipo di file. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Non sono disponibili applicazioni in grado di gestire questo tipo di file. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nessun file"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Il file non esiste. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Il file non esiste. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Attendi..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Attivazione Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Il file verrà ricevuto. Controlla l\'avanzamento nel pannello Notifiche."</string>
diff --git a/res/values-it/strings_map.xml b/res/values-it/strings_map.xml
new file mode 100644
index 0000000..079267b
--- /dev/null
+++ b/res/values-it/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Digita la chiave di sessione per %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Chiave sessione Bluetooth necessaria"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Timeout per l\'accettazione della connessione con %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Timeout dell\'ingresso della chiave di sessione con %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Richiesta di autenticazione Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Chiave sessione"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Digita la chiave di sessione per %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit auto"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nome sconosciuto"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Il mio nome"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 5d615af..92e898a 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -17,37 +17,37 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="permlab_bluetoothShareManager" msgid="311492132450338925">"גישה למנהל ההורדות."</string>
- <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"מאפשר ליישום לגשת למנהל BluetoothShare ולהשתמש בו להעברת קבצים."</string>
- <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"הכנס מכשיר Bluetooth לרשימה הלבנה."</string>
- <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"מאפשר ליישום להכניס מכשיר Bluetooth באופן זמני לרשימה הלבנה, ובכך לאפשר למכשיר לשלוח קבצים למכשיר זה ללא אישור משתמש."</string>
- <string name="permlab_handoverStatus" msgid="7316032998801933554">"קבל שידורי העברת מסירה של Bluetooth."</string>
- <string name="permdesc_handoverStatus" msgid="4752738070064786310">"מאפשר קבלת מידע סטטוס של העברת מסירה מ-Bluetooth."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"מאפשר לאפליקציה לגשת למנהל BluetoothShare ולהשתמש בו להעברת קבצים."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"הכנס מכשיר Bluetooth לרשימה הלבנה."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"מאפשר לאפליקציה להכניס מכשיר Bluetooth באופן זמני לרשימה הלבנה, ובכך לאפשר למכשיר לשלוח קבצים למכשיר זה ללא אישור משתמש."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"קבל שידורי העברת מסירה של Bluetooth."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"מאפשר קבלת מידע סטטוס של העברת מסירה מ-Bluetooth."</string>
<string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
<string name="unknown_device" msgid="9221903979877041009">"מכשיר לא ידוע"</string>
<string name="unknownNumber" msgid="4994750948072751566">"לא ידוע"</string>
<string name="airplane_error_title" msgid="2683839635115739939">"מצב טיסה"</string>
- <string name="airplane_error_msg" msgid="8698965595254137230">"לא ניתן להשתמש ב-Bluetooth במצב טיסה."</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"לא ניתן להשתמש ב-Bluetooth במצב טיסה."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
- <string name="bt_enable_line1" msgid="7203551583048149">"כדי להשתמש בשירותי Bluetooth, עליך להפעיל תחילה את Bluetooth."</string>
- <string name="bt_enable_line2" msgid="4341936569415937994">"להפעיל Bluetooth כעת?"</string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"כדי להשתמש בשירותי Bluetooth, עליך להפעיל תחילה את Bluetooth."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"להפעיל Bluetooth כעת?"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"ביטול"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"הפעל"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"העברת קבצים"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" מעוניין לשלוח לך את <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" לקבל את הקובץ?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" מעוניין לשלוח לך את <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n לקבל את הקובץ?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"דחה"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"קבל"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"אישור"</string>
<string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"תם הזמן הקצוב לקבלת קובץ נכנס מאת \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
- <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"שיתוף Bluetooth: קובץ נכנס"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"שיתוף Bluetooth: קובץ נכנס"</string>
<string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"האם ברצונך לקבל קובץ זה?"</string>
<string name="incoming_file_toast_msg" msgid="1733710749992901811">"מכשיר אחר שולח אליך קובץ. אשר את קבלת הקובץ."</string>
- <string name="notification_receiving" msgid="4674648179652543984">"שיתוף Bluetooth: מקבל את <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_received" msgid="3324588019186687985">"שיתוף Bluetooth: התקבל <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_received_fail" msgid="3619350997285714746">"שיתוף Bluetooth: הקובץ <xliff:g id="FILE">%1$s</xliff:g> לא התקבל"</string>
- <string name="notification_sending" msgid="3035748958534983833">"שיתוף Bluetooth: שולח את <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_sent" msgid="9218710861333027778">"שיתוף Bluetooth: נשלח <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_sent_complete" msgid="302943281067557969">"הושלם ב-100%"</string>
- <string name="notification_sent_fail" msgid="6696082233774569445">"שיתוף Bluetooth: הקובץ <xliff:g id="FILE">%1$s</xliff:g> לא נשלח"</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"שיתוף Bluetooth: מקבל את <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"שיתוף Bluetooth: התקבל <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"שיתוף Bluetooth: הקובץ <xliff:g id="FILE">%1$s</xliff:g> לא התקבל"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"שיתוף Bluetooth: שולח את <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"שיתוף Bluetooth: נשלח <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"הושלם ב-100%"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"שיתוף Bluetooth: הקובץ <xliff:g id="FILE">%1$s</xliff:g> לא נשלח"</string>
<string name="download_title" msgid="3353228219772092586">"העברת קבצים"</string>
<string name="download_line1" msgid="4926604799202134144">"מאת: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
<string name="download_line2" msgid="5876973543019417712">"קובץ: <xliff:g id="FILE">%1$s</xliff:g>"</string>
@@ -73,19 +73,19 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"סגור"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"אישור"</string>
<string name="unknown_file" msgid="6092727753965095366">"קובץ לא ידוע"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"אין יישום המתאים לטיפול בקבצים מסוג זה. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"אין אפליקציה המתאימה לטיפול בקבצים מסוג זה. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"אין קובץ"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"הקובץ לא קיים. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"הקובץ לא קיים. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"המתן..."</string>
- <string name="enabling_progress_content" msgid="4601542238119927904">"מפעיל Bluetooth…"</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"מפעיל Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"הקובץ יתקבל. בדוק את ההתקדמות בחלונית \'התראות\'."</string>
<string name="bt_toast_2" msgid="8602553334099066582">"לא ניתן לקבל את הקובץ."</string>
<string name="bt_toast_3" msgid="6707884165086862518">"הופסקה קבלת קובץ מאת \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
<string name="bt_toast_4" msgid="4678812947604395649">"שולח קובץ אל \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
<string name="bt_toast_5" msgid="2846870992823019494">"שולח <xliff:g id="NUMBER">%1$s</xliff:g> קבצים אל \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
<string name="bt_toast_6" msgid="1855266596936622458">"שליחת קובץ אל \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" הופסקה"</string>
- <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"אין מספיק שטח פנוי באחסון ה-USB לשמירת הקובץ מאת <xliff:g id="SENDER">%1$s</xliff:g>"</string>
- <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"אין מספיק שטח אחסון בכרטיס ה-SD לשמירת הקובץ מאת <xliff:g id="SENDER">%1$s</xliff:g>"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"אין מספיק שטח פנוי באחסון ה-USB לשמירת הקובץ מאת <xliff:g id="SENDER">%1$s</xliff:g>"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"אין מספיק שטח אחסון בכרטיס ה-SD לשמירת הקובץ מאת <xliff:g id="SENDER">%1$s</xliff:g>"</string>
<string name="bt_sm_2_2" msgid="2965243265852680543">"שטח דרוש: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="ErrorTooManyRequests" msgid="8578277541472944529">"בקשות רבות מדי הועברו לעיבוד. נסה שוב מאוחר יותר."</string>
<string name="status_pending" msgid="2503691772030877944">"העברת הקובץ עדיין לא החלה."</string>
@@ -95,20 +95,20 @@
<string name="status_forbidden" msgid="613956401054050725">"מכשיר היעד לא התיר את ההעברה."</string>
<string name="status_canceled" msgid="6664490318773098285">"ההעברה בוטלה על ידי המשתמש."</string>
<string name="status_file_error" msgid="3671917770630165299">"בעיית אחסון."</string>
- <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"אין אחסון USB."</string>
- <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"אין כרטיס SD. הכנס כרטיס SD כדי לשמור קבצים שהועברו."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"אין אחסון USB."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"אין כרטיס SD. הכנס כרטיס SD כדי לשמור קבצים שהועברו."</string>
<string name="status_connection_error" msgid="947681831523219891">"החיבור נכשל."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"לא ניתן לטפל בבקשה כהלכה."</string>
<string name="status_unknown_error" msgid="8156660554237824912">"שגיאה לא ידועה."</string>
- <string name="btopp_live_folder" msgid="7967791481444474554">"התקבל באמצעות Bluetooth"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"התקבל באמצעות Bluetooth"</string>
<string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> שהתקבלו הושלמו."</string>
<string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> שנשלחו הושלמו."</string>
<string name="inbound_history_title" msgid="6940914942271327563">"העברות נכנסות"</string>
<string name="outbound_history_title" msgid="4279418703178140526">"העברות יוצאות"</string>
<string name="no_transfers" msgid="3482965619151865672">"היסטוריית ההעברות ריקה."</string>
<string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"כל הפריטים ינוקו מהרשימה."</string>
- <string name="outbound_noti_title" msgid="8051906709452260849">"שיתוף Bluetooth: נשלחו קבצים"</string>
- <string name="inbound_noti_title" msgid="4143352641953027595">"שיתוף Bluetooth: התקבלו קבצים"</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"שיתוף Bluetooth: נשלחו קבצים"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"שיתוף Bluetooth: התקבלו קבצים"</string>
<string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> הושלמו בהצלחה, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> לא הושלמו בהצלחה."</string>
<string name="transfer_menu_clear_all" msgid="790017462957873132">"נקה רשימה"</string>
<string name="transfer_menu_open" msgid="3368984869083107200">"פתח"</string>
diff --git a/res/values-iw/strings_map.xml b/res/values-iw/strings_map.xml
new file mode 100644
index 0000000..0ec79be
--- /dev/null
+++ b/res/values-iw/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"הקלד קוד הפעלה עבור %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"דרוש קוד הפעלה של Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"תם הזמן הקצוב לתפוגה של הסכמה לחיבור עם %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"תם הזמן הקצוב להזנת קוד הפעלה עם %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"בקשת אימות של Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"קוד הפעלה"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"הקלד קוד הפעלה עבור %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"דיבורית לרכב"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"שם לא ידוע"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"השם שלי"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-iw/strings_pbap.xml b/res/values-iw/strings_pbap.xml
index b4c1193..6e1e932 100644
--- a/res/values-iw/strings_pbap.xml
+++ b/res/values-iw/strings_pbap.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"הקלד קוד הפעלה עבור %1$s"</string>
- <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"דרוש קוד הפעלת Bluetooth"</string>
- <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"תם הזמן שהוקצב להסכמה לחיבור עם %1$s"</string>
- <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"תם הזמן הקצוב להזנת קוד הפעלה עם %1$s"</string>
- <string name="auth_notif_ticker" msgid="1575825798053163744">"בקשת אימות של Obex"</string>
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"הקלד קוד הפעלה עבור %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"דרוש קוד הפעלת Bluetooth"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"תם הזמן שהוקצב להסכמה לחיבור עם %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"תם הזמן הקצוב להזנת קוד הפעלה עם %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"בקשת אימות של Obex"</string>
<string name="auth_notif_title" msgid="7599854855681573258">"קוד הפעלה"</string>
- <string name="auth_notif_message" msgid="6667218116427605038">"הקלד קוד הפעלה עבור %1$s"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"הקלד קוד הפעלה עבור %1$s"</string>
<string name="defaultname" msgid="4821590500649090078">"דיבורית לרכב"</string>
<string name="unknownName" msgid="2841414754740600042">"שם לא ידוע"</string>
<string name="localPhoneName" msgid="2349001318925409159">"השם שלי"</string>
diff --git a/res/values-iw/test_strings.xml b/res/values-iw/test_strings.xml
index d37e421..3406186 100644
--- a/res/values-iw/test_strings.xml
+++ b/res/values-iw/test_strings.xml
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hello" msgid="1740533743008967039">"שלום לעולם, TestActivity"</string>
- <string name="app_name" msgid="1203877025577761792">"שיתוף Bluetooth"</string>
+ <string name="hello" msgid="1740533743008967039">"שלום לעולם, TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"שיתוף Bluetooth"</string>
<string name="insert_record" msgid="1450997173838378132">"הוסף רשומה"</string>
<string name="update_record" msgid="2480425402384910635">"אשר רשומה"</string>
<string name="ack_record" msgid="6716152390978472184">"אשר רשומה"</string>
<string name="deleteAll_record" msgid="4383349788485210582">"מחק את כל הרשומות"</string>
<string name="ok_button" msgid="6519033415223065454">"אישור"</string>
<string name="delete_record" msgid="4645040331967533724">"מחק רשומה"</string>
- <string name="start_server" msgid="9034821924409165795">"הפעל שרת TCP"</string>
- <string name="notify_server" msgid="4369106744022969655">"שלח התראה לשרת TCP"</string>
+ <string name="start_server" msgid="9034821924409165795">"הפעל שרת TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"שלח התראה לשרת TCP"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index aa6bc3e..fb1a134 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"キャンセル"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"ONにする"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"ファイル転送"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"「<xliff:g id="SENDER">%1$s</xliff:g>」が<xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>)を送信しようとしています。"\n\n"ファイルを受信しますか?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"「<xliff:g id="SENDER">%1$s</xliff:g>」が<xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>)を送信しようとしています。\n\nファイルを受信しますか?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"拒否"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"承諾"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"閉じる"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"不明なファイル"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"この形式のファイルを処理するアプリがありません。"\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"この形式のファイルを処理するアプリがありません。\n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"ファイルがありません"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"そのファイルは存在しません。"\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"そのファイルは存在しません。\n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"お待ちください..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"BluetoothをONにしています..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"ファイルを受信します。進行状況は[通知]パネルでご確認ください。"</string>
diff --git a/res/values-ja/strings_map.xml b/res/values-ja/strings_map.xml
new file mode 100644
index 0000000..e23017c
--- /dev/null
+++ b/res/values-ja/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$sのセッションキーを入力してください"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetoothセッションキーが必要です"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$sとの接続の承諾がタイムアウトになりました"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$sでのセッションキーの入力がタイムアウトになりました"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"OBEX認証リクエスト"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"セッションキー"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$sのセッションキーを入力してください"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"カーキット"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"不明な名前"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"名前"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..b87ec2f
--- /dev/null
+++ b/res/values-ka-rGE/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"ჩამოტვირთვების მენეჯერზე წვდომა."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"ანიჭებს აპს BluetoothShare მენეჯერზე წვდომას და მისი გამოყენების უფლებას ფაილების გასაგზავნად."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Bluetooth მოწყობილობის წვდომის თეთრ სიაში შეყვანა."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"საშუალებას აძლევს აპს, რომ დროებით თეთრ სიაში შეიყვანოს Bluetooth მოწყობილობა, რაც ამ მოწყობილობას საშუალებას მიცემს ფაილები ამ მოწყობილობაზე მომხმარებლის დასტურის გარეშე გამოაგზავნოს."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"BT ჰენდოვერის ტრანსფერის მაუწყებლობების მიღება."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"იძლევა Bluetooth-დან ჰენდოვერის ტრანსფერის სტატუსის მიღების საშუალებას."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"უცნობი მოწყობილობა"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"უცნობი"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"თვითმფრინავის რეჟიმი"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"თვითმფრინავის რეჟიმში Bluetooth-ს ვერ გამოიყენებთ."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Bluetooth სერვისების გამოსაყენებლად ჯერ Bluetooth უნდა ჩართოთ."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"გსურთ Bluetooth-ის ახლა ჩართვა?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"გაუქმება"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"ჩართვა"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"ფაილის ტრანსფერი"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>“ გიგზავნით <xliff:g id="FILE">%2$s</xliff:g>-ს (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n გსურთ ფაილის მიღება?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"უარყოფა"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"მიღება"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"კარგი"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"„<xliff:g id="SENDER">%1$s</xliff:g>“-გან ფაილის შემომავალი ფაილის მიღების დრო ამოიწურა"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth გაზიარება: შემომავალი ფაილი"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"გსურთ ამ ფაილის მიღება?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"შემომავალი ფაილი სხვა მოწყობილობიდან. დაადასტურეთ, რომ გსურთ ფაილის მიღება."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Bluetooth გაზიარება: <xliff:g id="FILE">%1$s</xliff:g> ფაილის მიღება"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Bluetooth გაზიარება: მიღებულია <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth გაზიარება: ფაილი <xliff:g id="FILE">%1$s</xliff:g> არ მიღებულა"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Bluetooth გაზიარება: <xliff:g id="FILE">%1$s</xliff:g>-ის გაგზავნა"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Bluetooth გაზიარება: გაიგზავნა <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"დასრულდა 100%"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetooth გაზიარება: ფაილი <xliff:g id="FILE">%1$s</xliff:g> არ გაიგზავნა"</string>
+ <string name="download_title" msgid="3353228219772092586">"ფაილის ტრანსფერი"</string>
+ <string name="download_line1" msgid="4926604799202134144">"გამგზავნი: „<xliff:g id="SENDER">%1$s</xliff:g>“"</string>
+ <string name="download_line2" msgid="5876973543019417712">"ფაილი: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"ფაილის ზომა: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"მიმდინარეობს ფაილის მიღება…"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"შეწყვეტა"</string>
+ <string name="download_ok" msgid="5000360731674466039">"დამალვა"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"ფაილი არ მიღებულა"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"ფაილი: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"მიზეზი: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"კარგი"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"ფაილი მიღებულია"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"გახსნა"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"მიმღები: „<xliff:g id="RECIPIENT">%1$s</xliff:g>“"</string>
+ <string name="upload_line3" msgid="4920689672457037437">"ფაილის ტიპი: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"ფაილი იგზავნება…"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"ფაილი გაიგზავნა"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"კარგი"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"ფაილი არ გაიგზავნა „<xliff:g id="RECIPIENT">%1$s</xliff:g>“-თან."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"ფაილი: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"კიდევ სცადეთ"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"დახურვა"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"კარგი"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"უცნობი ფაილი"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"არ არსებობს აპი, რომელიც ამ ფაილის ტიპის დაამუშავებს. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"ფაილი არ არის"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"ფაილი არ არსებობს. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"გთხოვთ, მოითმინოთ..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth-ის ჩართვა…"</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"ფაილი მიღებული იქნება. შეამოწმეთ პროგრესი შეტყობინებების დაფაზე."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"ფაილის მიღება ვერ ხერხდება."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"„<xliff:g id="SENDER">%1$s</xliff:g>“-დან ფაილის მიღება შეჩერდა"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"„<xliff:g id="RECIPIENT">%1$s</xliff:g>“-თან ფაილის გაგზავნა"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"<xliff:g id="NUMBER">%1$s</xliff:g> ფაილის „<xliff:g id="RECIPIENT">%2$s</xliff:g>“-თან გაგზავნა"</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"„<xliff:g id="RECIPIENT">%1$s</xliff:g>“-თან ფაილის გაგზავნა შეჩერდა"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"ფაილის „<xliff:g id="SENDER">%1$s</xliff:g>“-იდან შესანახად USB მეხსიერებაზე საკმარისი თავისუფალი სივრცე არ არის."</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"„<xliff:g id="SENDER">%1$s</xliff:g>“-იდან ფაილის შესანახად SD ბარათზე საკმარისი ისვრცე არ არის."</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"საჭირო სივრცე: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"მუშავდება ძალიან ბევრი პროცესი. შეეცადეთ მოგვიანებით."</string>
+ <string name="status_pending" msgid="2503691772030877944">"ფაილის ტრანსფერი ჯერ არ დაწყებულა."</string>
+ <string name="status_running" msgid="6562808920311008696">"მიმდინარეობს ფაილის ტრანსფერი."</string>
+ <string name="status_success" msgid="239573225847565868">"ფაილის ტრანსფერი წარმატებით დასრულდა."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"კონტენტი მხარდაჭერილი არ არის."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"ტრანსფერი აკრძალულია სამიზნე მოწყობილობის მიერ."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"ტრანსფერი გაუქმდა მომხმარებლის მიერ."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"მეხსიერების შეცდომა."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"USB მეხსიერება არ არის."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"SD ბარათი არ არის. ჩადეთ SD ბარათი გადმოგზავნილი ფაილების შესანახად."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"კავშირი ვერ განხორციელდა."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"მოთხოვნის სწორად დამუშავება ვერ ხერხდება."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"უცნობი შეცდომა."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth-ით მიღებული"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> მიღება დასრულდა."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> გაგზავნა დასრულდა."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"შემომავალი ტრანსფერები"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"გამავალი ტრანსფერები"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"ტრანსფერების ისტორია ცარიელია."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"სიიდან ყველა ერთეული ამოიშლება."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetooth გაზიარება: გაგზავნილი ფაილები"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth გაზიარება: მიღებული ფაილები"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> წარმატებით გადაიწერა, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> ვერ განხორციელდა."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"სიის გასუფთავება"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"გახსნა"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"სიიდან ამოშლა"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"ამოშლა"</string>
+</resources>
diff --git a/res/values-ka-rGE/strings_map.xml b/res/values-ka-rGE/strings_map.xml
new file mode 100644
index 0000000..8e645c4
--- /dev/null
+++ b/res/values-ka-rGE/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"სესიის გასაღები %1$s-ისთვის"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"აუცილებელია Bluetooth სესიის გასაღები"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-თან კავშირის მიღების დრო ამოიწურა"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-თან სესიის გასაღების შეყვანის დრო ამოიწურა"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex ავთენტიფიკაციის მოთხოვნა"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"სესიის გასაღები"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"სესიის გასაღები %1$s-ისთვის"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"მანქანის ნაკრები"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"უცნობი სახელი"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ჩემი სახელი"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ka-rGE/strings_pbap.xml b/res/values-ka-rGE/strings_pbap.xml
new file mode 100644
index 0000000..f160d08
--- /dev/null
+++ b/res/values-ka-rGE/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"სესსის გასაღები %1$s-ისთვის"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"აუცილებელია Bluetooth სესიის გასაღები"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"%1$s-თან კავშირის მიღების დრო ამოიწურა"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"%1$s-თან სესიის გასაღების შეყვანის დრო ამოიწურა"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Obex ავტენთიფიკაციის მოთხოვნა"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"სესიის გასაღები"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"სესსის გასაღები %1$s-ისთვის"</string>
+ <string name="defaultname" msgid="4821590500649090078">"მანქანის ნაკრები"</string>
+ <string name="unknownName" msgid="2841414754740600042">"უცნობი სახელი"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"ჩემი სახელი"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-ka-rGE/test_strings.xml b/res/values-ka-rGE/test_strings.xml
new file mode 100644
index 0000000..8723056
--- /dev/null
+++ b/res/values-ka-rGE/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"გაუმარჯოს! TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"Bluetooth გაზიარება"</string>
+ <string name="insert_record" msgid="1450997173838378132">"ჩანაწერის ჩასმა"</string>
+ <string name="update_record" msgid="2480425402384910635">"ჩანაწერის დადასტურება"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Ack ჩანაწერი"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"ყველა ჩანაწერის წაშლა"</string>
+ <string name="ok_button" msgid="6519033415223065454">"კარგი"</string>
+ <string name="delete_record" msgid="4645040331967533724">"ჩანაწერის წაშლა"</string>
+ <string name="start_server" msgid="9034821924409165795">"TCP სერვერის დაწყება"</string>
+ <string name="notify_server" msgid="4369106744022969655">"TCP სერვერის შეტყობინება"</string>
+</resources>
diff --git a/res/values-ka/strings_map.xml b/res/values-ka/strings_map.xml
new file mode 100644
index 0000000..8e645c4
--- /dev/null
+++ b/res/values-ka/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"სესიის გასაღები %1$s-ისთვის"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"აუცილებელია Bluetooth სესიის გასაღები"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-თან კავშირის მიღების დრო ამოიწურა"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-თან სესიის გასაღების შეყვანის დრო ამოიწურა"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex ავთენტიფიკაციის მოთხოვნა"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"სესიის გასაღები"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"სესიის გასაღები %1$s-ისთვის"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"მანქანის ნაკრები"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"უცნობი სახელი"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ჩემი სახელი"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..83a8fb2
--- /dev/null
+++ b/res/values-km-rKH/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"ចូលដំណើរការកម្មវិធីគ្រប់គ្រងការទាញយក។"</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"អនុញ្ញាតឲ្យកម្មវិធីត្រូវចូលដំណើរការកម្មវិធីគ្រប់គ្រង BluetoothShare ហើយប្រើវាដើម្បីផ្ទេរឯកសារ។"</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"បញ្ជីសការចូលដំណើរការប៊្លូធូស។"</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"ឲ្យកម្មវិធីដាក់ឧបករណ៍ប៊្លូធូសក្នុងបញ្ជីបណ្ដោះអាសន្ន ដែលអនុញ្ញាតឲ្យឧបករណ៍នោះ ផ្ញើឯកសារទៅកាន់ឧបករណ៍ដោយមិនចាំបាច់ការបញ្ជាក់អ្នកប្រើ។"</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"ទទួលការផ្សព្វផ្សាយការផ្ទេរ BT ។"</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"ឲ្យទទួលព័ត៌មានស្ថានភាពការផ្ទេរពីប៊្លូធូស។"</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"ប៊្លូធូស"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"មិនស្គាល់ឧបករណ៍"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"មិនស្គាល់"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"ពេលជិះយន្តហោះ"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"អ្នកមិនអាចប្រើប៊្លូធូសក្នុងពេលជិះយន្តហោះបានទេ"</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"ដើម្បីប្រើសេវាប៊្លូធូស ជាដំបូងអ្នកត្រូវតែបើកប៊្លូធូសសិន។"</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"បើកប៊្លូធូសឥឡូវនេះ?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"បោះបង់"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"បើក"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"ការផ្ទេរឯកសារ"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ចង់ផ្ញើ <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) ឲ្យអ្នក។ \n\n ទទួលឯកសារ?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"បោះបង់"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"ទទួល"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"យល់ព្រម"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"អស់ពេលទទួលឯកសារចូលពី \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"ការចែករំលែកប៊្លូធូស៖ ឯកសារចូល"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"តើអ្នកចង់ទទួលឯកសារនេះឬ?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"ឯកសារចូលពីឧបករណ៍ផ្សេងទៀត។ បញ្ជាក់ថាអ្នកចង់ទទួលបានឯកសារនេះ។"</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"ការចែករំលែកប៊្លូធូស៖ ទទួល <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"ការចែករំលែកប៊្លូធូស៖ បានទទួល <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"ការចែករំលែកប៊្លូធូស៖ មិនបានទទួលឯកសារ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"ការចែករំលែកប៊្លូធូស៖ ផ្ញើ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"ការចែករំលែកប៊្លូធូស៖ បានផ្ញើ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"បញ្ចប់ 100%"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"ការចែករំលែកប៊្លូធូស៖ មិនបានផ្ញើឯកសារ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_title" msgid="3353228219772092586">"ការផ្ទេរឯកសារ"</string>
+ <string name="download_line1" msgid="4926604799202134144">"ពី៖ \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"ឯកសារ៖ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"ទំហំឯកសារ៖ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"កំពុងទទួលឯកសារ…"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"បញ្ឈប់"</string>
+ <string name="download_ok" msgid="5000360731674466039">"លាក់"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"មិនបានទទួលឯកសារ"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"ឯកសារ៖ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"មូលហេតុ៖ <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"យល់ព្រម"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"បានទទួលឯកសារ"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"បើក"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"ទៅ៖ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"ប្រភេទឯកសារ៖ <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"កំពុងផ្ញើឯកសារ…"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"បានផ្ញើឯកសារ"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"យល់ព្រម"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"មិនបានផ្ញើឯកសារទៅ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" ។"</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"ឯកសារ៖ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"ព្យាយាមម្ដងទៀត"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"បិទ"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"យល់ព្រម"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"មិនស្គាល់ឯកសារ"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"គ្មានកម្មវិធីសម្រាប់គ្រប់គ្រងប្រភេទឯកសារនេះទេ។ \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"គ្មានឯកសារ"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"គ្មានឯកសារ។ \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"សូមរង់ចាំ..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"កំពុងបើកប៊្លូធូស…"</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"នឹងបានទទួលឯកសារ។ ពិនិត្យមើលវឌ្ឍនភាពនៅក្នុងផ្ទាំងជូនដំណឹង។"</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"មិនអាចទទួលឯកសារ។"</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"បានបញ្ឈប់ការទទួលឯកសារពី \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"ផ្ញើឯកសារទៅ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"ផ្ញើឯកសារ <xliff:g id="NUMBER">%1$s</xliff:g> ទៅ \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"បានបញ្ឈប់ការផ្ញើឯកសារទៅ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"ឧបករណ៍ផ្ទុកយូអេសប៊ីមិនមានទំហំគ្រប់គ្រាន់ ដើម្បីរក្សាទុកឯកសារពី \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"កាតអេសឌីមិនមានទំហំគ្រប់គ្រាន់ ដើម្បីរក្សាទុកឯកសារពី \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"ទំហំដែលត្រូវការ៖ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"កំពុងដំណើរការសំណើជាច្រើន។ សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string>
+ <string name="status_pending" msgid="2503691772030877944">"មិនទាន់បានចាប់ផ្ដើមផ្ទេរឯកសារនៅឡើយទេ។"</string>
+ <string name="status_running" msgid="6562808920311008696">"កំពុងបន្តការផ្ទេរឯកសារ។"</string>
+ <string name="status_success" msgid="239573225847565868">"ការផ្ទេរឯកសារបានបញ្ចប់ដោយជោគជ័យ។"</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"មិនបានគាំទ្រមាតិកា។"</string>
+ <string name="status_forbidden" msgid="613956401054050725">"ឧបករណ៍គោលដៅបានហាមឃាត់ការផ្ទេរ។"</string>
+ <string name="status_canceled" msgid="6664490318773098285">"អ្នកប្រើបានបោះបង់ការផ្ទេរ។"</string>
+ <string name="status_file_error" msgid="3671917770630165299">"បញ្ហាឧបករណ៍ផ្ទុក។"</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"គ្មានឧបករណ៍ផ្ទុកយូអេសប៊ី។"</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"គ្មានកាតអេសឌី។ បញ្ចូលកាតអេសឌី ដើម្បីរក្សាទុកឯកសារដែលបានផ្ទេរ។"</string>
+ <string name="status_connection_error" msgid="947681831523219891">"ការតភ្ជាប់មិនជោគជ័យ។"</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"មិនអាចដោះស្រាយសំណើដោយត្រឹមត្រូវទេ។"</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"មិនស្គាល់កំហុស។"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"បានទទួលប៊្លូធូស"</string>
+ <string name="download_success" msgid="7036160438766730871">"បានទទួលពេញលេញ <xliff:g id="FILE_SIZE">%1$s</xliff:g> ។"</string>
+ <string name="upload_success" msgid="4014469387779648949">"បានផ្ញើពេញលេញ <xliff:g id="FILE_SIZE">%1$s</xliff:g> ។"</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"ការផ្ទេរចូល"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"ការផ្ទេរចេញ"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"មិនមានប្រវត្តិផ្ទេរ។"</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"នឹងសម្អាតធាតុទាំងអស់ពីបញ្ជី។"</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"ការចែករំលែកប៊្លូធូស៖ បានផ្ញើឯកសារ"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"ការចែករំលែកប៊្លូធូស៖ បានទទួលឯកសារ"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"ជោគជ័យ <xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> បរាជ័យ <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> ។"</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"សម្អាតបញ្ជី"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"បើក"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"សម្អាតពីបញ្ជី"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"សម្អាត"</string>
+</resources>
diff --git a/res/values-km-rKH/strings_map.xml b/res/values-km-rKH/strings_map.xml
new file mode 100644
index 0000000..8118669
--- /dev/null
+++ b/res/values-km-rKH/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"បានទាមទារសោសម័យប៊្លូធូស"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"អស់ពេលវេលាក្នុងការទទួលយកការតភ្ជាប់ជាមួយ %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"អស់ពេលដើម្បីបញ្ចូលសោសម័យជាមួយ %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"សំណើការផ្ទៀងផ្ទាត់ Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"សោសម័យ"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"មិនស្គាល់ឈ្មោះ"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ឈ្មោះរបស់ខ្ញុំ"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-km-rKH/strings_pbap.xml b/res/values-km-rKH/strings_pbap.xml
new file mode 100644
index 0000000..b175936
--- /dev/null
+++ b/res/values-km-rKH/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"បានទាមទារសោសម័យប៊្លូធូស"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"អស់ពេលវេលាក្នុងការទទួលយកការតភ្ជាប់ជាមួយ %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"អស់ពេលដើម្បីបញ្ចូលសោសម័យជាមួយ %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"សំណើការផ្ទៀងផ្ទាត់ Obex"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"សោសម័យ"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Carkit"</string>
+ <string name="unknownName" msgid="2841414754740600042">"មិនស្គាល់ឈ្មោះ"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"ឈ្មោះរបស់ខ្ញុំ"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-km-rKH/test_strings.xml b/res/values-km-rKH/test_strings.xml
new file mode 100644
index 0000000..f35bc4a
--- /dev/null
+++ b/res/values-km-rKH/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"សួស្ដី TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"ការចែករំលែកប៊្លូធូស"</string>
+ <string name="insert_record" msgid="1450997173838378132">"បញ្ចូលកំណត់ត្រា"</string>
+ <string name="update_record" msgid="2480425402384910635">"បញ្ជាក់កំណត់ត្រា"</string>
+ <string name="ack_record" msgid="6716152390978472184">"កំណត់ត្រាការទទួលស្គាល់"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"លុបកំណត់ត្រាទាំងអស់"</string>
+ <string name="ok_button" msgid="6519033415223065454">"យល់ព្រម"</string>
+ <string name="delete_record" msgid="4645040331967533724">"លុបកំណត់ត្រា"</string>
+ <string name="start_server" msgid="9034821924409165795">"ចាប់ផ្ដើមម៉ាស៊ីនមេ TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"ជូនដំណឹងម៉ាស៊ីនមេ TCP"</string>
+</resources>
diff --git a/res/values-km/strings_map.xml b/res/values-km/strings_map.xml
new file mode 100644
index 0000000..8118669
--- /dev/null
+++ b/res/values-km/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"បានទាមទារសោសម័យប៊្លូធូស"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"អស់ពេលវេលាក្នុងការទទួលយកការតភ្ជាប់ជាមួយ %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"អស់ពេលដើម្បីបញ្ចូលសោសម័យជាមួយ %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"សំណើការផ្ទៀងផ្ទាត់ Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"សោសម័យ"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"បញ្ចូលសោសម័យសម្រាប់ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"មិនស្គាល់ឈ្មោះ"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ឈ្មោះរបស់ខ្ញុំ"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f8c73be..31270de 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"취소"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"사용"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"파일 전송"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\'<xliff:g id="SENDER">%1$s</xliff:g>\'님이 <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>)을(를) 보내려고 합니다. "\n\n" 파일을 수락하시겠습니까?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\'<xliff:g id="SENDER">%1$s</xliff:g>\'님이 <xliff:g id="FILE">%2$s</xliff:g>(<xliff:g id="SIZE">%3$s</xliff:g>)을(를) 보내려고 합니다. \n\n 파일을 수락하시겠습니까?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"거부"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"수락"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"확인"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"닫기"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"확인"</string>
<string name="unknown_file" msgid="6092727753965095366">"알 수 없는 파일"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"이러한 형식의 파일을 처리할 앱이 없습니다. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"이러한 형식의 파일을 처리할 앱이 없습니다. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"파일 없음"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"파일이 없습니다. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"파일이 없습니다. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"잠시 기다려 주세요."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"블루투스 켜는 중..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"파일이 수신됩니다. 알림 패널에서 진행률을 확인하세요."</string>
diff --git a/res/values-ko/strings_map.xml b/res/values-ko/strings_map.xml
new file mode 100644
index 0000000..2789943
--- /dev/null
+++ b/res/values-ko/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s의 세션 키 입력"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"블루투스 세션 키 필요"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s 연결 수락 제한 시간이 초과되었습니다."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s에 세션 키 입력 제한 시간이 초과되었습니다."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex 인증 요청"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"세션 키"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s의 세션 키 입력"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"알 수 없는 이름"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"내 이름"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..61c1233
--- /dev/null
+++ b/res/values-lo-rLA/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"ເຂົ້າເຖິງໂຕຈັດການການດາວໂຫລດ."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"ອະນຸຍາດໃຫ້ແອັບຯນີ້ເຂົາເຖິງໂຕຈັດການ BluetoothShare ແລະໃຊ້ມັນເພື່ອສົ່ງໄຟລ໌."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"ເຮັດບັນຊີອະນຸຍາດການເຂົ້າເຖິງອຸປະກອນ bluetooth."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວຕັ້ງບັນຊີຂາວໃຫ້ກັບອຸປະກອນ Bluetooth ຊົ່ວຄາວ, ການອະນຸຍາດໃຫ້ອຸປະກອນນັ້ນສົ່ງໄຟລ໌ມາທີ່ອຸປະກອນນີ້ໂດຍທີ່ບໍ່ຈຳເປັນຕ້ອງມີການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"ຮັບສັນຍານການໂອນໄຟລ໌ BT handover."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"ອະນຸຍາດການຮັບຂໍ້ມູນສະຖານະການໂອນຈາກ Bluetooth."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"ອຸປະກອນທີ່ບໍ່ຮູ້ຈັກ"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"ບໍ່ຮູ້ຈັກ"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"ໂໝດຢູ່ເທິງຍົນ"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"ທ່ານບໍ່ສາມາດໃຊ້ Bluetooth ໃນໂໝດຢູ່ເທິງຍົນໄດ້."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"ໃນການນຳໃຊ້ບໍລິການ Bluetooth, ທ່ານຕ້ອງເປີດ Bluetooth ກ່ອນ."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"ເປີດ Bluetooth ດຽວນີ້ບໍ່?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"ຍົກເລີກ"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"ເປີດ"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"ການໂອນໄຟລ໌"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ຕ້ອງການທີ່ຈະສົ່ງ <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) ໃຫ້ທ່ານ. \n\n ຮັບເອົາໄຟລ໌ດັ່ງກ່າວບໍ່?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"ປະຕິເສດ"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"ຮັບເອົາ"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ຕົກລົງ"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"ເກີດມີການໝົດເວລາໃນລະຫວ່າງທີ່ກຳລັງຮັບເອົາໄຟລ໌ທີ່ເຂົ້າມາຈາກ \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"ແບ່ງປັນໃນ Bluetooth: ມີໄຟລ໌ເຂົ້າມາ"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"ທ່ານຕ້ອງການທີ່ຮັບເອົາໄຟລ໌ນີ້ບໍ່?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"ມີໄຟລ໌ກຳລັງເຂົ້າມາຈາກອຸປະກອນອື່ນ. ຢືນຢັນວ່າທ່ານຕ້ອງການຮັບເອົາໄຟລ໌ນີ້."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"ແບ່ງປັນໃນ Bluetooth: ກຳລັງຮັບເອົາ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"ແບ່ງປັນໃນ Bluetooth: ໄດ້ຮັບ <xliff:g id="FILE">%1$s</xliff:g> ແລ້ວ"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"ແບ່ງປັນໃນ Bluetooth: ບໍ່ໄດ້ຮັບ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"ແບ່ງປັນໃນ Bluetooth: ກຳລັງສົ່ງ <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"ແບ່ງປັນໃນ Bluetooth: ສົ່ງ <xliff:g id="FILE">%1$s</xliff:g> ແລ້ວ"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100% ສໍາເລັດແລ້ວ"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"ແບ່ງປັນໃນ Bluetooth: ໄຟລ໌<xliff:g id="FILE">%1$s</xliff:g> ບໍ່ໄດ້ຖືກສົ່ງ"</string>
+ <string name="download_title" msgid="3353228219772092586">"ໂອນໄຟລ໌"</string>
+ <string name="download_line1" msgid="4926604799202134144">"ຈາກ: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"ໄຟລ໌: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"ຂະໜາດໄຟລ໌: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"ກຳລັງຮັບເອົາໄຟລ໌..."</string>
+ <string name="download_cancel" msgid="9177305996747500768">"ຢຸດ"</string>
+ <string name="download_ok" msgid="5000360731674466039">"ເຊື່ອງ"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"ໄຟລ໌ບໍ່ໄດ້ຮັບ"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"ໄຟລ໌: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"ເຫດຜົນ: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"ຕົກລົງ"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"ໄດ້ຮັບໄຟລ໌ແລ້ວ"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"ເປີດ"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"ເຖິງ: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"ປະເພດຂອງໄຟລ໌: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"ກຳລັງສົ່ງໄຟລ໌..."</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"ໄຟລ໌ຖືກສົ່ງແລ້ວ"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"ຕົກລົງ"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"ໄຟລ໌ດັ່ງກ່າວບໍ່ໄດ້ຖືກສົ່ງໄປທີ່ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"ໄຟລ໌: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"ລອງອີກຄັ້ງ"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"ປິດ"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"ໄຟລ໌ທີ່ບໍ່ຮູ້ຈັກ"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"ບໍ່ມີແອັບຯໃດຈັດການໄຟລ໌ປະເພດນີ້ໄດ້. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"ບໍ່ມີໄຟລ໌"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"ໄຟລ໌ດັ່ງກ່າວບໍ່ມີຢູ່ \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"ກະລຸນາລໍຖ້າ..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"ກຳລັງເປີດ Bluetooth..."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"ຈະໄດ້ຮັບໄຟລ໌ດັ່ງກ່າວ. ກວດສອບການດຳເນີນການໃນແຜງການແຈ້ງເຕືອນ."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"ບໍ່ສາມາດຮັບໄຟລ໌ໄດ້."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"ຢຸດການຮັບໄຟລ໌ຈາກ \"<xliff:g id="SENDER">%1$s</xliff:g>\" ແລ້ວ"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"ກຳລັງສົ່ງໄຟລ໌ໄປຫາ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"ກຳລັງສົ່ງ <xliff:g id="NUMBER">%1$s</xliff:g> ໄຟລ໌ໄປຫາ \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"ຢຸດການສົ່ງໄຟລ໌ໄປຫາ \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" ແລ້ວ"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB ບໍ່ພຽງພໍທີ່ຈະບັນທຶກໄຟລ໌ດັ່ງກ່າວຈາກ \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"ບ່ອນຈັດເກັບຂໍ້ມູນ SD card ບໍ່ພຽງພໍທີ່ຈະບັນທຶກໄຟລ໌ດັ່ງກ່າວຈາກ \"<xliff:g id="SENDER">%1$s</xliff:g>\" ໄດ້"</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"ພື້ນທີ່ທີ່ຕ້ອງການ: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"ມີການຮ້ອງຂໍຫຼາຍເກີນໄປ, ກະລຸນາລອງໃໝ່ພາຍຫຼັງ."</string>
+ <string name="status_pending" msgid="2503691772030877944">"ການໂອນໄຟລ໌ຍັງບໍ່ທັນໄດ້ເລີ່ມເທື່ອ."</string>
+ <string name="status_running" msgid="6562808920311008696">"ການໂອນໄຟລ໌ກຳລັງດຳເນີນຢູ່."</string>
+ <string name="status_success" msgid="239573225847565868">"ການໂອນໄຟລ໌ສຳເລັດແລ້ວ."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"ເນື້ອຫາບໍ່ໄດ້ຖືກຮອງຮັບ."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"ການໂອນໄຟລ໌ຖືກປິດກັ້ນໂດຍອຸປະກອນປາຍທາງ."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"ການໂອນຖືກຍົກເລີກໂດຍຜູ່ໃຊ້."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"ປັນຫາພື້ນທີ່ເກັບຂໍ້ມູນ."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"ບໍ່ມີບ່ອນຈັດເກັບຂໍ້ມູນ USB."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"ບໍ່ມີ SD card. ໃສ່ SD card ເພື່ອບັນທຶກໄຟລ໌ທີ່ໂອນມາ."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"ການເຊື່ອມຕໍ່ບໍ່ສຳເລັດຜົນ"</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"ການຮ້ອງຂໍບໍ່ສາມາດຖືກຈັດການໄດ້ຢ່າງຖືກຕ້ອງ."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"ຄວາມຜິດພາດທີ່ບໍ່ຮູ້ຈັກ."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"ໄຟລ໌ທີ່ໄດ້ຮັບແລ້ວຈາກ Bluetooth"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> ໄດ້ຮັບຮຽບຮ້ອຍແລ້ວ."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> ຖືກສົ່ງສຳເລັດແລ້ວ."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"ການໂອນເຂົ້າ"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"ການໂອນອອກ"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"ປະຫວັດການໂອນຫວ່າງເປົ່າ."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"ລາຍການທັງໝົດຈະຖືກລຶບອອກຈາກລາຍການດັ່ງກ່າວ."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"ແບ່ງປັນໃນ Bluetooth: ໄຟລ໌ສົ່ງແລ້ວ"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"ແບ່ງປັນໃນ Bluetooth: ໄຟລ໌ໄດ້ຮັບແລ້ວ"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> ສຳເລັດແລ້ວ, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> ບໍ່ສຳເລັດ."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"ລຶບລາຍການ"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"ເປີດ"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"ລຶບອອກຈາກລາຍການ"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"ລຶບ"</string>
+</resources>
diff --git a/res/values-lo-rLA/strings_map.xml b/res/values-lo-rLA/strings_map.xml
new file mode 100644
index 0000000..dd3a288
--- /dev/null
+++ b/res/values-lo-rLA/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"ຕ້ອງມີ Bluetooth ລະຫັດເຊສຊັນ"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"ໝົດເວລາທີ່ຈະຮັບການເຊື່ອມຕໍ່ກັບ %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"ເກີດໝົດເວລາກ່ອນທີ່ຈະໃສ່ລະຫັດເຊສຊັນກັບ %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"ການຮ້ອງຂໍພິສູດຢືນຢັນໂຕ Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"ກະແຈເຊສຊັສ"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"ບໍ່ຮູ້ຊື່"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ຊື່ຂອງຂ້ອຍ"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-lo-rLA/strings_pbap.xml b/res/values-lo-rLA/strings_pbap.xml
new file mode 100644
index 0000000..0ccdd49
--- /dev/null
+++ b/res/values-lo-rLA/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"ຕ້ອງມີ Bluetooth ລະຫັດເຊສຊັນ"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"ໝົດເວລາທີ່ຈະຮັບການເຊື່ອມຕໍ່ກັບ %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"ເກີດໝົດເວລາກ່ອນທີ່ຈະໃສ່ລະຫັດເຊສຊັນກັບ %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"ການຮ້ອງຂໍພິສູດຢືນຢັນໂຕ Obex"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"ກະແຈເຊສຊັນ"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Carkit"</string>
+ <string name="unknownName" msgid="2841414754740600042">"ບໍ່ຮູ້ຊື່"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"ຊື່ຂອງຂ້ອຍ"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-lo-rLA/test_strings.xml b/res/values-lo-rLA/test_strings.xml
new file mode 100644
index 0000000..778583b
--- /dev/null
+++ b/res/values-lo-rLA/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"ສະບາຍດີ, ການເຮັດວຽກທົດສອບ"</string>
+ <string name="app_name" msgid="1203877025577761792">"ແບ່ງປັນໃນ Bluetooth"</string>
+ <string name="insert_record" msgid="1450997173838378132">"ໃສ່ບັນທຶກ"</string>
+ <string name="update_record" msgid="2480425402384910635">"ຢືນຢັນການບັນທຶກ"</string>
+ <string name="ack_record" msgid="6716152390978472184">"ບັນທຶກ Ack"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"ລຶບບັນທຶກທັງໝົດ"</string>
+ <string name="ok_button" msgid="6519033415223065454">"ຕົກລົງ"</string>
+ <string name="delete_record" msgid="4645040331967533724">"ລຶບການບັນທຶກ"</string>
+ <string name="start_server" msgid="9034821924409165795">"ເລີ່ມ TCP ເຊີບເວີ"</string>
+ <string name="notify_server" msgid="4369106744022969655">"ແຈ້ງເຕືອນ TCP ເຊີບເວີ"</string>
+</resources>
diff --git a/res/values-lo/strings_map.xml b/res/values-lo/strings_map.xml
new file mode 100644
index 0000000..dd3a288
--- /dev/null
+++ b/res/values-lo/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"ຕ້ອງມີ Bluetooth ລະຫັດເຊສຊັນ"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"ໝົດເວລາທີ່ຈະຮັບການເຊື່ອມຕໍ່ກັບ %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"ເກີດໝົດເວລາກ່ອນທີ່ຈະໃສ່ລະຫັດເຊສຊັນກັບ %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"ການຮ້ອງຂໍພິສູດຢືນຢັນໂຕ Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"ກະແຈເຊສຊັສ"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"ພິມລະຫັດເຊສຊັນສຳລັບ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"ບໍ່ຮູ້ຊື່"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ຊື່ຂອງຂ້ອຍ"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4c3c44b..86ba0c4 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Atšaukti"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Įjungti"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Failo perkėlimas"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> nori jums atsiųsti <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Priimti failą?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> nori jums atsiųsti <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Priimti failą?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Atmesti"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Priimti"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Gerai"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Uždaryti"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Gerai"</string>
<string name="unknown_file" msgid="6092727753965095366">"Nežinomas failas"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Nėra programos, kurią naudojant būtų galima tvarkyti šio tipo failą. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Nėra programos, kurią naudojant būtų galima tvarkyti šio tipo failą. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nėra failų"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Failas neegzistuoja. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Failas neegzistuoja. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Palaukite..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Įjungiamas „Bluetooth“…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Failas bus gautas. Patikrinkite eigą skydelyje „Pranešimai“."</string>
diff --git a/res/values-lt/strings_map.xml b/res/values-lt/strings_map.xml
new file mode 100644
index 0000000..4441b07
--- /dev/null
+++ b/res/values-lt/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Įveskite %1$s seanso raktą"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Reikalingas „Bluetooth“ seanso raktas"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Baigėsi skirtasis ryšio su %1$s priėmimo laikas"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Baigėsi įvesties seanso rakto su %1$s skirtasis laikas"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"„Obex“ tapatybės nustatymo užklausa"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Seanso raktas"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Įveskite %1$s seanso raktą"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Automobilinė įranga"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nežinomas pavadinimas"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mano vardas"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e5a457e..1bcd05f 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Atcelt"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Ieslēgt"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Faila pārsūtīšana"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> vēlas nosūtīt jums failu <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>)."\n\n"Vai pieņemt šo failu?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> vēlas nosūtīt jums failu <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>).\n\nVai pieņemt šo failu?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Noraidīt"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Piekrist"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Labi"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Aizvērt"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Labi"</string>
<string name="unknown_file" msgid="6092727753965095366">"Nezināms fails"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Nav nevienas lietotnes, ar kuru var apstrādāt šī tipa failu. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Nav nevienas lietotnes, ar kuru var apstrādāt šī tipa failu. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nav faila"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Šāds fails nepastāv. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Šāds fails nepastāv. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Lūdzu, uzgaidiet…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Tiek ieslēgts Bluetooth savienojums..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Fails tiks saņemts. Skatiet progresu paziņojumu panelī."</string>
diff --git a/res/values-lv/strings_map.xml b/res/values-lv/strings_map.xml
new file mode 100644
index 0000000..a60fd69
--- /dev/null
+++ b/res/values-lv/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Ierīces “%1$s” sesijas atslēgas ievadīšana"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Nepieciešama Bluetooth sesijas atslēga"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Radās noildze, apstiprinot savienojumu ar ierīci “%1$s”."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Radās noildze, ievadot ierīces “%1$s” sesijas atslēgu."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex autentifikācijas pieprasījums"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sesijas atslēga"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Ievadiet ierīces “%1$s” sesijas atslēgu."</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Automobiļa komplekts"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nezināms nosaukums"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mans vārds"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..c35997d
--- /dev/null
+++ b/res/values-mn-rMN/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Татан авалтын менежерт хандалт хийх."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Апп-д BluetoothShare менежерт хандах, үүнийг ашиглан файл дамжуулах боломж олгоно."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Цагаан жагсаалтаар bluetooth төхөөрөмжид хандалт хийх."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Апп-т Bluetooth төхөөрөмжийг цагаан жагсаалтад оруулж хэрэглэгчийн баталгаажуулалт шаардахгүйгээр тус төхөөрөмж рүү файл илгээх боломж олгоно."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"BT дамжуулалтын нэвтрүүлгийг хүлээн авах."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Bluetooth-с дамжуулалтын статусын мэдээллийг хүлээн авах боломж олгоно."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Үл мэдэгдэх төхөөрөмж"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Тодорхойгүй"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Нислэгийн горим"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Та Нислэгийн горимд Bluetooth ашиглах боломжгүй."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Bluetooth үйлчилгээг ашиглахын тулд та эхлээд Bluetooth-ээ асаах шаардлагатай."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Bluetooth-г одоо асаах уу?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Цуцлах"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Асаах"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"Файл дамжуулалт"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" танд <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>)-г илгээхийг хүсэж байна. \n\n Энэ файлыг авах уу?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Татгалзах"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Зөвшөөрөх"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Тийм"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"\"<xliff:g id="SENDER">%1$s</xliff:g>\"-с ирж байгаа файлыг зөвшөөрөх явцад хугацаа хэтэрсэн байна"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth хуваалцах: Ирж байгаа файл"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Та энэ файлыг хүлээн авахыг хүсэж байна уу?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Өөр төхөөрөмжөөс ирж байгаа файл. Та энэ файлыг хүлээн авахыг хүсэж байгаагаа баталгаажуулна уу."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Bluetooth хуваалцах: Хүлээн авч байна <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Bluetooth хуваалцах: Хүлээн авсан <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Bluetooth хуваалцах: Файл <xliff:g id="FILE">%1$s</xliff:g> хүлээж аваагүй"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Bluetooth хуваалцах: Илгээж байна <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Bluetooth хуваалцах: Илгээсэн <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"100% дууссан"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Bluetooth хуваалцах: <xliff:g id="FILE">%1$s</xliff:g> файл илгээгдээгүй"</string>
+ <string name="download_title" msgid="3353228219772092586">"Файл дамжуулалт"</string>
+ <string name="download_line1" msgid="4926604799202134144">"Илгээгч: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"Файл: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"Файлын хэмжээ: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Файлыг хүлээн авч байна…"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Зогсоох"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Нуух"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"Файлыг хүлээж аваагүй"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"Файл: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Шалтгаан: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"Тийм"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"Файлыг хүлээж авсан"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Нээх"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"Хэнд: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"Файлын хэлбэр: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Файл илгээж байна…"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"Файлыг илгээсэн"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"Тийм"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"Файл \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" руу илгээгдсэнгүй."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"Файл: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Дахин оролдоно уу"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Хаах"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"Тийм"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Үл мэдэгдэх файл"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Ийм төрлийн файлыг нээх апп байхгүй байна. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"Файл байхгүй"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл байхгүй байна. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Түр хүлээнэ үү..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth-г асааж байна…"</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"Файлыг хүлээж авах болно. Мэдэгдлийн самбар дээрээс явцыг нь шалгана уу."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"Файлыг хүлээн авах боломжгүй."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"\"<xliff:g id="SENDER">%1$s</xliff:g>\"-с файл хүлээн авахыг зогсоосон"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"\"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" руу файлыг илгээж байна"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"<xliff:g id="NUMBER">%1$s</xliff:g> файлуудыг \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\" руу илгээж байна"</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"\"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" руу файл илгээхийн зогсоосон"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"USB сан дотор \"<xliff:g id="SENDER">%1$s</xliff:g>\"-с ирүүлсэн файлыг хадгалах хангалттай зай байхгүй байна"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"SD карт дээр \"<xliff:g id="SENDER">%1$s</xliff:g>\"-с ирүүлсэн файлыг хадгалах хангалттай зай байхгүй байна"</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Шаардлагатай зай: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Хэт олон хүсэлтийг боловсруулж байна. Дараа дахин оролдоно уу."</string>
+ <string name="status_pending" msgid="2503691772030877944">"Файл дамжуулалт хараахан эхлээгүй байна."</string>
+ <string name="status_running" msgid="6562808920311008696">"Файл дамжуулалт үргэлжилж байна."</string>
+ <string name="status_success" msgid="239573225847565868">"Файл дамжуулалт амжилттай дууслаа."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Контент дэмжигдэхгүй байна."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"Дамжуулалтыг хүлээн авагч төхөөрөмжөөс хориглосон."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Дамжуулалтыг хэрэглэгч цуцалсан."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Хадгалах сангийн асуудал."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"USB сан алга байна."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"SD карт алга байна. Дамжуулсан файлуудыг хадгалахын тулд SD карт хийнэ үү."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Холболт амжилтгүй."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Хүсэлтийг зөв гүйцэтгэх боломжгүй."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Тодорхойгүй алдаа."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth хүлээж авсан"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Бүрэн хүлээж авсан."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Илгээж дууссан."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Дотогш чиглэсэн дамжуулалт"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Гадагш чиглэсэн дамжуулалт"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"Дамжуулсан түүх хоосон байна."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Жагсаалтаас бүгдийг нь арилгах болно."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Bluetooth хуваалцах: Илгээсэн файлууд"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth хуваалцах: Хүлээн авсан файлууд"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> амжилттай, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> амжилтгүй."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Жагсаалтыг арилгах"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"Нээх"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Жагсаалтаас арилгах"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Арилгах"</string>
+</resources>
diff --git a/res/values-mn-rMN/strings_map.xml b/res/values-mn-rMN/strings_map.xml
new file mode 100644
index 0000000..45fc07d
--- /dev/null
+++ b/res/values-mn-rMN/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Блютүүт горимын түлхүүр шаардлагатай"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-тай холболт хийхийг зөвшөөрөх явцад хугацаа хэтэрсэн байна"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-д горимын түлхүүр оруулах явцад хугацаа хэтэрсэн байна"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex гэрчлэлтийн хүсэлт"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Горимын Түлхүүр"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Тодорхойгүй нэр"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Миний нэр"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-mn-rMN/strings_pbap.xml b/res/values-mn-rMN/strings_pbap.xml
new file mode 100644
index 0000000..121d32a
--- /dev/null
+++ b/res/values-mn-rMN/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Bluetooth горимын түлхүүр шаардлагатай"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"%1$s-тай холболт хийхийг зөвшөөрөх явцад хугацаа хэтэрсэн байна"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"%1$s-д горимын түлхүүр оруулах явцад хугацаа хэтэрсэн байна"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Obex гэрчлэлтийн хүсэлт"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Горимын Түлхүүр"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Carkit"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Тодорхойгүй нэр"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"Миний нэр"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-mn-rMN/test_strings.xml b/res/values-mn-rMN/test_strings.xml
new file mode 100644
index 0000000..43e8d2e
--- /dev/null
+++ b/res/values-mn-rMN/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Сайн уу, TestActivity"</string>
+ <string name="app_name" msgid="1203877025577761792">"Bluetooth Хуваалцах"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Бичлэг оруулах"</string>
+ <string name="update_record" msgid="2480425402384910635">"Бичлэгийг баталгаажуулах"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Ack бичлэг"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Бүх бичлэгийг устгах"</string>
+ <string name="ok_button" msgid="6519033415223065454">"Тийм"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Бичлэгийг устгах"</string>
+ <string name="start_server" msgid="9034821924409165795">"TCP серверийг эхлүүлэх"</string>
+ <string name="notify_server" msgid="4369106744022969655">"TCP серверт мэдэгдэх"</string>
+</resources>
diff --git a/res/values-mn/strings_map.xml b/res/values-mn/strings_map.xml
new file mode 100644
index 0000000..45fc07d
--- /dev/null
+++ b/res/values-mn/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Блютүүт горимын түлхүүр шаардлагатай"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s-тай холболт хийхийг зөвшөөрөх явцад хугацаа хэтэрсэн байна"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s-д горимын түлхүүр оруулах явцад хугацаа хэтэрсэн байна"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex гэрчлэлтийн хүсэлт"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Горимын Түлхүүр"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s-н горимын түлхүүрийг оруулна уу"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Тодорхойгүй нэр"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Миний нэр"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..84c29e9
--- /dev/null
+++ b/res/values-ms-rMY/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Akses pengurus muat turun."</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Membenarkan aplikasi mengakses pengurus Perkongsian Bluetooth dan menggunakannya untuk memindahkan fail."</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Akses peranti bluetooth senarai putih."</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Membenarkan apl untuk menyenarai putihkan peranti Bluetooth sementara waktu, membolehkan peranti itu menghantar fail ke peranti ini tanpa pengesahan pengguna."</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"Terima siaran pemindahan penyerahan BT."</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"Membolehkan penerimaan maklumat status pemindahan penyerahan dari Bluetooth."</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"Peranti tidak diketahui"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"Tidak diketahui"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Mod pesawat"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Anda tidak boleh menggunakan Bluetooth dalam mod Pesawat."</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Untuk menggunakan perkhidmatan Bluetooth, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Hidupkan Bluetooth sekarang?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"Batal"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"Hidupkan"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"Pemindahan fail"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" mahu menghantar <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) kepada anda. \n\n Terima fail?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Tolak"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"Terima"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"Berlaku tamat masa semasa menerima fail masuk daripada \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Perkongsian Bluetooth: Fail masuk"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Adakah anda mahu menerima fail ini?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"Fail masuk daripada peranti lain. Sila sahkan bahawa anda mahu menerima fail ini."</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"Perkongsian Bluetooth: Menerima <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Perkongsian Bluetooth: Diterima <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"Perkongsian Bluetooth: Fail <xliff:g id="FILE">%1$s</xliff:g> tidak diterima"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"Perkongsian Bluetooth: Menghantar <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Perkongsian Bluetooth: Dihantar <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"Selesai 100%"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"Perkongsian Bluetooth: Fail <xliff:g id="FILE">%1$s</xliff:g> tidak dihantar"</string>
+ <string name="download_title" msgid="3353228219772092586">"Pemindahan fail"</string>
+ <string name="download_line1" msgid="4926604799202134144">"Daripada: \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="download_line2" msgid="5876973543019417712">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"Saiz fail: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"Menerima fail..."</string>
+ <string name="download_cancel" msgid="9177305996747500768">"Berhenti"</string>
+ <string name="download_ok" msgid="5000360731674466039">"Sembunyi"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"Fail tidak diterima"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"Sebab: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"OK"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"Fail diterima"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"Buka"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"Kepada: \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="upload_line3" msgid="4920689672457037437">"Jenis fail: <xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"Menghantar fail..."</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"Fail telah dihantar"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"OK"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"Fail tidak dihantarkan kepada \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\"."</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"Fail: <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"Cuba lagi"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"Tutup"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"Fail tidak diketahui"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Tiada aplikasi untuk mengendalikan fail jenis ini. \n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"Tiada fail"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Fail tidak wujud. \n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"Sila tunggu..."</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"Menghidupkan Bluetooth..."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"Fail akan diterima. Semak kemajuan dalam panel Pemberitahuan."</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"Fail tidak boleh diterima."</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"Penerimaan fail daripada \"<xliff:g id="SENDER">%1$s</xliff:g>\" dihentikan"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"Menghantar fail kepada \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\""</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"Menghantar <xliff:g id="NUMBER">%1$s</xliff:g> fail kepada \"<xliff:g id="RECIPIENT">%2$s</xliff:g>\""</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"Penghantaran fail ke \"<xliff:g id="RECIPIENT">%1$s</xliff:g>\" dihentikan"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"Tiada ruang mencukupi pada storan USB untuk menyimpan fail daripada \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"Tiada ruang mencukupi pada kad SD untuk menyimpan fail daripada \"<xliff:g id="SENDER">%1$s</xliff:g>\""</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"Ruang diperlukan: <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"Terlalu banyak permintaan sedang diproses. Cuba sebentar lagi."</string>
+ <string name="status_pending" msgid="2503691772030877944">"Pemindahan fail belum lagi dimulakan."</string>
+ <string name="status_running" msgid="6562808920311008696">"Pemindahan fail sedang berlangsung."</string>
+ <string name="status_success" msgid="239573225847565868">"Pemindahan fail berjaya diselesaikan."</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"Kandungan tidak disokong."</string>
+ <string name="status_forbidden" msgid="613956401054050725">"Pemindahan dilarang oleh peranti sasaran."</string>
+ <string name="status_canceled" msgid="6664490318773098285">"Pemindahan dibatalkan oleh pengguna."</string>
+ <string name="status_file_error" msgid="3671917770630165299">"Isu storan."</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"Tiada storan USB."</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"Tiada kad SD. Masukkan kad SD untuk menyimpan fail yang dipindahkan."</string>
+ <string name="status_connection_error" msgid="947681831523219891">"Sambungan tidak berjaya."</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"Permintaan tidak dapat dikendalikan dengan betul."</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"Ralat tidak diketahui."</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth diterima"</string>
+ <string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Penerimaan selesai."</string>
+ <string name="upload_success" msgid="4014469387779648949">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Penghantaran selesai."</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"Pemindahan masuk"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"Pemindahan keluar"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"Sejarah pemindahan kosong."</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Semua item akan dipadam bersih daripada senarai."</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"Perkongsian Bluetooth: Fail diterima"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Perkongsian Bluetooth: Fail diterima"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> berjaya, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> tidak berjaya."</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Padam bersih senarai"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"Buka"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Padam bersih daripada senarai"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Padam bersih"</string>
+</resources>
diff --git a/res/values-ms-rMY/strings_map.xml b/res/values-ms-rMY/strings_map.xml
new file mode 100644
index 0000000..afc98d7
--- /dev/null
+++ b/res/values-ms-rMY/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Kunci sesi Bluetooth diperlukan"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Berlaku tamat masa semasa menerima sambungan dengan %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Tamat masa berlaku semasa memasukkan kunci sesi dengan %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Permintaan pengesahan Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Kunci Sesi"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit kereta"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nama tidak diketahui"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Nama saya"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ms-rMY/strings_pbap.xml b/res/values-ms-rMY/strings_pbap.xml
new file mode 100644
index 0000000..63f873d
--- /dev/null
+++ b/res/values-ms-rMY/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"Kunci sesi Bluetooth diperlukan"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"Berlaku tamat masa semasa menerima sambungan dengan %1$s"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"Tamat masa berlaku semasa memasukkan kunci sesi dengan %1$s"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Permintaan pengesahan Obex"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"Kunci Sesi"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="defaultname" msgid="4821590500649090078">"Kit kereta"</string>
+ <string name="unknownName" msgid="2841414754740600042">"Nama tidak diketahui"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"Nama saya"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-ms-rMY/test_strings.xml b/res/values-ms-rMY/test_strings.xml
new file mode 100644
index 0000000..ead3bc8
--- /dev/null
+++ b/res/values-ms-rMY/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"Hello World, AktivitiUjian"</string>
+ <string name="app_name" msgid="1203877025577761792">"Perkongsian Bluetooth"</string>
+ <string name="insert_record" msgid="1450997173838378132">"Masukkan rekod"</string>
+ <string name="update_record" msgid="2480425402384910635">"Sahkan rekod"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Rekod Ack"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Padamkan semua rekod"</string>
+ <string name="ok_button" msgid="6519033415223065454">"OK"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Padamkan rekod"</string>
+ <string name="start_server" msgid="9034821924409165795">"Mulakan pelayan TCP"</string>
+ <string name="notify_server" msgid="4369106744022969655">"Beritahu pelayan TCP"</string>
+</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index ff386c0..84c29e9 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Batal"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Hidupkan"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Pemindahan fail"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" mahu menghantar <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) kepada anda. "\n\n" Terima fail?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" mahu menghantar <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) kepada anda. \n\n Terima fail?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Tolak"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Terima"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Tutup"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Fail tidak diketahui"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Tiada aplikasi untuk mengendalikan fail jenis ini. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Tiada aplikasi untuk mengendalikan fail jenis ini. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Tiada fail"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Fail tidak wujud. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Fail tidak wujud. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Sila tunggu..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Menghidupkan Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Fail akan diterima. Semak kemajuan dalam panel Pemberitahuan."</string>
diff --git a/res/values-ms/strings_map.xml b/res/values-ms/strings_map.xml
new file mode 100644
index 0000000..afc98d7
--- /dev/null
+++ b/res/values-ms/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Kunci sesi Bluetooth diperlukan"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Berlaku tamat masa semasa menerima sambungan dengan %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Tamat masa berlaku semasa memasukkan kunci sesi dengan %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Permintaan pengesahan Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Kunci Sesi"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Taipkan kunci sesi untuk %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit kereta"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nama tidak diketahui"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Nama saya"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ce65721..7496fec 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Avbryt"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Slå på"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Filoverføring"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"«<xliff:g id="SENDER">%1$s</xliff:g>» vil sende deg <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Vil du godta filen?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"«<xliff:g id="SENDER">%1$s</xliff:g>» vil sende deg <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Vil du godta filen?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Avslå"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Godta"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Lukk"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Ukjent fil"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Det finnes ingen app på enheten som kan håndtere denne filtypen. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Det finnes ingen app på enheten som kan håndtere denne filtypen. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ingen fil"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen finnes ikke. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen finnes ikke. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Vent litt ..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Aktiverer Bluetooth …"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Filen vil bli mottatt. Du kan se fremdriften i varselpanelet."</string>
diff --git a/res/values-nb/strings_map.xml b/res/values-nb/strings_map.xml
new file mode 100644
index 0000000..5b6cc48
--- /dev/null
+++ b/res/values-nb/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Skriv inn øktsnøkkel for %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-øktsnøkkel kreves"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Det tok for lang tid å godta forbindelsen med «%1$s»"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Det tok for lang tid å legge inn øktsnøkkel med %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Autentiseringsforespørsel fra Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Øktsnøkkel"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Skriv inn øktsnøkkel for %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Bilsett"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Ukjent navn"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Navnet mitt"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ne-rNP/strings_map.xml b/res/values-ne-rNP/strings_map.xml
new file mode 100644
index 0000000..7584c1e
--- /dev/null
+++ b/res/values-ne-rNP/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s का लागि सत्र कुञ्जी टाइप गर्नुहोस्"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"ब्लूटूथ सत्र कुञ्जी आवश्यक"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s सँग जडान स्वीकार गर्न समय सकियो"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s का साथ सत्र कुञ्जी इनपुट गर्ने समय सकियो"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex प्रमाणिकरण अनुरोध"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"सत्र कुञ्जी"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s का लागि सत्र कुञ्जी टाइप गर्नुहोस्"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"अज्ञात नाम"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"मेरो नाम"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"००००००"</string>
+</resources>
diff --git a/res/values-ne/strings_map.xml b/res/values-ne/strings_map.xml
new file mode 100644
index 0000000..7584c1e
--- /dev/null
+++ b/res/values-ne/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s का लागि सत्र कुञ्जी टाइप गर्नुहोस्"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"ब्लूटूथ सत्र कुञ्जी आवश्यक"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s सँग जडान स्वीकार गर्न समय सकियो"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s का साथ सत्र कुञ्जी इनपुट गर्ने समय सकियो"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex प्रमाणिकरण अनुरोध"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"सत्र कुञ्जी"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s का लागि सत्र कुञ्जी टाइप गर्नुहोस्"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"अज्ञात नाम"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"मेरो नाम"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"००००००"</string>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index ea3437d..e786358 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Annuleren"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Inschakelen"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Bestandsoverdracht"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\'<xliff:g id="SENDER">%1$s</xliff:g>\' wil <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) naar u verzenden. "\n\n" Het bestand accepteren?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\'<xliff:g id="SENDER">%1$s</xliff:g>\' wil <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) naar u verzenden. \n\n Het bestand accepteren?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Weigeren"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Accepteren"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Sluiten"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Onbekend bestand"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Er is geen app om dit type bestand af te handelen. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Er is geen app om dit type bestand af te handelen. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Geen bestand"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Het bestand bestaat niet. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Het bestand bestaat niet. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Een ogenblik geduld..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth inschakelen…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Het bestand wordt ontvangen. U kunt de voortgang controleren in het venster \'Meldingen\'."</string>
diff --git a/res/values-nl/strings_map.xml b/res/values-nl/strings_map.xml
new file mode 100644
index 0000000..261bb63
--- /dev/null
+++ b/res/values-nl/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Typ de sessiesleutel voor %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth-sessiesleutel is vereist"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Er is een time-out opgetreden voor het accepteren van de verbinding met %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Er is een time-out opgetreden tijdens het invoeren van de sessiesleutel met %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"OBEX-verificatieverzoek"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sessiesleutel"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Typ de sessiesleutel voor %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Onbekende naam"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mijn naam"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index c60cdc5..72795c5 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Anuluj"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Włącz"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Przesyłanie pliku"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Urządzenie „<xliff:g id="SENDER">%1$s</xliff:g>” chce wysłać do Ciebie plik <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Czy zaakceptować ten plik?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Urządzenie „<xliff:g id="SENDER">%1$s</xliff:g>” chce wysłać do Ciebie plik <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Czy zaakceptować ten plik?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Odrzuć"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Akceptuj"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Zamknij"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Nieznany plik"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Brak aplikacji do obsługi tego typu pliku "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Brak aplikacji do obsługi tego typu pliku \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Brak pliku"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Plik nie istnieje. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Plik nie istnieje. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Czekaj…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Włączanie Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Plik zostanie odebrany. Sprawdzaj postęp na panelu powiadomień."</string>
diff --git a/res/values-pl/strings_map.xml b/res/values-pl/strings_map.xml
new file mode 100644
index 0000000..6de3584
--- /dev/null
+++ b/res/values-pl/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Wpisz klucz sesji dla: %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Wymagany klucz sesji Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Przekroczono limit czasu na akceptację połączenia z: %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Przekroczono limit czasu na wprowadzenie klucza sesji z: %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Żądanie uwierzytelniania Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Klucz sesji"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Wpisz klucz sesji dla: %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Zestaw samochodowy"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nieznana nazwa"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Moja nazwa"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a1593f6..5e59155 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -28,12 +28,12 @@
<string name="airplane_error_title" msgid="2683839635115739939">"Modo de avião"</string>
<string name="airplane_error_msg" msgid="8698965595254137230">"Não pode utilizar o Bluetooth em modo de Avião."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
- <string name="bt_enable_line1" msgid="7203551583048149">"Para utilizar os serviços Bluetooth, tem de activar primeiro o Bluetooth."</string>
- <string name="bt_enable_line2" msgid="4341936569415937994">"Activar o Bluetooth agora?"</string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Para utilizar os serviços Bluetooth, tem de ativar primeiro o Bluetooth."</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"Ativar o Bluetooth agora?"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancelar"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Ativar"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferência do ficheiro"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" quer enviar-lhe <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Aceita o ficheiro?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" quer enviar-lhe <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Aceita o ficheiro?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Recusar"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Aceitar"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Fechar"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Ficheiro desconhecido"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Não existe nenhuma aplicação para executar este tipo de ficheiro. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Não existe nenhuma aplicação para executar este tipo de ficheiro. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nenhum ficheiro"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"O ficheiro não existe. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"O ficheiro não existe. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Aguarde..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"A ligar Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"O ficheiro será recebido. Consulte o progresso no painel Notificações."</string>
diff --git a/res/values-pt-rPT/strings_map.xml b/res/values-pt-rPT/strings_map.xml
new file mode 100644
index 0000000..1e1a071
--- /dev/null
+++ b/res/values-pt-rPT/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Escreva a chave de sessão para %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Necessária chave de sessão Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Foi excedido o tempo para aceitar a ligação a %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Foi excedido o tempo para introduzir a chave de sessão com %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Pedido de autenticação OBEX"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Chave de sessão"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Escreva a chave de sessão para %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit para carro"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nome desconhecido"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"O meu nome"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index aa2ec74..3b72c6c 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -25,15 +25,15 @@
<string name="bt_share_picker_label" msgid="6268100924487046932">"Bluetooth"</string>
<string name="unknown_device" msgid="9221903979877041009">"Dispositivo desconhecido"</string>
<string name="unknownNumber" msgid="4994750948072751566">"Desconhecido"</string>
- <string name="airplane_error_title" msgid="2683839635115739939">"Modo para avião"</string>
- <string name="airplane_error_msg" msgid="8698965595254137230">"Não é possível usar o Bluetooth no modo para avião."</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"Modo avião"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"Não é possível usar o Bluetooth no modo avião."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
<string name="bt_enable_line1" msgid="7203551583048149">"Para usar os serviços de Bluetooth, é necessário ativar o Bluetooth."</string>
<string name="bt_enable_line2" msgid="4341936569415937994">"Ativar Bluetooth agora?"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"Cancelar"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Ativar"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transferência de arquivo"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" deseja enviar para você <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Aceitar o arquivo?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" deseja enviar para você <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Aceitar o arquivo?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Recusar"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Aceitar"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Fechar"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Arquivo desconhecido"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Não há um aplicativo para lidar com este tipo de arquivo. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Não há um aplicativo para lidar com este tipo de arquivo. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Nenhum arquivo"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"O arquivo não existe. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"O arquivo não existe. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Aguarde..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Ativando Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"O arquivo será recebido. Verifique o andamento no painel de Notificações."</string>
diff --git a/res/values-pt/strings_map.xml b/res/values-pt/strings_map.xml
new file mode 100644
index 0000000..d2e66f7
--- /dev/null
+++ b/res/values-pt/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Digite a chave de sessão para %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"É necessário fornecer a chave de sessão Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Tempo limite esgotado para aceitar a conexão com %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Tempo limite esgotado para inserir a chave de sessão com %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Solicitação de autenticação Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Chave de sessão"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Digite a chave de sessão para %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kit para carro"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nome desconhecido"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Meu nome"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 0c849d7..67ea370 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -39,7 +39,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Interrumper"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activar"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transfer da datoteca"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> As tramettess gugent <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Acceptar la datoteca?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> As tramettess gugent <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Acceptar la datoteca?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Refusar"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Acceptar"</string>
<!-- no translation found for incoming_file_confirm_timeout_ok (1414676773249857278) -->
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 99ac76d..713d026 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -33,12 +33,12 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Anulaţi"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Activaţi"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Transfer de fişier"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>” doreşte să vă trimită <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Acceptaţi acest fişier?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>” doreşte să vă trimită <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Acceptaţi acest fişier?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Refuzaţi"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Acceptaţi"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
<string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"A fost atins timpul limită pentru acceptarea unui fişier primit de la „<xliff:g id="SENDER">%1$s</xliff:g>”"</string>
- <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Distribuire prin Bluetooth: se primeşte fişierul"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"Bluetooth: se primeşte fişierul"</string>
<string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Doriţi să primiţi acest fişier?"</string>
<string name="incoming_file_toast_msg" msgid="1733710749992901811">"Un fişier de la alt dispozitiv se află în curs de primire. Confirmaţi dacă doriţi primirea acestuia."</string>
<string name="notification_receiving" msgid="4674648179652543984">"Distribuire prin Bluetooth: se primeşte <xliff:g id="FILE">%1$s</xliff:g>"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Închideţi"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Fişier necunoscut"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Nu există nicio aplicaţie care să gestioneze acest tip de fişier. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Nu există nicio aplicaţie care să gestioneze acest tip de fişier. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Niciun fişier"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Fişierul nu există. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Fişierul nu există. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Aşteptaţi..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Se activează Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Se va primi fişierul. Verificaţi progresul în panoul de notificări."</string>
@@ -108,10 +108,10 @@
<string name="no_transfers" msgid="3482965619151865672">"Istoricul de transferuri este gol."</string>
<string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Toate elementele din listă vor fi eliminate."</string>
<string name="outbound_noti_title" msgid="8051906709452260849">"Distribuire prin Bluetooth: fişiere trimise"</string>
- <string name="inbound_noti_title" msgid="4143352641953027595">"Distribuire prin Bluetooth: fişiere primite"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"Bluetooth: fișiere primite"</string>
<string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> reuşite, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> eşuate."</string>
- <string name="transfer_menu_clear_all" msgid="790017462957873132">"Ştergeţi lista"</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"Ștergeţi lista"</string>
<string name="transfer_menu_open" msgid="3368984869083107200">"Deschideţi"</string>
- <string name="transfer_menu_clear" msgid="5854038118831427492">"Ştergeţi din listă"</string>
- <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Ştergeţi"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"Ștergeţi din listă"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"Ștergeţi"</string>
</resources>
diff --git a/res/values-ro/strings_map.xml b/res/values-ro/strings_map.xml
new file mode 100644
index 0000000..bfed36c
--- /dev/null
+++ b/res/values-ro/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Introduceţi cheia de sesiune pentru %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Cheie de sesiune Bluetooth solicitată"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"A expirat timpul pentru acceptarea conexiunii cu %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"A expirat timpul de introducere a cheii de sesiune cu %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Cerere de autentificare pentru protocolul OBEX"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Cheia sesiunii"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Introduceţi cheia de sesiune pentru %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Set de maşină"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Nume necunoscut"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Numele meu"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-ro/test_strings.xml b/res/values-ro/test_strings.xml
index 1174667..3e10db1 100644
--- a/res/values-ro/test_strings.xml
+++ b/res/values-ro/test_strings.xml
@@ -6,9 +6,9 @@
<string name="insert_record" msgid="1450997173838378132">"Inseraţi o înregistrare"</string>
<string name="update_record" msgid="2480425402384910635">"Confirmaţi înregistrarea"</string>
<string name="ack_record" msgid="6716152390978472184">"Înregistrare Ack"</string>
- <string name="deleteAll_record" msgid="4383349788485210582">"Ştergeţi toate înregistrările"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"Ștergeţi toate înregistrările"</string>
<string name="ok_button" msgid="6519033415223065454">"OK"</string>
- <string name="delete_record" msgid="4645040331967533724">"Ştergeţi înregistrarea"</string>
+ <string name="delete_record" msgid="4645040331967533724">"Ștergeţi înregistrarea"</string>
<string name="start_server" msgid="9034821924409165795">"Porniţi serverul TCP"</string>
<string name="notify_server" msgid="4369106744022969655">"Notificaţi serverul TCP"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index fc66903..4251973 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Отмена"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Включить"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Передача файла"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" отправляет вам файл <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n"Принять файл?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" отправляет вам файл <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\nПринять файл?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Отклонить"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Принять"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ОК"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Закрыть"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"ОК"</string>
<string name="unknown_file" msgid="6092727753965095366">"Неизвестный файл"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Нет приложений для работы с файлами этого типа. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Нет приложений для работы с файлами этого типа. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Нет файла"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не существует. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не существует. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Подождите..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Включение Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Этот файл будет получен. Ход выполнения отображается на панели уведомлений."</string>
diff --git a/res/values-ru/strings_map.xml b/res/values-ru/strings_map.xml
new file mode 100644
index 0000000..f51054b
--- /dev/null
+++ b/res/values-ru/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Введите ключ сеанса для %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Необходим ключ сеанса Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Истекло время ожидания при установке подключения к %1$s."</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Истекло время ожидания ввода ключа сеанса для связи с %1$s."</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Запрос на аутентификацию Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ключ сеанса"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Введите ключ сеанса для %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Автомобильный комплект"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Без названия"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Мое название"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-si-rLK/strings_map.xml b/res/values-si-rLK/strings_map.xml
new file mode 100644
index 0000000..31c2feb
--- /dev/null
+++ b/res/values-si-rLK/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s සඳහා සැසි යතුර ටයිප් කරන්න"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"බ්ලූටූත් සැසි යතුර අවශ්යයි"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s හා සම්බන්ධය පිළිගැනීමට කාල නිමාවක් විය"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s හා සැසි යතුර ආදානය කිරීමට කාල නිමාවක් විය"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex සත්යාපන ඉල්ලීම"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"සැසි යතුර"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s සඳහා සැසි යතුර ටයිප් කරන්න"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"නොදන්නා නමකි"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"මගේ නම"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-si/strings_map.xml b/res/values-si/strings_map.xml
new file mode 100644
index 0000000..31c2feb
--- /dev/null
+++ b/res/values-si/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s සඳහා සැසි යතුර ටයිප් කරන්න"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"බ්ලූටූත් සැසි යතුර අවශ්යයි"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s හා සම්බන්ධය පිළිගැනීමට කාල නිමාවක් විය"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s හා සැසි යතුර ආදානය කිරීමට කාල නිමාවක් විය"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex සත්යාපන ඉල්ලීම"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"සැසි යතුර"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s සඳහා සැසි යතුර ටයිප් කරන්න"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"නොදන්නා නමකි"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"මගේ නම"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index b584699..198bbb7 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Získať prístup k správcovi preberania."</string>
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"Získať prístup k správcovi sťahovania."</string>
<string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"Umožňuje aplikácii pristupovať k Správcovi BluetoothShare a použiť ho na prenos súborov."</string>
<string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"Prístup povoleného zariadenia Bluetooth."</string>
<string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"Umožňuje aplikácii dočasne povoliť zariadenie Bluetooth, čím sa povolí zariadeniu odosielať súbory do tohto zariadenia bez potvrdenia používateľa."</string>
@@ -28,12 +28,12 @@
<string name="airplane_error_title" msgid="2683839635115739939">"Režim V lietadle"</string>
<string name="airplane_error_msg" msgid="8698965595254137230">"Technológiu Bluetooth nemôžete používať v režime V lietadle."</string>
<string name="bt_enable_title" msgid="8657832550503456572"></string>
- <string name="bt_enable_line1" msgid="7203551583048149">"Komu používať služby Bluetooth, musíte najskôr rozhranie Bluetooth zapnúť."</string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"Ak chcete používať služby Bluetooth, musíte najskôr rozhranie Bluetooth zapnúť."</string>
<string name="bt_enable_line2" msgid="4341936569415937994">"Zapnúť Bluetooth?"</string>
<string name="bt_enable_cancel" msgid="1988832367505151727">"Zrušiť"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Zapnúť"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Prenos súborov"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Používateľ <xliff:g id="SENDER">%1$s</xliff:g> sa vám pokúša odoslať súbor <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Chcete súbor prijať?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Používateľ <xliff:g id="SENDER">%1$s</xliff:g> sa vám pokúša odoslať súbor <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Chcete súbor prijať?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Odmietnuť"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Prijať"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Zavrieť"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Neznámy súbor"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Na spracovanie tohto typu súboru nemáte žiadnu aplikáciu. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Na spracovanie tohto typu súboru nemáte žiadnu aplikáciu. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Žiadny súbor"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Súbor neexistuje. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Súbor neexistuje. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Čakajte..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Prebieha zapínanie rozhrania Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Prebehne prijatie súboru. Priebeh môžete sledovať na paneli Oznámenie."</string>
diff --git a/res/values-sk/strings_map.xml b/res/values-sk/strings_map.xml
new file mode 100644
index 0000000..0b4d771
--- /dev/null
+++ b/res/values-sk/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Zadajte kľúč relácie pre zariadenie %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Požaduje sa kľúč relácie Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Časový limit na pripojenie k zariadeniu „%1$s“ vypršal"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Časový limit na zadanie kľúča relácie pre %1$s vypršal"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Žiadosť overenia Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Kľúč relácie"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Zadajte kľúč relácie pre zariadenie %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Súprava handsfree do auta"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Neznámy názov"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Moje meno"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 45760ba..31c6f36 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Prekliči"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Vklopi"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Prenos datoteke"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"»<xliff:g id="SENDER">%1$s</xliff:g>« vam želi poslati <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Želite sprejeti datoteko?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"»<xliff:g id="SENDER">%1$s</xliff:g>« vam želi poslati <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Želite sprejeti datoteko?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Zavrni"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Sprejmi"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"V redu"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Zapri"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"V redu"</string>
<string name="unknown_file" msgid="6092727753965095366">"Neznana datoteka"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Ni programa, s katerim bi bilo mogoče odpreti to vrsto datoteke. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Ni programa, s katerim bi bilo mogoče odpreti to vrsto datoteke. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ni datoteke"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Datoteka ne obstaja. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Datoteka ne obstaja. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Počakajte ..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Vklop Bluetootha …"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Datoteka bo prejeta. Potek preverite na plošči »Obvestila«."</string>
diff --git a/res/values-sl/strings_map.xml b/res/values-sl/strings_map.xml
new file mode 100644
index 0000000..1badf05
--- /dev/null
+++ b/res/values-sl/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Vnesite ključ seje za %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Zahtevan je ključ seje Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Iztekla se je časovna omejitev za sprejem povezave z »%1$s«"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Iztekla se je časovna omejitev za vnos ključa seje v %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Zahteva za preverjanje pristnosti Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ključ seje"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Vnesite ključ seje za %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Avtokomplet"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Neznano ime"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Moje ime"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index dcf66c4..cf770fd 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Откажи"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Укључи"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Пренос датотеке"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>“ жели да вам пошаље <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Желите ли да прихватите датотеку?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"„<xliff:g id="SENDER">%1$s</xliff:g>“ жели да вам пошаље <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Желите ли да прихватите датотеку?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Одбиј"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Прихвати"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Потврди"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Затвори"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Потврди"</string>
<string name="unknown_file" msgid="6092727753965095366">"Непозната датотека"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Нема апликација за обраду овог типа датотеке. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Нема апликација за обраду овог типа датотеке. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Нема датотеке"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Датотека не постоји. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Датотека не постоји. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Сачекајте…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Укључивање Bluetooth-а…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Датотека ће бити примљена. Проверавајте ток на табли са обавештењима."</string>
diff --git a/res/values-sr/strings_map.xml b/res/values-sr/strings_map.xml
new file mode 100644
index 0000000..82c7982
--- /dev/null
+++ b/res/values-sr/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Унесите кључ сесије за %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Потребан је кључ сесије за Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Истекло је време за прихватање везе са уређајем %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Истекло је време за унос кључа сесије помоћу %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Захтев за потврду аутентичности преко Obex протокола"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Кључ сесије"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Унесите кључ сесије за %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Опрема за аутомобил"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Непознат назив"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Моје име"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 197621a..54e7b3e 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Avbryt"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Aktivera"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Filöverföring"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> vill skicka <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) till dig. "\n\n" Vill du ta emot filen?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"<xliff:g id="SENDER">%1$s</xliff:g> vill skicka <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) till dig. \n\n Vill du ta emot filen?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Avvisa"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Godkänn"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Stäng"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Okänd fil"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Det finns ingen app för att hantera denna typ av fil. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Det finns ingen app för att hantera denna typ av fil. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ingen fil"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen finns inte. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Filen finns inte. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Vänta …"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth aktiveras …"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Filen tas emot. Du kan se förloppet på aviseringspanelen."</string>
diff --git a/res/values-sv/strings_map.xml b/res/values-sv/strings_map.xml
new file mode 100644
index 0000000..059b3ef
--- /dev/null
+++ b/res/values-sv/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Ange sessionsnyckeln för %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"En Bluetooth-sessionsnyckel krävs"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Tidsgränsen för godkännande av anslutning till %1$s har överskridits"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Tiden för inmatning av sessionsnyckel med %1$s har gått ut"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex-autentiseringsbegäran"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Sessionsnyckel"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Ange sessionsnyckeln för %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Bilsats"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Okänt namn"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Mitt namn"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 384dcd9..d97cb52 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Ghairi"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Washa"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Uhamishaji faili"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" anataka kukutumia <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Ikubali faili?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" anataka kukutumia <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Ikubali faili?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Kataa"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Kubali"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Sawa"</string>
@@ -42,10 +42,10 @@
<string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"Je, unataka kupokea faili hii?"</string>
<string name="incoming_file_toast_msg" msgid="1733710749992901811">"Faili zinazoingia kutoka kwa kifaa kingine. Thibitisha kuwa unataka kupokea faili hii."</string>
<string name="notification_receiving" msgid="4674648179652543984">"Kushiriki kwa bluetooth: Inapokea <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_received" msgid="3324588019186687985">"Kushiriki kwa bluetooth: Ilipokea<xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"Kushiriki kwa bluetooth: Imepokea <xliff:g id="FILE">%1$s</xliff:g>"</string>
<string name="notification_received_fail" msgid="3619350997285714746">"Kushiriki kwa Bluetooth: Faili <xliff:g id="FILE">%1$s</xliff:g> haijapokewa"</string>
<string name="notification_sending" msgid="3035748958534983833">"Kushiriki kwa bluetooth: Inatuma <xliff:g id="FILE">%1$s</xliff:g>"</string>
- <string name="notification_sent" msgid="9218710861333027778">"Kushiriki kwa bluetooth: <xliff:g id="FILE">%1$s</xliff:g> Iliyotumwa"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"Kushiriki kwa bluetooth: Imetuma <xliff:g id="FILE">%1$s</xliff:g>"</string>
<string name="notification_sent_complete" msgid="302943281067557969">"Imekamilika 100%"</string>
<string name="notification_sent_fail" msgid="6696082233774569445">"Kushiriki kwa bluetooth: Faili <xliff:g id="FILE">%1$s</xliff:g> haijatumwa"</string>
<string name="download_title" msgid="3353228219772092586">"Uhamishaji faili"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Funga"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Sawa"</string>
<string name="unknown_file" msgid="6092727753965095366">"Faili isiyojulikana"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Hakuna programu ya kushughulikia aina hii ya faili. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Hakuna programu ya kushughulikia aina hii ya faili. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Hakuna faili."</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Faili haipo. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Faili haipo. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Tafadhali subiri…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Inawasha Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Faili itapokelewa. Kagua maendeleo katika paneli ya Arifa."</string>
@@ -100,7 +100,7 @@
<string name="status_connection_error" msgid="947681831523219891">"Muunganisho haujafanikiwa."</string>
<string name="status_protocol_error" msgid="3245444473429269539">"Ombi haliwezi kushughulikiwa kwa usahihi."</string>
<string name="status_unknown_error" msgid="8156660554237824912">"Hitilafu isiyojulikana."</string>
- <string name="btopp_live_folder" msgid="7967791481444474554">"Bluetooth imepokelewa"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"Zilizopokewa kupitia Bluetooth"</string>
<string name="download_success" msgid="7036160438766730871">"<xliff:g id="FILE_SIZE">%1$s</xliff:g> Imepokelewa kikamilifu"</string>
<string name="upload_success" msgid="4014469387779648949">"Kutuma kwa <xliff:g id="FILE_SIZE">%1$s</xliff:g> kumekamilika."</string>
<string name="inbound_history_title" msgid="6940914942271327563">"Mahamisho yanayoingia"</string>
@@ -109,7 +109,7 @@
<string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"Vipengee vyote vitafutwa kutoka kwenye orodha."</string>
<string name="outbound_noti_title" msgid="8051906709452260849">"Kushiriki kwa bluetooth: Faili zilizotumwa"</string>
<string name="inbound_noti_title" msgid="4143352641953027595">"Kushiriki kwa bluetooth: Faili zilizopokelewa"</string>
- <string name="noti_caption" msgid="7508708288885707365">"zimefanikiwa <xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g>, hazikufanikiwa <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g>"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> zimefanikiwa, <xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> hazikufanikiwa"</string>
<string name="transfer_menu_clear_all" msgid="790017462957873132">"Futa orodha"</string>
<string name="transfer_menu_open" msgid="3368984869083107200">"Fungua"</string>
<string name="transfer_menu_clear" msgid="5854038118831427492">"Futa kutoka orodha"</string>
diff --git a/res/values-sw/strings_map.xml b/res/values-sw/strings_map.xml
new file mode 100644
index 0000000..1ac86e7
--- /dev/null
+++ b/res/values-sw/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Chapa nenosiri la kipindi cha %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Nenosiri la kipindi cha Bluetooth linahitajika"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Muda wa kukubali muunganisho na %1$s umepita"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Muda wa kuweka nenosiri kwa kipindi na %1$s umepita"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Ombi la uthibitishaji kutoka Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ufunguo wa Kipindi"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Chapa nenosiri la kipindi cha %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Kifaa cha gari"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Jina lisilojulikana"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Jina langu"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 9ff1952..617aae5 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"ยกเลิก"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"เปิด"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"การถ่ายโอนไฟล์"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ต้องการส่ง <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) ถึงคุณ "\n\n" ยอมรับไฟล์หรือไม่"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ต้องการส่ง <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) ถึงคุณ \n\n ยอมรับไฟล์หรือไม่"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"ปฏิเสธ"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"ยอมรับ"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"ตกลง"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"ปิด"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"ตกลง"</string>
<string name="unknown_file" msgid="6092727753965095366">"ไฟล์ที่ไม่รู้จัก"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"ไม่มีแอปพลิเคชันในการจัดการกับไฟล์ประเภทนี้"\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"ไม่มีแอปพลิเคชันในการจัดการกับไฟล์ประเภทนี้\n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"ไม่มีไฟล์"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"ไม่มีไฟล์นี้"\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"ไม่มีไฟล์นี้\n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"โปรดรอสักครู่..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"กำลังเปิดบลูทูธ…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"ไฟล์จะถูกรับ ดูความคืบหน้าในแผงการแจ้งเตือน"</string>
diff --git a/res/values-th/strings_map.xml b/res/values-th/strings_map.xml
new file mode 100644
index 0000000..b9008ee
--- /dev/null
+++ b/res/values-th/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"พิมพ์เซสชันคีย์ของ %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"ต้องใช้เซสชันคีย์ของบลูทูธ"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"หมดเวลายอมรับการเชื่อมต่อกับ %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"หมดเวลาป้อนเซสชันคีย์ด้วย %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"คำขอการตรวจสอบสิทธิ์ Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"เซสชันคีย์"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"พิมพ์เซสชันคีย์ของ %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"อุปกรณ์ในรถยนต์"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"ชื่อที่ไม่รู้จัก"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"ชื่อของฉัน"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 60137cd..a9923aa 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Kanselahin"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"I-on"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Paglilipat ng file"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Gusto kang padalhan ni \"<xliff:g id="SENDER">%1$s</xliff:g>\" ng <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Tanggapin ang file?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"Gusto kang padalhan ni \"<xliff:g id="SENDER">%1$s</xliff:g>\" ng <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Tanggapin ang file?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Tanggihan"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Tanggapin"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Isara"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Hindi kilalang file"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Walang app na mangangasiwa sa ganitong uri ng file. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Walang app na mangangasiwa sa ganitong uri ng file. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Walang file"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Hindi umiiral ang file. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Hindi umiiral ang file. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Pakihintay…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Ino-on ang Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Matatanggap ang file. Suriin ang pagsulong sa panel na Mga Notification."</string>
diff --git a/res/values-tl/strings_map.xml b/res/values-tl/strings_map.xml
new file mode 100644
index 0000000..e7dd123
--- /dev/null
+++ b/res/values-tl/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"I-type ang key ng session para kay %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Kinakailangan ang key ng session sa bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Nagkaroon ng time out upang tanggapin ang koneksyon sa %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Nagkaroon ng time out sa pag-input ng key ng session sa %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Kahilingan sa Obex na pagpapatunay"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Key ng Session"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"I-type ang key ng session para kay %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Carkit"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Hindi kilalang pangalan"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Pangalan ko"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 0b14c08..49083b3 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"İptal"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Aç"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Dosya aktarımı"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" size <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) dosyasını göndermek istiyor. "\n\n" Dosyayı kabul ediyor musunuz?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" size <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) dosyasını göndermek istiyor. \n\n Dosyayı kabul ediyor musunuz?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Reddet"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Kabul Et"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Tamam"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Kapat"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"Tamam"</string>
<string name="unknown_file" msgid="6092727753965095366">"Bilinmeyen dosya"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Bu dosya türünü işleyecek hiçbir uygulama yok. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Bu dosya türünü işleyecek hiçbir uygulama yok. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Dosya yok"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Dosya mevcut değil. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Dosya mevcut değil. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Lütfen bekleyin..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Bluetooth açılıyor..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Dosya alınacak. İlerlemeyi Bildirimler panelinden izleyebilirsiniz."</string>
diff --git a/res/values-tr/strings_map.xml b/res/values-tr/strings_map.xml
new file mode 100644
index 0000000..7730ac7
--- /dev/null
+++ b/res/values-tr/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"%1$s için oturum anahtarını yazın"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Bluetooth oturum anahtarı gerekiyor"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"%1$s ile bağlantı yapılmasını kabul etme süresi doldu"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s ile oturum anahtarını girme süresi doldu"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex kimlik doğrulama isteği"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Oturum Anahtarı"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"%1$s için oturum anahtarını yazın"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Araç Kiti"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Bilinmeyen ad"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Adım"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 2497971..fdc66c1 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Скасувати"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Увімкнути"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Пересилка файлу"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" хоче надіслати вам <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Прийняти файл?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" хоче надіслати вам <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Прийняти файл?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Відхилити"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Прийняти"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Закрити"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Невідомий файл"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Немає програми для обробки цього типу файлу. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Немає програми для обробки цього типу файлу. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Немає файлу"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не існує. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Файл не існує. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Зачекайте…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Увімкнення Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Файл буде отримано. Перевіряйте прогрес на панелі сповіщень."</string>
diff --git a/res/values-uk/strings_map.xml b/res/values-uk/strings_map.xml
new file mode 100644
index 0000000..e4462b8
--- /dev/null
+++ b/res/values-uk/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Введіть ключ сеансу для %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Потрібен ключ сеансу Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Виникла затримка прийому з’єднання з %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Виникла затримка введення ключа сесії з %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Запит автентифікації Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ключ сеансу"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Введіть ключ сеансу для %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Комплект для автомобіля"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Немає імені"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Моє ім’я"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index fb9a2ad..fb2cde9 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Hủy"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Bật"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Chuyển tệp"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" muốn gửi cho bạn <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Chấp nhận tệp?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" muốn gửi cho bạn <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Chấp nhận tệp?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Từ chối"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Chấp nhận"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"OK"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Đóng"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"OK"</string>
<string name="unknown_file" msgid="6092727753965095366">"Tệp không xác định"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Không có ứng dụng nào để xử lý loại tệp này. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Không có ứng dụng nào để xử lý loại tệp này. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Không có tệp"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Tệp không tồn tại! "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Tệp không tồn tại! \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Vui lòng đợi..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Đang bật Bluetooth…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"Tệp sẽ được nhận. Hãy kiểm tra tiến trình trong bảng điều khiển Thông báo."</string>
diff --git a/res/values-vi/strings_map.xml b/res/values-vi/strings_map.xml
new file mode 100644
index 0000000..0f57ca3
--- /dev/null
+++ b/res/values-vi/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Nhập khóa phiên cho %1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Yêu cầu khóa phiên Bluetooth"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Đã hết thời gian chờ chấp nhập kết nối với %1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Đã hết thời gian chờ nhập khóa phiên với %1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Yêu cầu xác thực Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Khóa phiên"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Nhập khóa phiên cho %1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Bộ rảnh tay trên ô tô"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Tên không xác định"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Tên của tôi"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index b642fc3..5425f5c 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"取消"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"打开"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"文件传输"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"“<xliff:g id="SENDER">%1$s</xliff:g>”想给您发送 <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>)。"\n\n"是否接受该文件?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"“<xliff:g id="SENDER">%1$s</xliff:g>”想给您发送 <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>)。\n\n是否接受该文件?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"拒绝"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"接受"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"确定"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"关闭"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"确定"</string>
<string name="unknown_file" msgid="6092727753965095366">"未知文件"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"没有可处理此类文件的应用。"\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"没有可处理此类文件的应用。\n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"没有文件"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"该文件不存在。"\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"该文件不存在。\n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"请稍候..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"正在打开蓝牙..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"系统将要接收该文件。请在“通知”面板中检查进度。"</string>
diff --git a/res/values-zh-rCN/strings_map.xml b/res/values-zh-rCN/strings_map.xml
new file mode 100644
index 0000000..72ab0d0
--- /dev/null
+++ b/res/values-zh-rCN/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"输入“%1$s”的会话密钥"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"需要提供蓝牙会话密钥"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"接受与“%1$s”的连接时超时"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"输入“%1$s”的会话密钥时超时"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"OBEX 身份验证请求"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"会话密钥"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"输入“%1$s”的会话密钥"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"车用套件"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"未知名称"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"我的名字"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..46cff21
--- /dev/null
+++ b/res/values-zh-rHK/strings.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="permlab_bluetoothShareManager" msgid="311492132450338925">"存取下載管理員。"</string>
+ <string name="permdesc_bluetoothShareManager" msgid="8930572979123190223">"允許應用程式存取 BluetoothShare 管理員並使用 BluetoothShare 管理員傳輸檔案。"</string>
+ <string name="permlab_bluetoothWhitelist" msgid="7091552898592306386">"將藍牙裝置列入許可名單。"</string>
+ <string name="permdesc_bluetoothWhitelist" msgid="5494513855192170109">"允許應用程式暫時將藍牙裝置加入許可名單,使其不需經用戶確認便可把檔案傳送到裝置上。"</string>
+ <string name="permlab_handoverStatus" msgid="7316032998801933554">"接收藍牙交遞傳輸廣播。"</string>
+ <string name="permdesc_handoverStatus" msgid="4752738070064786310">"允許接收來自藍牙的交遞傳輸狀態資訊。"</string>
+ <string name="bt_share_picker_label" msgid="6268100924487046932">"藍牙"</string>
+ <string name="unknown_device" msgid="9221903979877041009">"不明裝置"</string>
+ <string name="unknownNumber" msgid="4994750948072751566">"未知"</string>
+ <string name="airplane_error_title" msgid="2683839635115739939">"飛行模式"</string>
+ <string name="airplane_error_msg" msgid="8698965595254137230">"裝置處於飛行模式時,無法使用藍牙功能。"</string>
+ <string name="bt_enable_title" msgid="8657832550503456572"></string>
+ <string name="bt_enable_line1" msgid="7203551583048149">"如要使用藍牙服務,請先開啟藍牙功能。"</string>
+ <string name="bt_enable_line2" msgid="4341936569415937994">"立即開啟藍牙功能?"</string>
+ <string name="bt_enable_cancel" msgid="1988832367505151727">"取消"</string>
+ <string name="bt_enable_ok" msgid="3432462749994538265">"開啟"</string>
+ <string name="incoming_file_confirm_title" msgid="8139874248612182627">"檔案傳輸"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"「<xliff:g id="SENDER">%1$s</xliff:g>」想將 <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) 傳送給您。\n\n您要接收檔案嗎?"</string>
+ <string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"拒絕"</string>
+ <string name="incoming_file_confirm_ok" msgid="281462442932231475">"接受"</string>
+ <string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"確定"</string>
+ <string name="incoming_file_confirm_timeout_content" msgid="172779756093975981">"接收來自「<xliff:g id="SENDER">%1$s</xliff:g>」的檔案時發生作業逾時"</string>
+ <string name="incoming_file_confirm_Notification_title" msgid="2958227698135117210">"藍牙分享:外來檔案"</string>
+ <string name="incoming_file_confirm_Notification_caption" msgid="6671081128475981157">"您要接收這個檔案嗎?"</string>
+ <string name="incoming_file_toast_msg" msgid="1733710749992901811">"來自另一部裝置的檔案,請確認您要接收這個外來檔案。"</string>
+ <string name="notification_receiving" msgid="4674648179652543984">"藍牙分享:正在接收 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received" msgid="3324588019186687985">"藍牙分享:已接收 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_received_fail" msgid="3619350997285714746">"藍牙分享:未收到檔案 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sending" msgid="3035748958534983833">"藍牙分享:正在傳送 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent" msgid="9218710861333027778">"藍牙分享:已傳送 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="notification_sent_complete" msgid="302943281067557969">"傳送完成"</string>
+ <string name="notification_sent_fail" msgid="6696082233774569445">"藍牙分享:未傳送檔案 <xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_title" msgid="3353228219772092586">"檔案傳輸"</string>
+ <string name="download_line1" msgid="4926604799202134144">"寄件者:「<xliff:g id="SENDER">%1$s</xliff:g>」"</string>
+ <string name="download_line2" msgid="5876973543019417712">"檔案:<xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_line3" msgid="4384821622908676061">"檔案大小:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="download_line4" msgid="8535996869722666525"></string>
+ <string name="download_line5" msgid="3069560415845295386">"正在接收檔案…"</string>
+ <string name="download_cancel" msgid="9177305996747500768">"停止"</string>
+ <string name="download_ok" msgid="5000360731674466039">"隱藏"</string>
+ <string name="download_fail_line1" msgid="3846450148862894552">"未接收檔案"</string>
+ <string name="download_fail_line2" msgid="8950394574689971071">"檔案:<xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="download_fail_line3" msgid="3451040656154861722">"原因: <xliff:g id="REASON">%1$s</xliff:g>"</string>
+ <string name="download_fail_ok" msgid="1521733664438320300">"確定"</string>
+ <string name="download_succ_line5" msgid="4509944688281573595">"已接收檔案"</string>
+ <string name="download_succ_ok" msgid="7053688246357050216">"開啟"</string>
+ <string name="upload_line1" msgid="2055952074059709052">"傳送給:「<xliff:g id="RECIPIENT">%1$s</xliff:g>」"</string>
+ <string name="upload_line3" msgid="4920689672457037437">"檔案類型:<xliff:g id="TYPE">%1$s</xliff:g> (<xliff:g id="SIZE">%2$s</xliff:g>)"</string>
+ <string name="upload_line5" msgid="7759322537674229752">"正在傳送檔案…"</string>
+ <string name="upload_succ_line5" msgid="5687317197463383601">"檔案已傳送"</string>
+ <string name="upload_succ_ok" msgid="7705428476405478828">"確定"</string>
+ <string name="upload_fail_line1" msgid="7899394672421491701">"未將檔案傳送給「<xliff:g id="RECIPIENT">%1$s</xliff:g>」。"</string>
+ <string name="upload_fail_line1_2" msgid="2108129204050841798">"檔案:<xliff:g id="FILE">%1$s</xliff:g>"</string>
+ <string name="upload_fail_ok" msgid="5807702461606714296">"重試"</string>
+ <string name="upload_fail_cancel" msgid="9118496285835687125">"關閉"</string>
+ <string name="bt_error_btn_ok" msgid="5965151173011534240">"確定"</string>
+ <string name="unknown_file" msgid="6092727753965095366">"未知的檔案"</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"沒有應用程式可處理這種檔案類型。\n"</string>
+ <string name="not_exist_file" msgid="3489434189599716133">"沒有檔案"</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"檔案不存在。\n"</string>
+ <string name="enabling_progress_title" msgid="436157952334723406">"請稍候…"</string>
+ <string name="enabling_progress_content" msgid="4601542238119927904">"正在開啟藍牙..."</string>
+ <string name="bt_toast_1" msgid="972182708034353383">"即將接收檔案,請在通知面板中查看進度。"</string>
+ <string name="bt_toast_2" msgid="8602553334099066582">"無法接收檔案。"</string>
+ <string name="bt_toast_3" msgid="6707884165086862518">"已停止接收來自「<xliff:g id="SENDER">%1$s</xliff:g>」的檔案"</string>
+ <string name="bt_toast_4" msgid="4678812947604395649">"正在將檔案傳送給「<xliff:g id="RECIPIENT">%1$s</xliff:g>」"</string>
+ <string name="bt_toast_5" msgid="2846870992823019494">"正在將 <xliff:g id="NUMBER">%1$s</xliff:g> 個檔案傳送給「<xliff:g id="RECIPIENT">%2$s</xliff:g>」"</string>
+ <string name="bt_toast_6" msgid="1855266596936622458">"已停止將檔案傳送給「<xliff:g id="RECIPIENT">%1$s</xliff:g>」"</string>
+ <string name="bt_sm_2_1" product="nosdcard" msgid="352165168004521000">"USB 儲存裝置上空間不足,無法儲存「<xliff:g id="SENDER">%1$s</xliff:g>」傳來的檔案"</string>
+ <string name="bt_sm_2_1" product="default" msgid="1989018443456803630">"SD 記憶卡上空間不足,無法儲存「<xliff:g id="SENDER">%1$s</xliff:g>」傳來的檔案"</string>
+ <string name="bt_sm_2_2" msgid="2965243265852680543">"所需儲存空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="ErrorTooManyRequests" msgid="8578277541472944529">"同時處理過多要求,請稍後再試。"</string>
+ <string name="status_pending" msgid="2503691772030877944">"尚未開始傳輸檔案。"</string>
+ <string name="status_running" msgid="6562808920311008696">"正在進行檔案傳輸。"</string>
+ <string name="status_success" msgid="239573225847565868">"已完成檔案傳輸。"</string>
+ <string name="status_not_accept" msgid="1695082417193780738">"內容不受支援。"</string>
+ <string name="status_forbidden" msgid="613956401054050725">"目標裝置禁止傳輸。"</string>
+ <string name="status_canceled" msgid="6664490318773098285">"用戶已取消傳輸。"</string>
+ <string name="status_file_error" msgid="3671917770630165299">"儲存空間問題。"</string>
+ <string name="status_no_sd_card" product="nosdcard" msgid="1112125377088421469">"沒有 USB 儲存裝置。"</string>
+ <string name="status_no_sd_card" product="default" msgid="5760944071743325592">"沒有 SD 卡,請插入 SD 卡來儲存傳輸的檔案。"</string>
+ <string name="status_connection_error" msgid="947681831523219891">"連線失敗。"</string>
+ <string name="status_protocol_error" msgid="3245444473429269539">"無法正確處理要求。"</string>
+ <string name="status_unknown_error" msgid="8156660554237824912">"未知錯誤。"</string>
+ <string name="btopp_live_folder" msgid="7967791481444474554">"已透過藍牙接收"</string>
+ <string name="download_success" msgid="7036160438766730871">"已完成 <xliff:g id="FILE_SIZE">%1$s</xliff:g> 的接收作業。"</string>
+ <string name="upload_success" msgid="4014469387779648949">"已完成 <xliff:g id="FILE_SIZE">%1$s</xliff:g> 的傳送作業。"</string>
+ <string name="inbound_history_title" msgid="6940914942271327563">"外來傳輸"</string>
+ <string name="outbound_history_title" msgid="4279418703178140526">"向外傳輸"</string>
+ <string name="no_transfers" msgid="3482965619151865672">"傳輸記錄是空的。"</string>
+ <string name="transfer_clear_dlg_msg" msgid="1712376797268438075">"將會從清單清除所有項目。"</string>
+ <string name="outbound_noti_title" msgid="8051906709452260849">"藍牙分享:傳送的檔案"</string>
+ <string name="inbound_noti_title" msgid="4143352641953027595">"藍牙分享:接收的檔案"</string>
+ <string name="noti_caption" msgid="7508708288885707365">"<xliff:g id="SUCCESSFUL_NUMBER_0">%1$s</xliff:g> 個成功,<xliff:g id="UNSUCCESSFUL_NUMBER">%2$s</xliff:g> 個失敗。"</string>
+ <string name="transfer_menu_clear_all" msgid="790017462957873132">"清除清單"</string>
+ <string name="transfer_menu_open" msgid="3368984869083107200">"開啟"</string>
+ <string name="transfer_menu_clear" msgid="5854038118831427492">"從清單清除"</string>
+ <string name="transfer_clear_dlg_title" msgid="2953444575556460386">"清除"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings_map.xml b/res/values-zh-rHK/strings_map.xml
new file mode 100644
index 0000000..cfbe3f1
--- /dev/null
+++ b/res/values-zh-rHK/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"輸入 %1$s 的工作階段金鑰"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"必須有藍牙工作階段金鑰"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"接受與 %1$s 的連線時逾時"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"輸入與 %1$s 連線的工作階段金鑰時逾時"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex 認證要求"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"工作階段金鑰"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"輸入 %1$s 的工作階段金鑰"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"車用套件"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"未知的名稱"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"我的名稱"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-zh-rHK/strings_pbap.xml b/res/values-zh-rHK/strings_pbap.xml
new file mode 100644
index 0000000..d29dd85
--- /dev/null
+++ b/res/values-zh-rHK/strings_pbap.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pbap_session_key_dialog_title" msgid="3580996574333882561">"輸入 %1$s 的對稱金鑰"</string>
+ <string name="pbap_session_key_dialog_header" msgid="2772472422782758981">"必須有藍牙工作階段金鑰"</string>
+ <string name="pbap_acceptance_timeout_message" msgid="1107401415099814293">"接受與 %1$s 的連線時發生作業逾時"</string>
+ <string name="pbap_authentication_timeout_message" msgid="4166979525521902687">"%1$s 輸入對稱金鑰時發生逾時"</string>
+ <string name="auth_notif_ticker" msgid="1575825798053163744">"Obex 驗證要求"</string>
+ <string name="auth_notif_title" msgid="7599854855681573258">"對稱金鑰"</string>
+ <string name="auth_notif_message" msgid="6667218116427605038">"輸入 %1$s 的對稱金鑰"</string>
+ <string name="defaultname" msgid="4821590500649090078">"車用套件"</string>
+ <string name="unknownName" msgid="2841414754740600042">"未知的名稱"</string>
+ <string name="localPhoneName" msgid="2349001318925409159">"我的姓名"</string>
+ <string name="defaultnumber" msgid="8520116145890867338">"000000"</string>
+</resources>
diff --git a/res/values-zh-rHK/test_strings.xml b/res/values-zh-rHK/test_strings.xml
new file mode 100644
index 0000000..a76b249
--- /dev/null
+++ b/res/values-zh-rHK/test_strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="hello" msgid="1740533743008967039">"TestActivity,向全世界問好!"</string>
+ <string name="app_name" msgid="1203877025577761792">"藍牙分享"</string>
+ <string name="insert_record" msgid="1450997173838378132">"插入記錄"</string>
+ <string name="update_record" msgid="2480425402384910635">"確認記錄"</string>
+ <string name="ack_record" msgid="6716152390978472184">"Ack 記錄"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"刪除所有記錄"</string>
+ <string name="ok_button" msgid="6519033415223065454">"確定"</string>
+ <string name="delete_record" msgid="4645040331967533724">"刪除記錄"</string>
+ <string name="start_server" msgid="9034821924409165795">"啟動 TCP 伺服器"</string>
+ <string name="notify_server" msgid="4369106744022969655">"通知 TCP 伺服器"</string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 400d5a5..4e39aad 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"取消"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"開啟"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"檔案傳輸"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"「<xliff:g id="SENDER">%1$s</xliff:g>」想將 <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) 傳送給您。"\n\n"您要接收檔案嗎?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"「<xliff:g id="SENDER">%1$s</xliff:g>」想將 <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>) 傳送給您。\n\n您要接收檔案嗎?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"拒絕"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"接受"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"確定"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"關閉"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"確定"</string>
<string name="unknown_file" msgid="6092727753965095366">"未知的檔案"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"沒有可處理這種檔案類型的應用程式。"\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"沒有可處理這種檔案類型的應用程式。\n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"沒有檔案"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"檔案不存在。"\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"檔案不存在。\n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"請稍候…"</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"正在開啟藍牙…"</string>
<string name="bt_toast_1" msgid="972182708034353383">"即將接收檔案,請在通知面板中查看進度。"</string>
diff --git a/res/values-zh-rTW/strings_map.xml b/res/values-zh-rTW/strings_map.xml
new file mode 100644
index 0000000..96c2256
--- /dev/null
+++ b/res/values-zh-rTW/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"輸入 %1$s 的對稱金鑰"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"必須有藍牙對稱金鑰"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"接受與 %1$s 的連線時發生作業逾時"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"%1$s 輸入對稱金鑰時發生逾時"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Obex 驗證要求"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"對稱金鑰"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"輸入 %1$s 的對稱金鑰"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"車用套件"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"未知的名稱"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"我的名稱"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values-zh-rTW/test_strings.xml b/res/values-zh-rTW/test_strings.xml
index ecfdd4d..4b24156 100644
--- a/res/values-zh-rTW/test_strings.xml
+++ b/res/values-zh-rTW/test_strings.xml
@@ -6,7 +6,7 @@
<string name="insert_record" msgid="1450997173838378132">"插入記錄"</string>
<string name="update_record" msgid="2480425402384910635">"確認記錄"</string>
<string name="ack_record" msgid="6716152390978472184">"Ack 記錄"</string>
- <string name="deleteAll_record" msgid="4383349788485210582">"刪除所有記錄"</string>
+ <string name="deleteAll_record" msgid="4383349788485210582">"刪除所有紀錄"</string>
<string name="ok_button" msgid="6519033415223065454">"確定"</string>
<string name="delete_record" msgid="4645040331967533724">"刪除記錄"</string>
<string name="start_server" msgid="9034821924409165795">"啟動 TCP 伺服器"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 8e1e6ae..1435041 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -33,7 +33,7 @@
<string name="bt_enable_cancel" msgid="1988832367505151727">"Khansela"</string>
<string name="bt_enable_ok" msgid="3432462749994538265">"Vula"</string>
<string name="incoming_file_confirm_title" msgid="8139874248612182627">"Ukudlulisa ifayela"</string>
- <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ufuna ukukuthumela <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). "\n\n" Yamukela ifayela?"</string>
+ <string name="incoming_file_confirm_content" msgid="6673812334377911289">"\"<xliff:g id="SENDER">%1$s</xliff:g>\" ufuna ukukuthumela <xliff:g id="FILE">%2$s</xliff:g> (<xliff:g id="SIZE">%3$s</xliff:g>). \n\n Yamukela ifayela?"</string>
<string name="incoming_file_confirm_cancel" msgid="2973321832477704805">"Nqaba"</string>
<string name="incoming_file_confirm_ok" msgid="281462442932231475">"Yamukela"</string>
<string name="incoming_file_confirm_timeout_ok" msgid="1414676773249857278">"Kulungile"</string>
@@ -73,9 +73,9 @@
<string name="upload_fail_cancel" msgid="9118496285835687125">"Vala"</string>
<string name="bt_error_btn_ok" msgid="5965151173011534240">"KULUNGILE"</string>
<string name="unknown_file" msgid="6092727753965095366">"Ifayela engaziwa"</string>
- <string name="unknown_file_desc" msgid="480434281415453287">"Alukho uhlelo olulungiselelwe ukuthatha lolu hlobo lwefayela. "\n</string>
+ <string name="unknown_file_desc" msgid="480434281415453287">"Alukho uhlelo olulungiselelwe ukuthatha lolu hlobo lwefayela. \n"</string>
<string name="not_exist_file" msgid="3489434189599716133">"Ayikho ifayela"</string>
- <string name="not_exist_file_desc" msgid="4059531573790529229">"Ifayela ayikho. "\n</string>
+ <string name="not_exist_file_desc" msgid="4059531573790529229">"Ifayela ayikho. \n"</string>
<string name="enabling_progress_title" msgid="436157952334723406">"Sicela ulinde..."</string>
<string name="enabling_progress_content" msgid="4601542238119927904">"Ivula i-Bluetooth..."</string>
<string name="bt_toast_1" msgid="972182708034353383">"Ifayela izotholwa. Hlola intuthuki kwiphaneli Yezaziso."</string>
diff --git a/res/values-zu/strings_map.xml b/res/values-zu/strings_map.xml
new file mode 100644
index 0000000..203fab6
--- /dev/null
+++ b/res/values-zu/strings_map.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="map_session_key_dialog_title" msgid="4357431314165953502">"Thayipha ukhiye weseshini ye-%1$s"</string>
+ <string name="map_session_key_dialog_header" msgid="1858363785687455516">"Ukhiye weseshini ye-Bluetooth uyadingeka"</string>
+ <string name="map_acceptance_timeout_message" msgid="2247454902690565876">"Kube khona isikhathi sokuvala ekwamukeleni ukuxhumeka ne-%1$s"</string>
+ <string name="map_authentication_timeout_message" msgid="2151423397615327066">"Kube khona isikhathi sokuvala ekufakeni ukhiye wesikhathi nge-%1$s"</string>
+ <string name="map_auth_notif_ticker" msgid="8840174807927327119">"Isicelo sokufakazela ubuqiniso se-Obex"</string>
+ <string name="map_auth_notif_title" msgid="301767019364765129">"Ukhiye Weseshini"</string>
+ <string name="map_auth_notif_message" msgid="1510095655064214863">"Thayipha ukhiye wesikhathi we-%1$s"</string>
+ <string name="map_defaultname" msgid="3805234816465216759">"Ikhithi yemoto"</string>
+ <string name="map_unknownName" msgid="4985352365863687360">"Igama elingaziwa"</string>
+ <string name="map_localPhoneName" msgid="6264496105941797768">"Igama lami"</string>
+ <string name="map_defaultnumber" msgid="3838264444043503815">"000000"</string>
+</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index af90926..24eeb2c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -23,4 +23,5 @@
<bool name="profile_supported_gatt">true</bool>
<bool name="pbap_include_photos_in_vcard">false</bool>
<bool name="pbap_use_profile_for_owner_vcard">true</bool>
+ <bool name="profile_supported_map">true</bool>
</resources>
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 2ff6487..3b449ac 100755
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -176,6 +176,19 @@
return priority;
}
+ /* Absolute volume implementation */
+ public boolean isAvrcpAbsoluteVolumeSupported() {
+ return mAvrcp.isAbsoluteVolumeSupported();
+ }
+
+ public void adjustAvrcpAbsoluteVolume(int direction) {
+ mAvrcp.adjustVolume(direction);
+ }
+
+ public void setAvrcpAbsoluteVolume(int volume) {
+ mAvrcp.setAbsoluteVolume(volume);
+ }
+
synchronized boolean isA2dpPlaying(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
@@ -251,6 +264,24 @@
return service.getPriority(device);
}
+ public boolean isAvrcpAbsoluteVolumeSupported() {
+ A2dpService service = getService();
+ if (service == null) return false;
+ return service.isAvrcpAbsoluteVolumeSupported();
+ }
+
+ public void adjustAvrcpAbsoluteVolume(int direction) {
+ A2dpService service = getService();
+ if (service == null) return;
+ service.adjustAvrcpAbsoluteVolume(direction);
+ }
+
+ public void setAvrcpAbsoluteVolume(int volume) {
+ A2dpService service = getService();
+ if (service == null) return;
+ service.setAvrcpAbsoluteVolume(volume);
+ }
+
public boolean isA2dpPlaying(BluetoothDevice device) {
A2dpService service = getService();
if (service == null) return false;
diff --git a/src/com/android/bluetooth/a2dp/Avrcp.java b/src/com/android/bluetooth/a2dp/Avrcp.java
index ac7a323..16fc327 100755
--- a/src/com/android/bluetooth/a2dp/Avrcp.java
+++ b/src/com/android/bluetooth/a2dp/Avrcp.java
@@ -16,6 +16,9 @@
package com.android.bluetooth.a2dp;
+import java.util.Timer;
+import java.util.TimerTask;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +55,7 @@
* support metadata, play status and event notification
*/
final class Avrcp {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
private static final String TAG = "Avrcp";
private Context mContext;
@@ -73,17 +76,65 @@
private int mPlayPosChangedNT;
private long mNextPosMs;
private long mPrevPosMs;
+ private long mSkipStartTime;
+ private int mFeatures;
+ private int mAbsoluteVolume;
+ private int mLastSetVolume;
+ private int mLastDirection;
+ private final int mVolumeStep;
+ private final int mAudioStreamMax;
+ private boolean mVolCmdInProgress;
+ private int mAbsVolRetryTimes;
+ private int mSkipAmount;
- private static final int MESSAGE_GET_PLAY_STATUS = 1;
- private static final int MESSAGE_GET_ELEM_ATTRS = 2;
- private static final int MESSAGE_REGISTER_NOTIFICATION = 3;
- private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 4;
+ /* AVRC IDs from avrc_defs.h */
+ private static final int AVRC_ID_REWIND = 0x48;
+ private static final int AVRC_ID_FAST_FOR = 0x49;
+
+ /* BTRC features */
+ public static final int BTRC_FEAT_METADATA = 0x01;
+ public static final int BTRC_FEAT_ABSOLUTE_VOLUME = 0x02;
+ public static final int BTRC_FEAT_BROWSE = 0x04;
+
+ /* AVRC response codes, from avrc_defs */
+ private static final int AVRC_RSP_NOT_IMPL = 8;
+ private static final int AVRC_RSP_ACCEPT = 9;
+ private static final int AVRC_RSP_REJ = 10;
+ private static final int AVRC_RSP_IN_TRANS = 11;
+ private static final int AVRC_RSP_IMPL_STBL = 12;
+ private static final int AVRC_RSP_CHANGED = 13;
+ private static final int AVRC_RSP_INTERIM = 15;
+
+ private static final int MESSAGE_GET_RC_FEATURES = 1;
+ private static final int MESSAGE_GET_PLAY_STATUS = 2;
+ private static final int MESSAGE_GET_ELEM_ATTRS = 3;
+ private static final int MESSAGE_REGISTER_NOTIFICATION = 4;
+ private static final int MESSAGE_PLAY_INTERVAL_TIMEOUT = 5;
+ private static final int MESSAGE_VOLUME_CHANGED = 6;
+ private static final int MESSAGE_ADJUST_VOLUME = 7;
+ private static final int MESSAGE_SET_ABSOLUTE_VOLUME = 8;
+ private static final int MESSAGE_ABS_VOL_TIMEOUT = 9;
+ private static final int MESSAGE_FAST_FORWARD = 10;
+ private static final int MESSAGE_REWIND = 11;
+ private static final int MESSAGE_CHANGE_PLAY_POS = 12;
private static final int MSG_UPDATE_STATE = 100;
private static final int MSG_SET_METADATA = 101;
private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
private static final int MSG_SET_ARTWORK = 103;
private static final int MSG_SET_GENERATION_ID = 104;
+ private static final int BUTTON_TIMEOUT_TIME = 2000;
+ private static final int BASE_SKIP_AMOUNT = 2000;
+ private static final int KEY_STATE_PRESS = 1;
+ private static final int KEY_STATE_RELEASE = 0;
+ private static final int SKIP_PERIOD = 400;
+ private static final int SKIP_DOUBLE_INTERVAL = 3000;
+ private static final long MAX_MULTIPLIER_VALUE = 128L;
+ private static final int CMD_TIMEOUT_DELAY = 2000;
+ private static final int MAX_ERROR_RETRY_TIMES = 3;
+ private static final int AVRCP_MAX_VOL = 127;
+ private static final int AVRCP_BASE_VOLUME_STEP = 1;
+
static {
classInitNative();
}
@@ -99,12 +150,20 @@
mSongLengthMs = 0L;
mPlaybackIntervalMs = 0L;
mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mFeatures = 0;
+ mAbsoluteVolume = -1;
+ mLastSetVolume = -1;
+ mLastDirection = 0;
+ mVolCmdInProgress = false;
+ mAbsVolRetryTimes = 0;
mContext = context;
initNative();
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ mVolumeStep = Math.max(AVRCP_BASE_VOLUME_STEP, AVRCP_MAX_VOL/mAudioStreamMax);
}
private void start() {
@@ -193,6 +252,11 @@
clientGeneration, (clearing ? 1 : 0), mediaIntent).sendToTarget();
}
}
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ // no-op: this RemoteControlDisplay is not subject to being disabled.
+ }
}
/** Handles Avrcp messages. */
@@ -228,6 +292,14 @@
mClientGeneration = msg.arg1;
break;
+ case MESSAGE_GET_RC_FEATURES:
+ String address = (String) msg.obj;
+ if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
+ ", features="+msg.arg1);
+ mFeatures = msg.arg1;
+ mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
+ break;
+
case MESSAGE_GET_PLAY_STATUS:
if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS");
getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState),
@@ -262,6 +334,119 @@
registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition());
break;
+ case MESSAGE_VOLUME_CHANGED:
+ if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + msg.arg1 +
+ " ctype=" + msg.arg2);
+
+ if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
+ if (mVolCmdInProgress == false) {
+ Log.e(TAG, "Unsolicited response, ignored");
+ break;
+ }
+ removeMessages(MESSAGE_ABS_VOL_TIMEOUT);
+ mVolCmdInProgress = false;
+ mAbsVolRetryTimes = 0;
+ }
+ if (mAbsoluteVolume != msg.arg1 && (msg.arg2 == AVRC_RSP_ACCEPT ||
+ msg.arg2 == AVRC_RSP_CHANGED ||
+ msg.arg2 == AVRC_RSP_INTERIM)) {
+ notifyVolumeChanged(msg.arg1);
+ mAbsoluteVolume = msg.arg1;
+ } else if (msg.arg2 == AVRC_RSP_REJ) {
+ Log.e(TAG, "setAbsoluteVolume call rejected");
+ }
+ break;
+
+ case MESSAGE_ADJUST_VOLUME:
+ if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1);
+ if (mVolCmdInProgress) {
+ if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
+ break;
+ }
+ // Wait on verification on volume from device, before changing the volume.
+ if (mAbsoluteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
+ int setVol = Math.min(AVRCP_MAX_VOL,
+ Math.max(0, mAbsoluteVolume + msg.arg1*mVolumeStep));
+ if (setVolumeNative(setVol)) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
+ CMD_TIMEOUT_DELAY);
+ mVolCmdInProgress = true;
+ mLastDirection = msg.arg1;
+ mLastSetVolume = setVol;
+ }
+ } else {
+ Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
+ }
+ break;
+
+ case MESSAGE_SET_ABSOLUTE_VOLUME:
+ if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME");
+ if (mVolCmdInProgress) {
+ if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
+ break;
+ }
+ if (setVolumeNative(msg.arg1)) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
+ mVolCmdInProgress = true;
+ mLastSetVolume = msg.arg1;
+ }
+ break;
+
+ case MESSAGE_ABS_VOL_TIMEOUT:
+ if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
+ mVolCmdInProgress = false;
+ if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
+ mAbsVolRetryTimes = 0;
+ } else {
+ mAbsVolRetryTimes += 1;
+ if (setVolumeNative(mLastSetVolume)) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
+ CMD_TIMEOUT_DELAY);
+ mVolCmdInProgress = true;
+ }
+ }
+ break;
+
+ case MESSAGE_FAST_FORWARD:
+ case MESSAGE_REWIND:
+ int skipAmount;
+ if (msg.what == MESSAGE_FAST_FORWARD) {
+ if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD");
+ skipAmount = BASE_SKIP_AMOUNT;
+ } else {
+ if (DEBUG) Log.v(TAG, "MESSAGE_REWIND");
+ skipAmount = -BASE_SKIP_AMOUNT;
+ }
+
+ if (hasMessages(MESSAGE_CHANGE_PLAY_POS) &&
+ (skipAmount != mSkipAmount)) {
+ Log.w(TAG, "missing release button event:" + mSkipAmount);
+ }
+
+ if ((!hasMessages(MESSAGE_CHANGE_PLAY_POS)) ||
+ (skipAmount != mSkipAmount)) {
+ mSkipStartTime = SystemClock.elapsedRealtime();
+ }
+
+ removeMessages(MESSAGE_CHANGE_PLAY_POS);
+ if (msg.arg1 == KEY_STATE_PRESS) {
+ mSkipAmount = skipAmount;
+ changePositionBy(mSkipAmount * getSkipMultiplier());
+ Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
+ posMsg.arg1 = 1;
+ sendMessageDelayed(posMsg, SKIP_PERIOD);
+ }
+ break;
+
+ case MESSAGE_CHANGE_PLAY_POS:
+ if (DEBUG) Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1);
+ changePositionBy(mSkipAmount * getSkipMultiplier());
+ if (msg.arg1 * SKIP_PERIOD < BUTTON_TIMEOUT_TIME) {
+ Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
+ posMsg.arg1 = msg.arg1 + 1;
+ sendMessageDelayed(posMsg, SKIP_PERIOD);
+ }
+ break;
}
}
}
@@ -371,6 +556,12 @@
if (DEBUG) Log.v(TAG, "duration=" + mSongLengthMs);
}
+ private void getRcFeatures(byte[] address, int features) {
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_RC_FEATURES, features, 0,
+ Utils.getAddressStringFromByte(address));
+ mHandler.sendMessage(msg);
+ }
+
private void getPlayStatus() {
Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS);
mHandler.sendMessage(msg);
@@ -422,6 +613,41 @@
}
}
+ private void handlePassthroughCmd(int id, int keyState) {
+ switch (id) {
+ case AVRC_ID_REWIND:
+ rewind(keyState);
+ break;
+ case AVRC_ID_FAST_FOR:
+ fastForward(keyState);
+ break;
+ }
+ }
+
+ private void fastForward(int keyState) {
+ Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ private void rewind(int keyState) {
+ Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ private void changePositionBy(long amount) {
+ long currentPosMs = getPlayPosition();
+ if (currentPosMs == -1L) return;
+ long newPosMs = Math.max(0L, currentPosMs + amount);
+ mAudioManager.setRemoteControlClientPlaybackPosition(mClientGeneration,
+ newPosMs);
+ }
+
+ private int getSkipMultiplier() {
+ long currentTime = SystemClock.elapsedRealtime();
+ long multi = (long) Math.pow(2, (currentTime - mSkipStartTime)/SKIP_DOUBLE_INTERVAL);
+ return (int) Math.min(MAX_MULTIPLIER_VALUE, multi);
+ }
+
private void sendTrackChangedRsp() {
byte[] track = new byte[TRACK_ID_SIZE];
/* track is stored in big endian format */
@@ -509,6 +735,59 @@
return playStatus;
}
+ /**
+ * This is called from AudioService. It will return whether this device supports abs volume.
+ * NOT USED AT THE MOMENT.
+ */
+ public boolean isAbsoluteVolumeSupported() {
+ return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
+ }
+
+ /**
+ * We get this call from AudioService. This will send a message to our handler object,
+ * requesting our handler to call setVolumeNative()
+ */
+ public void adjustVolume(int direction) {
+ Message msg = mHandler.obtainMessage(MESSAGE_ADJUST_VOLUME, direction, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ public void setAbsoluteVolume(int volume) {
+ int avrcpVolume = convertToAvrcpVolume(volume);
+ avrcpVolume = Math.min(AVRCP_MAX_VOL, Math.max(0, avrcpVolume));
+ mHandler.removeMessages(MESSAGE_ADJUST_VOLUME);
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_ABSOLUTE_VOLUME, avrcpVolume, 0);
+ mHandler.sendMessage(msg);
+
+ }
+
+ /* Called in the native layer as a btrc_callback to return the volume set on the carkit in the
+ * case when the volume is change locally on the carkit. This notification is not called when
+ * the volume is changed from the phone.
+ *
+ * This method will send a message to our handler to change the local stored volume and notify
+ * AudioService to update the UI
+ */
+ private void volumeChangeCallback(int volume, int ctype) {
+ Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype);
+ mHandler.sendMessage(msg);
+ }
+
+ private void notifyVolumeChanged(int volume) {
+ volume = convertToAudioStreamVolume(volume);
+ mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
+ AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
+ }
+
+ private int convertToAudioStreamVolume(int volume) {
+ // Rescale volume to match AudioSystem's volume
+ return (int) Math.ceil((double) volume*mAudioStreamMax/AVRCP_MAX_VOL);
+ }
+
+ private int convertToAvrcpVolume(int volume) {
+ return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);
+ }
+
// Do not modify without updating the HAL bt_rc.h files.
// match up with btrc_play_status_t enum of bt_rc.h
@@ -553,4 +832,5 @@
private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
+ private native boolean setVolumeNative(int volume);
}
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index b05becd..af8e416 100755
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -203,10 +203,9 @@
* @return the mState
*/
int getState() {
- synchronized (mObject) {
- if (VDBG) debugLog("State = " + mState);
- return mState;
- }
+ /* remove the lock to work around a platform deadlock problem */
+ /* and also for read access, it is safe to remove the lock to save CPU power */
+ return mState;
}
/**
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index f96d1f7..6c7576a 100755
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -74,8 +74,10 @@
//For Debugging only
private static int sRefCount=0;
- public static final String ACTION_LOAD_ADAPTER_PROPERTIES="com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
- public static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
+ public static final String ACTION_LOAD_ADAPTER_PROPERTIES =
+ "com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
+ public static final String ACTION_SERVICE_STATE_CHANGED =
+ "com.android.bluetooth.btservice.action.STATE_CHANGED";
public static final String EXTRA_ACTION="action";
public static final int PROFILE_CONN_CONNECTED = 1;
public static final int PROFILE_CONN_REJECTED = 2;
@@ -872,6 +874,18 @@
return service.createSocketChannel(type, serviceName, uuid, port, flag);
}
+ public boolean configHciSnoopLog(boolean enable) {
+ if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+ (!Utils.checkCaller())) {
+ Log.w(TAG,"configHciSnoopLog(): not allowed for non-active user");
+ return false;
+ }
+
+ AdapterService service = getService();
+ if (service == null) return false;
+ return service.configHciSnoopLog(enable);
+ }
+
public void registerCallback(IBluetoothCallback cb) {
AdapterService service = getService();
if (service == null) return ;
@@ -915,7 +929,7 @@
public synchronized boolean enable(boolean quietMode) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
if (DBG)debugLog("Enable called with quiet mode status = " + mQuietmode);
mQuietmode = quietMode;
Message m =
@@ -926,7 +940,7 @@
boolean disable() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
if (DBG) debugLog("disable() called...");
Message m =
@@ -951,7 +965,7 @@
String getName() {
enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
+ "Need BLUETOOTH permission");
try {
return mAdapterProperties.getName();
@@ -963,7 +977,7 @@
boolean setName(String name) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
return mAdapterProperties.setName(name);
}
@@ -997,14 +1011,14 @@
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
return startDiscoveryNative();
}
boolean cancelDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
+ "Need BLUETOOTH ADMIN permission");
return cancelDiscoveryNative();
}
@@ -1041,6 +1055,10 @@
return false;
}
+ // Pairing is unreliable while scanning, so cancel discovery
+ // Note, remove this when native stack improves
+ cancelDiscoveryNative();
+
Message msg = mBondStateMachine.obtainMessage(BondStateMachine.CREATE_BOND);
msg.obj = device;
mBondStateMachine.sendMessage(msg);
@@ -1254,7 +1272,8 @@
}
boolean setPin(BluetoothDevice device, boolean accept, int len, byte[] pinCode) {
- enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
return false;
@@ -1277,7 +1296,8 @@
}
boolean setPairingConfirmation(BluetoothDevice device, boolean accept) {
- enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);
if (deviceProp == null || deviceProp.getBondState() != BluetoothDevice.BOND_BONDING) {
return false;
@@ -1322,6 +1342,11 @@
return ParcelFileDescriptor.adoptFd(fd);
}
+ boolean configHciSnoopLog(boolean enable) {
+ enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return configHciSnoopLogNative(enable);
+ }
+
void registerCallback(IBluetoothCallback cb) {
mCallbacks.register(cb);
}
@@ -1396,6 +1421,8 @@
private native int createSocketChannelNative(int type, String serviceName,
byte[] uuid, int port, int flag);
+ /*package*/ native boolean configHciSnoopLogNative(boolean enable);
+
protected void finalize() {
cleanup();
if (TRACE_REF) {
diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java
index a2b2ff3..99cc411 100644
--- a/src/com/android/bluetooth/btservice/Config.java
+++ b/src/com/android/bluetooth/btservice/Config.java
@@ -29,6 +29,7 @@
import com.android.bluetooth.hid.HidService;
import com.android.bluetooth.pan.PanService;
import com.android.bluetooth.gatt.GattService;
+import com.android.bluetooth.map.BluetoothMapService;
public class Config {
private static final String TAG = "AdapterServiceConfig";
@@ -44,7 +45,8 @@
HidService.class,
HealthService.class,
PanService.class,
- GattService.class
+ GattService.class,
+ BluetoothMapService.class
};
/**
* Resource flag to indicate whether profile is supported or not.
@@ -55,7 +57,8 @@
R.bool.profile_supported_hid,
R.bool.profile_supported_hdp,
R.bool.profile_supported_pan,
- R.bool.profile_supported_gatt
+ R.bool.profile_supported_gatt,
+ R.bool.profile_supported_map
};
private static Class[] SUPPORTED_PROFILES = new Class[0];
diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java
index a60f977..f054df6 100755
--- a/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -228,7 +228,7 @@
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
- mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
+ mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
}
void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) {
@@ -354,7 +354,7 @@
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address));
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
BluetoothDevice.PAIRING_VARIANT_PIN);
- mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
+ mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
return;
}
@@ -379,7 +379,7 @@
variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY;
} else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION) {
variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY;
- displayPasskey = true;
+ displayPasskey = true;
} else {
errorLog("SSP Pairing variant not present");
return;
@@ -396,7 +396,7 @@
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
}
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant);
- mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
+ mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
}
void aclStateChangeCallback(int status, byte[] address, int newState) {
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 2c967a5..1ab6d87 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -196,6 +196,7 @@
public void binderDied() {
if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
+ stopScan(mAppIf, false);
unregisterClient(mAppIf);
}
}
@@ -286,6 +287,12 @@
service.clientDisconnect(clientIf, address);
}
+ public void clientListen(int clientIf, boolean start) {
+ GattService service = getService();
+ if (service == null) return;
+ service.clientListen(clientIf, start);
+ }
+
public void refreshDevice(int clientIf, String address) {
GattService service = getService();
if (service == null) return;
@@ -324,26 +331,29 @@
public void readDescriptor(int clientIf, String address, int srvcType,
int srvcInstanceId, ParcelUuid srvcId,
int charInstanceId, ParcelUuid charId,
- ParcelUuid descrId, int authReq) {
+ int descrInstanceId, ParcelUuid descrId,
+ int authReq) {
GattService service = getService();
if (service == null) return;
- service.readDescriptor(clientIf, address, srvcType, srvcInstanceId,
- srvcId.getUuid(), charInstanceId,
- charId.getUuid(), descrId.getUuid(),
- authReq);
+ service.readDescriptor(clientIf, address, srvcType,
+ srvcInstanceId, srvcId.getUuid(),
+ charInstanceId, charId.getUuid(),
+ descrInstanceId, descrId.getUuid(),
+ authReq);
}
public void writeDescriptor(int clientIf, String address, int srvcType,
int srvcInstanceId, ParcelUuid srvcId,
int charInstanceId, ParcelUuid charId,
- ParcelUuid descrId, int writeType,
- int authReq, byte[] value) {
+ int descrInstanceId, ParcelUuid descrId,
+ int writeType, int authReq, byte[] value) {
GattService service = getService();
if (service == null) return;
- service.writeDescriptor(clientIf, address, srvcType, srvcInstanceId,
- srvcId.getUuid(), charInstanceId,
- charId.getUuid(), descrId.getUuid(),
- writeType, authReq, value);
+ service.writeDescriptor(clientIf, address, srvcType,
+ srvcInstanceId, srvcId.getUuid(),
+ charInstanceId, charId.getUuid(),
+ descrInstanceId, descrId.getUuid(),
+ writeType, authReq, value);
}
public void beginReliableWrite(int clientIf, String address) {
@@ -468,6 +478,14 @@
srvcId.getUuid(), charInstanceId, charId.getUuid(), confirm, value);
}
+ public void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
+ boolean inclTxPower, int minInterval, int maxInterval,
+ int appearance, byte[] manufacturerData) {
+ GattService service = getService();
+ if (service == null) return;
+ service.setAdvData(serverIf, setScanRsp, inclName, inclTxPower,
+ minInterval, maxInterval, appearance, manufacturerData);
+ }
};
/**************************************************************************
@@ -619,7 +637,7 @@
void onGetDescriptor(int connId, int status, int srvcType,
int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
int charInstId, long charUuidLsb, long charUuidMsb,
- long descrUuidLsb, long descrUuidMsb) throws RemoteException {
+ int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
@@ -635,14 +653,14 @@
app.callback.onGetDescriptor(address, srvcType,
srvcInstId, new ParcelUuid(srvcUuid),
charInstId, new ParcelUuid(charUuid),
- new ParcelUuid(descUuid));
+ descrInstId, new ParcelUuid(descUuid));
}
// Get next descriptor for the current characteristic
gattClientGetDescriptorNative(connId, srvcType,
srvcInstId, srvcUuidLsb, srvcUuidMsb,
charInstId, charUuidLsb, charUuidMsb,
- descrUuidLsb, descrUuidMsb);
+ descrInstId, descrUuidLsb, descrUuidMsb);
} else {
// Explore the next service
continueSearch(connId, 0);
@@ -764,7 +782,7 @@
void onReadDescriptor(int connId, int status, int srvcType,
int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
int charInstId, long charUuidLsb, long charUuidMsb,
- long descrUuidLsb, long descrUuidMsb,
+ int descrInstId, long descrUuidLsb, long descrUuidMsb,
int charType, byte[] data) throws RemoteException {
UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
@@ -780,14 +798,14 @@
app.callback.onDescriptorRead(address, status, srvcType,
srvcInstId, new ParcelUuid(srvcUuid),
charInstId, new ParcelUuid(charUuid),
- new ParcelUuid(descrUuid), data);
+ descrInstId, new ParcelUuid(descrUuid), data);
}
}
void onWriteDescriptor(int connId, int status, int srvcType,
int srvcInstId, long srvcUuidLsb, long srvcUuidMsb,
int charInstId, long charUuidLsb, long charUuidMsb,
- long descrUuidLsb, long descrUuidMsb) throws RemoteException {
+ int descrInstId, long descrUuidLsb, long descrUuidMsb) throws RemoteException {
UUID srvcUuid = new UUID(srvcUuidMsb, srvcUuidLsb);
UUID charUuid = new UUID(charUuidMsb, charUuidLsb);
@@ -802,7 +820,7 @@
app.callback.onDescriptorWrite(address, status, srvcType,
srvcInstId, new ParcelUuid(srvcUuid),
charInstId, new ParcelUuid(charUuid),
- new ParcelUuid(descrUuid));
+ descrInstId, new ParcelUuid(descrUuid));
}
}
@@ -817,6 +835,16 @@
}
}
+ void onClientListen(int status, int clientIf)
+ throws RemoteException {
+ if (DBG) Log.d(TAG, "onClientListen() status=" + status);
+
+ ClientMap.App app = mClientMap.getById(clientIf);
+ if (app == null) return;
+
+ app.callback.onListen(status);
+ }
+
/**************************************************************************
* GATT Service functions - Shared CLIENT/SERVER
*************************************************************************/
@@ -921,7 +949,6 @@
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
- removeScanClient(clientIf, false);
mClientMap.remove(clientIf);
gattClientUnregisterAppNative(clientIf);
}
@@ -942,6 +969,11 @@
gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
}
+ void clientListen(int clientIf, boolean start) {
+ if (DBG) Log.d(TAG, "clientListen() - start=" + start);
+ gattClientListenNative(clientIf, start);
+ }
+
List<String> getConnectedDevices() {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
@@ -1013,7 +1045,8 @@
void readDescriptor(int clientIf, String address, int srvcType,
int srvcInstanceId, UUID srvcUuid,
int charInstanceId, UUID charUuid,
- UUID descrUuid, int authReq) {
+ int descrInstanceId, UUID descrUuid,
+ int authReq) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (DBG) Log.d(TAG, "readDescriptor() - address=" + address);
@@ -1021,9 +1054,11 @@
Integer connId = mClientMap.connIdByAddress(clientIf, address);
if (connId != null)
gattClientReadDescriptorNative(connId, srvcType,
- srvcInstanceId, srvcUuid.getLeastSignificantBits(),
- srvcUuid.getMostSignificantBits(), charInstanceId,
+ srvcInstanceId,
+ srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
+ charInstanceId,
charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
+ descrInstanceId,
descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
authReq);
else
@@ -1033,8 +1068,8 @@
void writeDescriptor(int clientIf, String address, int srvcType,
int srvcInstanceId, UUID srvcUuid,
int charInstanceId, UUID charUuid,
- UUID descrUuid, int writeType,
- int authReq, byte[] value) {
+ int descrInstanceId, UUID descrUuid,
+ int writeType, int authReq, byte[] value) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (DBG) Log.d(TAG, "writeDescriptor() - address=" + address);
@@ -1042,9 +1077,11 @@
Integer connId = mClientMap.connIdByAddress(clientIf, address);
if (connId != null)
gattClientWriteDescriptorNative(connId, srvcType,
- srvcInstanceId, srvcUuid.getLeastSignificantBits(),
- srvcUuid.getMostSignificantBits(), charInstanceId,
+ srvcInstanceId,
+ srvcUuid.getLeastSignificantBits(), srvcUuid.getMostSignificantBits(),
+ charInstanceId,
charUuid.getLeastSignificantBits(), charUuid.getMostSignificantBits(),
+ descrInstanceId,
descrUuid.getLeastSignificantBits(), descrUuid.getMostSignificantBits(),
writeType, authReq, value);
else
@@ -1096,6 +1133,15 @@
gattClientReadRemoteRssiNative(clientIf, address);
}
+ void setAdvData(int serverIf, boolean setScanRsp, boolean inclName,
+ boolean inclTxPower, int minInterval, int maxInterval,
+ int appearance, byte[] manufacturerData) {
+ if (DBG) Log.d(TAG, "setAdvData() - setScanRsp=" + setScanRsp);
+ if (minInterval == 0) maxInterval = 0;
+ gattSetAdvDataNative(serverIf, setScanRsp, inclName, inclTxPower,
+ minInterval, maxInterval, appearance, manufacturerData);
+ }
+
/**************************************************************************
* Callback functions - SERVER
*************************************************************************/
@@ -1477,7 +1523,7 @@
// Descriptor is up next
gattClientGetDescriptorNative(svc.connId, svc.srvcType,
svc.srvcInstId, svc.srvcUuidLsb, svc.srvcUuidMsb,
- svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0,0);
+ svc.charInstId, svc.charUuidLsb, svc.charUuidMsb, 0, 0, 0);
}
} else {
ClientMap.App app = mClientMap.getByConnId(connId);
@@ -1682,10 +1728,10 @@
long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
long char_id_uuid_msb);
- private native void gattClientGetDescriptorNative(int conn_id,
- int service_type, int service_id_inst_id, long service_id_uuid_lsb,
- long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
- long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb);
+ private native void gattClientGetDescriptorNative(int conn_id, int service_type,
+ int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
+ int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
+ int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb);
private native void gattClientGetIncludedServiceNative(int conn_id,
int service_type, int service_id_inst_id,
@@ -1698,10 +1744,10 @@
long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
long char_id_uuid_msb, int authReq);
- private native void gattClientReadDescriptorNative(int conn_id,
- int service_type, int service_id_inst_id, long service_id_uuid_lsb,
- long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
- long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb,
+ private native void gattClientReadDescriptorNative(int conn_id, int service_type,
+ int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
+ int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
+ int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
int authReq);
private native void gattClientWriteCharacteristicNative(int conn_id,
@@ -1709,10 +1755,10 @@
long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
long char_id_uuid_msb, int write_type, int auth_req, byte[] value);
- private native void gattClientWriteDescriptorNative(int conn_id,
- int service_type, int service_id_inst_id, long service_id_uuid_lsb,
- long service_id_uuid_msb, int char_id_inst_id, long char_id_uuid_lsb,
- long char_id_uuid_msb, long descr_id_uuid_lsb, long descr_id_uuid_msb,
+ private native void gattClientWriteDescriptorNative(int conn_id, int service_type,
+ int service_id_inst_id, long service_id_uuid_lsb, long service_id_uuid_msb,
+ int char_id_inst_id, long char_id_uuid_lsb, long char_id_uuid_msb,
+ int descr_id_inst_id, long descr_id_uuid_lsb, long descr_id_uuid_msb,
int write_type, int auth_req, byte[] value);
private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
@@ -1726,6 +1772,12 @@
private native void gattClientReadRemoteRssiNative(int clientIf,
String address);
+ private native void gattClientListenNative(int client_if, boolean start);
+
+ private native void gattSetAdvDataNative(int serverIf, boolean setScanRsp, boolean inclName,
+ boolean inclTxPower, int minInterval, int maxInterval,
+ int appearance, byte[] manufacturerData);
+
private native void gattServerRegisterAppNative(long app_uuid_lsb,
long app_uuid_msb);
diff --git a/src/com/android/bluetooth/hfp/AtPhonebook.java b/src/com/android/bluetooth/hfp/AtPhonebook.java
index d133706..4528bd6 100755
--- a/src/com/android/bluetooth/hfp/AtPhonebook.java
+++ b/src/com/android/bluetooth/hfp/AtPhonebook.java
@@ -47,7 +47,7 @@
* dialed calls respectively)
*/
private static final String[] CALLS_PROJECTION = new String[] {
- Calls._ID, Calls.NUMBER
+ Calls._ID, Calls.NUMBER, Calls.NUMBER_PRESENTATION
};
/** The projection to use when querying the contacts database in response
@@ -69,6 +69,7 @@
private class PhonebookResult {
public Cursor cursor; // result set of last query
public int numberColumn;
+ public int numberPresentationColumn;
public int typeColumn;
public int nameColumn;
};
@@ -403,6 +404,8 @@
if (pbr.cursor == null) return false;
pbr.numberColumn = pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER);
+ pbr.numberPresentationColumn =
+ pbr.cursor.getColumnIndexOrThrow(Calls.NUMBER_PRESENTATION);
pbr.typeColumn = -1;
pbr.nameColumn = -1;
} else {
@@ -411,6 +414,7 @@
if (pbr.cursor == null) return false;
pbr.numberColumn = pbr.cursor.getColumnIndex(Phone.NUMBER);
+ pbr.numberPresentationColumn = -1;
pbr.typeColumn = pbr.cursor.getColumnIndex(Phone.TYPE);
pbr.nameColumn = pbr.cursor.getColumnIndex(Phone.DISPLAY_NAME);
}
@@ -488,7 +492,7 @@
String number = pbr.cursor.getString(pbr.numberColumn);
String name = null;
int type = -1;
- if (pbr.nameColumn == -1) {
+ if (pbr.nameColumn == -1 && number != null && number.length() > 0) {
// try caller id lookup
// TODO: This code is horribly inefficient. I saw it
// take 7 seconds to process 100 missed calls.
@@ -505,8 +509,10 @@
}
if (DBG && name == null) log("Caller ID lookup failed for " + number);
- } else {
+ } else if (pbr.nameColumn != -1) {
name = pbr.cursor.getString(pbr.nameColumn);
+ } else {
+ log("processCpbrCommand: empty name and number");
}
if (name == null) name = "";
name = name.trim();
@@ -523,9 +529,14 @@
number = number.trim();
number = PhoneNumberUtils.stripSeparators(number);
if (number.length() > 30) number = number.substring(0, 30);
- if (number.equals("-1")) {
- // unknown numbers are stored as -1 in our database
+ int numberPresentation = Calls.PRESENTATION_ALLOWED;
+ if (pbr.numberPresentationColumn != -1) {
+ numberPresentation = pbr.cursor.getInt(pbr.numberPresentationColumn);
+ }
+ if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
number = "";
+ // TODO: there are 3 types of numbers should have resource
+ // strings for: unknown, private, and payphone
name = mContext.getString(R.string.unknownNumber);
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
index f6d282c..05034e2 100755
--- a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
+++ b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
@@ -178,6 +178,8 @@
mService = (serviceState.getState() == ServiceState.STATE_IN_SERVICE) ?
HeadsetHalConstants.NETWORK_STATE_AVAILABLE :
HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE;
+ setRoam(serviceState.getRoaming() ? HeadsetHalConstants.SERVICE_TYPE_ROAMING
+ : HeadsetHalConstants.SERVICE_TYPE_HOME);
sendDeviceStateChanged();
}
@@ -321,3 +323,13 @@
mType = type;
}
}
+
+class HeadsetVendorSpecificResultCode {
+ String mCommand;
+ String mArg;
+
+ public HeadsetVendorSpecificResultCode(String command, String arg) {
+ mCommand = command;
+ mArg = arg;
+ }
+}
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index b4928f4..d66009c 100755
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -104,8 +104,12 @@
}
}
else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
- Log.v(TAG, "HeadsetService - Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY");
- mStateMachine.handleAccessPermissionResult(intent);
+ int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
+ if (requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) {
+ Log.v(TAG, "Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY");
+ mStateMachine.handleAccessPermissionResult(intent);
+ }
}
}
};
@@ -257,18 +261,22 @@
service.phoneStateChanged(numActive, numHeld, callState, number, type);
}
- public void roamChanged(boolean roam) {
- HeadsetService service = getService();
- if (service == null) return;
- service.roamChanged(roam);
- }
-
public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type) {
HeadsetService service = getService();
if (service == null) return;
service.clccResponse(index, direction, status, mode, mpty, number, type);
}
+
+ public boolean sendVendorSpecificResultCode(BluetoothDevice device,
+ String command,
+ String arg) {
+ HeadsetService service = getService();
+ if (service == null) {
+ return false;
+ }
+ return service.sendVendorSpecificResultCode(device, command, arg);
+ }
};
//API methods
@@ -478,11 +486,6 @@
mStateMachine.sendMessage(msg);
}
- private void roamChanged(boolean roam) {
- enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
- mStateMachine.sendMessage(HeadsetStateMachine.ROAM_CHANGED, roam);
- }
-
private void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type) {
enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
@@ -490,4 +493,22 @@
new HeadsetClccResponse(index, direction, status, mode, mpty, number, type));
}
+ private boolean sendVendorSpecificResultCode(BluetoothDevice device,
+ String command,
+ String arg) {
+ enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ int connectionState = mStateMachine.getConnectionState(device);
+ if (connectionState != BluetoothProfile.STATE_CONNECTED) {
+ return false;
+ }
+ // Currently we support only "+ANDROID".
+ if (!command.equals(BluetoothHeadset.VENDOR_RESULT_CODE_COMMAND_ANDROID)) {
+ Log.w(TAG, "Disallowed unsolicited result code command: " + command);
+ return false;
+ }
+ mStateMachine.sendMessage(HeadsetStateMachine.SEND_VENDOR_SPECIFIC_RESULT_CODE,
+ new HeadsetVendorSpecificResultCode(command, arg));
+ return true;
+ }
+
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 059f326..7d9dc92 100755
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -62,7 +62,9 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
final class HeadsetStateMachine extends StateMachine {
@@ -88,8 +90,8 @@
static final int CALL_STATE_CHANGED = 9;
static final int INTENT_BATTERY_CHANGED = 10;
static final int DEVICE_STATE_CHANGED = 11;
- static final int ROAM_CHANGED = 12;
- static final int SEND_CCLC_RESPONSE = 13;
+ static final int SEND_CCLC_RESPONSE = 12;
+ static final int SEND_VENDOR_SPECIFIC_RESULT_CODE = 13;
static final int VIRTUAL_CALL_START = 14;
static final int VIRTUAL_CALL_STOP = 15;
@@ -103,6 +105,9 @@
private static final int DIALING_OUT_TIMEOUT_VALUE = 10000;
private static final int START_VR_TIMEOUT_VALUE = 5000;
+ // Keys are AT commands, and values are the company IDs.
+ private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;
+
private static final ParcelUuid[] HEADSET_UUIDS = {
BluetoothUuid.HSP,
BluetoothUuid.Handsfree,
@@ -160,6 +165,10 @@
static {
classInitNative();
+
+ VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID = new HashMap<String, Integer>();
+ VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+XEVENT", BluetoothAssignedNumbers.PLANTRONICS);
+ VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+ANDROID", BluetoothAssignedNumbers.GOOGLE);
}
private HeadsetStateMachine(HeadsetService context) {
@@ -179,8 +188,9 @@
mPhoneState = new HeadsetPhoneState(context, this);
mAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (!context.bindService(new Intent(IBluetoothHeadsetPhone.class.getName()),
- mConnection, 0)) {
+ Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
+ intent.setComponent(intent.resolveSystemService(context.getPackageManager(), 0));
+ if (intent.getComponent() == null || !context.bindService(intent, mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Headset Phone Service");
}
@@ -285,9 +295,6 @@
case INTENT_BATTERY_CHANGED:
processIntentBatteryChanged((Intent) message.obj);
break;
- case ROAM_CHANGED:
- processRoamChanged((Boolean) message.obj);
- break;
case CALL_STATE_CHANGED:
processCallState((HeadsetCallState) message.obj,
((message.arg1 == 1)?true:false));
@@ -416,9 +423,6 @@
case INTENT_BATTERY_CHANGED:
processIntentBatteryChanged((Intent) message.obj);
break;
- case ROAM_CHANGED:
- processRoamChanged((Boolean) message.obj);
- break;
case CALL_STATE_CHANGED:
processCallState((HeadsetCallState) message.obj,
((message.arg1 == 1)?true:false));
@@ -649,15 +653,16 @@
case INTENT_BATTERY_CHANGED:
processIntentBatteryChanged((Intent) message.obj);
break;
- case ROAM_CHANGED:
- processRoamChanged((Boolean) message.obj);
- break;
case DEVICE_STATE_CHANGED:
processDeviceStateChanged((HeadsetDeviceState) message.obj);
break;
case SEND_CCLC_RESPONSE:
processSendClccResponse((HeadsetClccResponse) message.obj);
break;
+ case SEND_VENDOR_SPECIFIC_RESULT_CODE:
+ processSendVendorSpecificResultCode(
+ (HeadsetVendorSpecificResultCode) message.obj);
+ break;
case DIALING_OUT_TIMEOUT:
if (mDialingOut) {
mDialingOut= false;
@@ -866,15 +871,16 @@
case INTENT_BATTERY_CHANGED:
processIntentBatteryChanged((Intent) message.obj);
break;
- case ROAM_CHANGED:
- processRoamChanged((Boolean) message.obj);
- break;
case DEVICE_STATE_CHANGED:
processDeviceStateChanged((HeadsetDeviceState) message.obj);
break;
case SEND_CCLC_RESPONSE:
processSendClccResponse((HeadsetClccResponse) message.obj);
break;
+ case SEND_VENDOR_SPECIFIC_RESULT_CODE:
+ processSendVendorSpecificResultCode(
+ (HeadsetVendorSpecificResultCode) message.obj);
+ break;
case VIRTUAL_CALL_START:
initiateScoUsingVirtualVoiceCall();
@@ -1111,8 +1117,7 @@
mVoiceRecognitionStarted + " mWaitingforVoiceRecognition: " + mWaitingForVoiceRecognition +
" isInCall: " + isInCall());
if (state == HeadsetHalConstants.VR_STATE_STARTED) {
- if (!mVoiceRecognitionStarted &&
- !isVirtualCallInProgress() &&
+ if (!isVirtualCallInProgress() &&
!isInCall())
{
try {
@@ -1713,21 +1718,40 @@
return out.toArray();
}
- private void processAtXevent(String atString) {
- log("processAtXevent - atString = "+ atString);
- if (atString.startsWith("=") && !atString.startsWith("=?")) {
- Object[] args = generateArgs(atString.substring(1));
- broadcastVendorSpecificEventIntent("+XEVENT",
- BluetoothAssignedNumbers.PLANTRONICS,
- BluetoothHeadset.AT_CMD_TYPE_SET,
- args,
- mCurrentDevice);
- atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_OK, 0);
+ /**
+ * @return {@code true} if the given string is a valid vendor-specific AT command.
+ */
+ private boolean processVendorSpecificAt(String atString) {
+ log("processVendorSpecificAt - atString = " + atString);
+
+ // Currently we accept only SET type commands.
+ int indexOfEqual = atString.indexOf("=");
+ if (indexOfEqual == -1) {
+ Log.e(TAG, "processVendorSpecificAt: command type error in " + atString);
+ return false;
}
- else {
- Log.e(TAG, "processAtXevent: command type error");
- atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
+
+ String command = atString.substring(0, indexOfEqual);
+ Integer companyId = VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.get(command);
+ if (companyId == null) {
+ Log.e(TAG, "processVendorSpecificAt: unsupported command: " + atString);
+ return false;
}
+
+ String arg = atString.substring(indexOfEqual + 1);
+ if (arg.startsWith("?")) {
+ Log.e(TAG, "processVendorSpecificAt: command type error in " + atString);
+ return false;
+ }
+
+ Object[] args = generateArgs(arg);
+ broadcastVendorSpecificEventIntent(command,
+ companyId,
+ BluetoothHeadset.AT_CMD_TYPE_SET,
+ args,
+ mCurrentDevice);
+ atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_OK, 0);
+ return true;
}
private void processUnknownAt(String atString) {
@@ -1741,9 +1765,7 @@
processAtCpbs(atCommand.substring(5), commandType);
else if (atCommand.startsWith("+CPBR"))
processAtCpbr(atCommand.substring(5), commandType, mCurrentDevice);
- else if (atCommand.startsWith("+XEVENT"))
- processAtXevent(atCommand.substring(7));
- else
+ else if (!processVendorSpecificAt(atCommand))
atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
}
@@ -1891,11 +1913,6 @@
mPhoneState.setBatteryCharge(batteryLevel);
}
- private void processRoamChanged(boolean roam) {
- mPhoneState.setRoam(roam ? HeadsetHalConstants.SERVICE_TYPE_ROAMING :
- HeadsetHalConstants.SERVICE_TYPE_HOME);
- }
-
private void processDeviceStateChanged(HeadsetDeviceState deviceState) {
notifyDeviceStatusNative(deviceState.mService, deviceState.mRoam, deviceState.mSignal,
deviceState.mBatteryCharge);
@@ -1906,6 +1923,14 @@
clcc.mNumber, clcc.mType);
}
+ private void processSendVendorSpecificResultCode(HeadsetVendorSpecificResultCode resultCode) {
+ String stringToSend = resultCode.mCommand + ": ";
+ if (resultCode.mArg != null) {
+ stringToSend += resultCode.mArg;
+ }
+ atResponseStringNative(stringToSend);
+ }
+
private String getCurrentDeviceName() {
String defaultName = "<unknown>";
if (mCurrentDevice == null) {
diff --git a/src/com/android/bluetooth/map/BluetoothMapAppParams.java b/src/com/android/bluetooth/map/BluetoothMapAppParams.java
new file mode 100644
index 0000000..ffdd2f1
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapAppParams.java
@@ -0,0 +1,798 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+import android.util.Log;
+
+/**
+ * This class encapsulates the appParams needed for MAP.
+ */
+public class BluetoothMapAppParams {
+
+ private static final String TAG = "BluetoothMapAppParams";
+
+ private static final int MAX_LIST_COUNT = 0x01;
+ private static final int MAX_LIST_COUNT_LEN = 0x02; //, 0x0000, 0xFFFF),
+ private static final int START_OFFSET = 0x02;
+ private static final int START_OFFSET_LEN = 0x02; //, 0x0000, 0xFFFF),
+ private static final int FILTER_MESSAGE_TYPE = 0x03;
+ private static final int FILTER_MESSAGE_TYPE_LEN = 0x01; //, 0x0000, 0x000f),
+ private static final int FILTER_PERIOD_BEGIN = 0x04;
+ private static final int FILTER_PERIOD_END = 0x05;
+ private static final int FILTER_READ_STATUS = 0x06;
+ private static final int FILTER_READ_STATUS_LEN = 0x01; //, 0x0000, 0x0002),
+ private static final int FILTER_RECIPIENT = 0x07;
+ private static final int FILTER_ORIGINATOR = 0x08;
+ private static final int FILTER_PRIORITY = 0x09;
+ private static final int FILTER_PRIORITY_LEN = 0x01; //, 0x0000, 0x0002),
+ private static final int ATTACHMENT = 0x0A;
+ private static final int ATTACHMENT_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int TRANSPARENT = 0x0B;
+ private static final int TRANSPARENT_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int RETRY = 0x0C;
+ private static final int RETRY_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int NEW_MESSAGE = 0x0D;
+ private static final int NEW_MESSAGE_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int NOTIFICATION_STATUS = 0x0E;
+ private static final int NOTIFICATION_STATUS_LEN = 0x01; //, 0x0000, 0xFFFF),
+ private static final int MAS_INSTANCE_ID = 0x0F;
+ private static final int MAS_INSTANCE_ID_LEN = 0x01; //, 0x0000, 0x00FF),
+ private static final int PARAMETER_MASK = 0x10;
+ private static final int PARAMETER_MASK_LEN = 0x04; //, 0x0000, 0x0000),
+ private static final int FOLDER_LISTING_SIZE = 0x11;
+ private static final int FOLDER_LISTING_SIZE_LEN = 0x02; //, 0x0000, 0xFFFF),
+ private static final int MESSAGE_LISTING_SIZE = 0x12;
+ private static final int MESSAGE_LISTING_SIZE_LEN = 0x02; //, 0x0000, 0xFFFF),
+ private static final int SUBJECT_LENGTH = 0x13;
+ private static final int SUBJECT_LENGTH_LEN = 0x01; //, 0x0000, 0x00FF),
+ private static final int CHARSET = 0x14;
+ private static final int CHARSET_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int FRACTION_REQUEST = 0x15;
+ private static final int FRACTION_REQUEST_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int FRACTION_DELIVER = 0x16;
+ private static final int FRACTION_DELIVER_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int STATUS_INDICATOR = 0x17;
+ private static final int STATUS_INDICATOR_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int STATUS_VALUE = 0x18;
+ private static final int STATUS_VALUE_LEN = 0x01; //, 0x0000, 0x0001),
+ private static final int MSE_TIME = 0x19;
+
+ public static final int INVALID_VALUE_PARAMETER = -1;
+ public static final int NOTIFICATION_STATUS_NO = 0;
+ public static final int NOTIFICATION_STATUS_YES = 1;
+ public static final int STATUS_INDICATOR_READ = 0;
+ public static final int STATUS_INDICATOR_DELETED = 1;
+ public static final int STATUS_VALUE_YES = 1;
+ public static final int STATUS_VALUE_NO = 0;
+ public static final int CHARSET_NATIVE = 0;
+ public static final int CHARSET_UTF8 = 1;
+
+ private int maxListCount = INVALID_VALUE_PARAMETER;
+ private int startOffset = INVALID_VALUE_PARAMETER;
+ private int filterMessageType = INVALID_VALUE_PARAMETER;
+ private long filterPeriodBegin = INVALID_VALUE_PARAMETER;
+ private long filterPeriodEnd = INVALID_VALUE_PARAMETER;
+ private int filterReadStatus = INVALID_VALUE_PARAMETER;
+ private String filterRecipient = null;
+ private String filterOriginator = null;
+ private int filterPriority = INVALID_VALUE_PARAMETER;
+ private int attachment = INVALID_VALUE_PARAMETER;
+ private int transparent = INVALID_VALUE_PARAMETER;
+ private int retry = INVALID_VALUE_PARAMETER;
+ private int newMessage = INVALID_VALUE_PARAMETER;
+ private int notificationStatus = INVALID_VALUE_PARAMETER;
+ private int masInstanceId = INVALID_VALUE_PARAMETER;
+ private long parameterMask = INVALID_VALUE_PARAMETER;
+ private int folderListingSize = INVALID_VALUE_PARAMETER;
+ private int messageListingSize = INVALID_VALUE_PARAMETER;
+ private int subjectLength = INVALID_VALUE_PARAMETER;
+ private int charset = INVALID_VALUE_PARAMETER;
+ private int fractionRequest = INVALID_VALUE_PARAMETER;
+ private int fractionDeliver = INVALID_VALUE_PARAMETER;
+ private int statusIndicator = INVALID_VALUE_PARAMETER;
+ private int statusValue = INVALID_VALUE_PARAMETER;
+ private long mseTime = INVALID_VALUE_PARAMETER;
+
+ /**
+ * Default constructor, used to build an application parameter object to be
+ * encoded. By default the member variables will be initialized to
+ * {@link INVALID_VALUE_PARAMETER} for values, and empty strings for String
+ * typed members.
+ */
+ public BluetoothMapAppParams() {
+ }
+
+ /**
+ * Creates an application parameter object based on a application parameter
+ * OBEX header. The content of the {@link appParam} byte array will be
+ * parsed, and its content will be stored in the member variables.
+ * {@link INVALID_VALUE_PARAMETER} can be used to determine if a value is
+ * set or not, where strings will be empty, if {@link appParam} did not
+ * contain the parameter.
+ *
+ * @param appParams
+ * the byte array containing the application parameters OBEX
+ * header
+ * @throws IllegalArgumentException
+ * when a parameter does not respect the valid ranges specified
+ * in the MAP spec.
+ * @throws ParseException
+ * if a parameter string if formated incorrectly.
+ */
+ public BluetoothMapAppParams(final byte[] appParams)
+ throws IllegalArgumentException, ParseException {
+ ParseParams(appParams);
+ }
+
+ /**
+ * Parse an application parameter OBEX header stored in a ByteArray.
+ *
+ * @param appParams
+ * the byte array containing the application parameters OBEX
+ * header
+ * @throws IllegalArgumentException
+ * when a parameter does not respect the valid ranges specified
+ * in the MAP spec.
+ * @throws ParseException
+ * if a parameter string if formated incorrectly.
+ */
+ private void ParseParams(final byte[] appParams) throws ParseException,
+ IllegalArgumentException {
+ int i = 0;
+ int tagId, tagLength;
+ ByteBuffer appParamBuf = ByteBuffer.wrap(appParams);
+ appParamBuf.order(ByteOrder.BIG_ENDIAN);
+ while (i < appParams.length) {
+ tagId = appParams[i++] & 0xff; // Convert to unsigned to support values above 127
+ tagLength = appParams[i++] & 0xff; // Convert to unsigned to support values above 127
+ switch (tagId) {
+ case MAX_LIST_COUNT:
+ if (tagLength != MAX_LIST_COUNT_LEN) {
+ Log.w(TAG, "MAX_LIST_COUNT: Wrong length received: " + tagLength
+ + " expected: " + MAX_LIST_COUNT_LEN);
+ break;
+ }
+ setMaxListCount(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
+ break;
+ case START_OFFSET:
+ if (tagLength != START_OFFSET_LEN) {
+ Log.w(TAG, "START_OFFSET: Wrong length received: " + tagLength + " expected: "
+ + START_OFFSET_LEN);
+ break;
+ }
+ setStartOffset(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
+ break;
+ case FILTER_MESSAGE_TYPE:
+ if (tagLength != FILTER_MESSAGE_TYPE_LEN) {
+ Log.w(TAG, "FILTER_MESSAGE_TYPE: Wrong length received: " + tagLength + " expected: "
+ + FILTER_MESSAGE_TYPE_LEN);
+ break;
+ }
+ setFilterMessageType(appParams[i] & 0x0f);
+ break;
+ case FILTER_PERIOD_BEGIN:
+ if(tagLength != 0) {
+ setFilterPeriodBegin(new String(appParams, i, tagLength));
+ }
+ break;
+ case FILTER_PERIOD_END:
+ if(tagLength != 0) {
+ setFilterPeriodEnd(new String(appParams, i, tagLength));
+ }
+ break;
+ case FILTER_READ_STATUS:
+ if (tagLength != FILTER_READ_STATUS_LEN) {
+ Log.w(TAG, "FILTER_READ_STATUS: Wrong length received: " + tagLength + " expected: "
+ + FILTER_READ_STATUS_LEN);
+ break;
+ }
+ setFilterReadStatus(appParams[i] & 0x03); // Lower two bits
+ break;
+ case FILTER_RECIPIENT:
+ setFilterRecipient(new String(appParams, i, tagLength));
+ break;
+ case FILTER_ORIGINATOR:
+ setFilterOriginator(new String(appParams, i, tagLength));
+ break;
+ case FILTER_PRIORITY:
+ if (tagLength != FILTER_PRIORITY_LEN) {
+ Log.w(TAG, "FILTER_PRIORITY: Wrong length received: " + tagLength + " expected: "
+ + FILTER_PRIORITY_LEN);
+ break;
+ }
+ setFilterPriority(appParams[i] & 0x03); // Lower two bits
+ break;
+ case ATTACHMENT:
+ if (tagLength != ATTACHMENT_LEN) {
+ Log.w(TAG, "ATTACHMENT: Wrong length received: " + tagLength + " expected: "
+ + ATTACHMENT_LEN);
+ break;
+ }
+ setAttachment(appParams[i] & 0x01); // Lower bit
+ break;
+ case TRANSPARENT:
+ if (tagLength != TRANSPARENT_LEN) {
+ Log.w(TAG, "TRANSPARENT: Wrong length received: " + tagLength + " expected: "
+ + TRANSPARENT_LEN);
+ break;
+ }
+ setTransparent(appParams[i] & 0x01); // Lower bit
+ break;
+ case RETRY:
+ if (tagLength != RETRY_LEN) {
+ Log.w(TAG, "RETRY: Wrong length received: " + tagLength + " expected: "
+ + RETRY_LEN);
+ break;
+ }
+ setRetry(appParams[i] & 0x01); // Lower bit
+ break;
+ case NEW_MESSAGE:
+ if (tagLength != NEW_MESSAGE_LEN) {
+ Log.w(TAG, "NEW_MESSAGE: Wrong length received: " + tagLength + " expected: "
+ + NEW_MESSAGE_LEN);
+ break;
+ }
+ setNewMessage(appParams[i] & 0x01); // Lower bit
+ break;
+ case NOTIFICATION_STATUS:
+ if (tagLength != NOTIFICATION_STATUS_LEN) {
+ Log.w(TAG, "NOTIFICATION_STATUS: Wrong length received: " + tagLength + " expected: "
+ + NOTIFICATION_STATUS_LEN);
+ break;
+ }
+ setNotificationStatus(appParams[i] & 0x01); // Lower bit
+ break;
+ case MAS_INSTANCE_ID:
+ if (tagLength != MAS_INSTANCE_ID_LEN) {
+ Log.w(TAG, "MAS_INSTANCE_ID: Wrong length received: " + tagLength + " expected: "
+ + MAS_INSTANCE_ID_LEN);
+ break;
+ }
+ setMasInstanceId(appParams[i] & 0xff);
+ break;
+ case PARAMETER_MASK:
+ if (tagLength != PARAMETER_MASK_LEN) {
+ Log.w(TAG, "PARAMETER_MASK: Wrong length received: " + tagLength + " expected: "
+ + PARAMETER_MASK_LEN);
+ break;
+ }
+ setParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
+ break;
+ case FOLDER_LISTING_SIZE:
+ if (tagLength != FOLDER_LISTING_SIZE_LEN) {
+ Log.w(TAG, "FOLDER_LISTING_SIZE: Wrong length received: " + tagLength + " expected: "
+ + FOLDER_LISTING_SIZE_LEN);
+ break;
+ }
+ setFolderListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
+ break;
+ case MESSAGE_LISTING_SIZE:
+ if (tagLength != MESSAGE_LISTING_SIZE_LEN) {
+ Log.w(TAG, "MESSAGE_LISTING_SIZE: Wrong length received: " + tagLength + " expected: "
+ + MESSAGE_LISTING_SIZE_LEN);
+ break;
+ }
+ setMessageListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
+ break;
+ case SUBJECT_LENGTH:
+ if (tagLength != SUBJECT_LENGTH_LEN) {
+ Log.w(TAG, "SUBJECT_LENGTH: Wrong length received: " + tagLength + " expected: "
+ + SUBJECT_LENGTH_LEN);
+ break;
+ }
+ setSubjectLength(appParams[i] & 0xff);
+ break;
+ case CHARSET:
+ if (tagLength != CHARSET_LEN) {
+ Log.w(TAG, "CHARSET: Wrong length received: " + tagLength + " expected: "
+ + CHARSET_LEN);
+ break;
+ }
+ setCharset(appParams[i] & 0x01); // Lower bit
+ break;
+ case FRACTION_REQUEST:
+ if (tagLength != FRACTION_REQUEST_LEN) {
+ Log.w(TAG, "FRACTION_REQUEST: Wrong length received: " + tagLength + " expected: "
+ + FRACTION_REQUEST_LEN);
+ break;
+ }
+ setFractionRequest(appParams[i] & 0x01); // Lower bit
+ break;
+ case FRACTION_DELIVER:
+ if (tagLength != FRACTION_DELIVER_LEN) {
+ Log.w(TAG, "FRACTION_DELIVER: Wrong length received: " + tagLength + " expected: "
+ + FRACTION_DELIVER_LEN);
+ break;
+ }
+ setFractionDeliver(appParams[i] & 0x01); // Lower bit
+ break;
+ case STATUS_INDICATOR:
+ if (tagLength != STATUS_INDICATOR_LEN) {
+ Log.w(TAG, "STATUS_INDICATOR: Wrong length received: " + tagLength + " expected: "
+ + STATUS_INDICATOR_LEN);
+ break;
+ }
+ setStatusIndicator(appParams[i] & 0x01); // Lower bit
+ break;
+ case STATUS_VALUE:
+ if (tagLength != STATUS_VALUE_LEN) {
+ Log.w(TAG, "STATUS_VALUER: Wrong length received: " + tagLength + " expected: "
+ + STATUS_VALUE_LEN);
+ break;
+ }
+ setStatusValue(appParams[i] & 0x01); // Lower bit
+ break;
+ case MSE_TIME:
+ setMseTime(new String(appParams, i, tagLength));
+ break;
+ default:
+ // Just skip unknown Tags, no need to report error
+ Log.w(TAG, "Unknown TagId received ( 0x" + Integer.toString(tagId, 16)
+ + "), skipping...");
+ break;
+ }
+ i += tagLength; // Offset to next TagId
+ }
+ }
+
+ /**
+ * Get the approximate length needed to store the appParameters in a byte
+ * array.
+ *
+ * @return the length in bytes
+ * @throws UnsupportedEncodingException
+ * if the platform does not support UTF-8 encoding.
+ */
+ private int getParamMaxLength() throws UnsupportedEncodingException {
+ int length = 0;
+ length += 25 * 2; // tagId + tagLength
+ length += 27; // fixed sizes
+ length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 15;
+ length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 15;
+ if (getFilterRecipient() != null)
+ length += getFilterRecipient().getBytes("UTF-8").length;
+ if (getFilterOriginator() != null)
+ length += getFilterOriginator().getBytes("UTF-8").length;
+ length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20;
+ return length;
+ }
+
+ /**
+ * Encode the application parameter object to a byte array.
+ *
+ * @return a byte Array representation of the application parameter object.
+ * @throws UnsupportedEncodingException
+ * if the platform does not support UTF-8 encoding.
+ */
+ public byte[] EncodeParams() throws UnsupportedEncodingException {
+ ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength());
+ appParamBuf.order(ByteOrder.BIG_ENDIAN);
+ byte[] retBuf;
+
+ if (getMaxListCount() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) MAX_LIST_COUNT);
+ appParamBuf.put((byte) MAX_LIST_COUNT_LEN);
+ appParamBuf.putShort((short) getMaxListCount());
+ }
+ if (getStartOffset() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) START_OFFSET);
+ appParamBuf.put((byte) START_OFFSET_LEN);
+ appParamBuf.putShort((short) getStartOffset());
+ }
+ if (getFilterMessageType() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FILTER_MESSAGE_TYPE);
+ appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN);
+ appParamBuf.put((byte) getFilterMessageType());
+ }
+ if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FILTER_PERIOD_BEGIN);
+ appParamBuf.put((byte) getFilterPeriodBeginString().getBytes("UTF-8").length);
+ appParamBuf.put(getFilterPeriodBeginString().getBytes("UTF-8"));
+ }
+ if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FILTER_PERIOD_END);
+ appParamBuf.put((byte) getFilterPeriodEndString().getBytes("UTF-8").length);
+ appParamBuf.put(getFilterPeriodEndString().getBytes("UTF-8"));
+ }
+ if (getFilterReadStatus() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FILTER_READ_STATUS);
+ appParamBuf.put((byte) FILTER_READ_STATUS_LEN);
+ appParamBuf.put((byte) getFilterReadStatus());
+ }
+ if (getFilterRecipient() != null) {
+ appParamBuf.put((byte) FILTER_RECIPIENT);
+ appParamBuf.put((byte) getFilterRecipient().getBytes("UTF-8").length);
+ appParamBuf.put(getFilterRecipient().getBytes("UTF-8"));
+ }
+ if (getFilterOriginator() != null) {
+ appParamBuf.put((byte) FILTER_ORIGINATOR);
+ appParamBuf.put((byte) getFilterOriginator().getBytes("UTF-8").length);
+ appParamBuf.put(getFilterOriginator().getBytes("UTF-8"));
+ }
+ if (getFilterPriority() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FILTER_PRIORITY);
+ appParamBuf.put((byte) FILTER_PRIORITY_LEN);
+ appParamBuf.put((byte) getFilterPriority());
+ }
+ if (getAttachment() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) ATTACHMENT);
+ appParamBuf.put((byte) ATTACHMENT_LEN);
+ appParamBuf.put((byte) getAttachment());
+ }
+ if (getTransparent() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) TRANSPARENT);
+ appParamBuf.put((byte) TRANSPARENT_LEN);
+ appParamBuf.put((byte) getTransparent());
+ }
+ if (getRetry() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) RETRY);
+ appParamBuf.put((byte) RETRY_LEN);
+ appParamBuf.put((byte) getRetry());
+ }
+ if (getNewMessage() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) NEW_MESSAGE);
+ appParamBuf.put((byte) NEW_MESSAGE_LEN);
+ appParamBuf.put((byte) getNewMessage());
+ }
+ if (getNotificationStatus() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) NOTIFICATION_STATUS);
+ appParamBuf.put((byte) NOTIFICATION_STATUS_LEN);
+ appParamBuf.putShort((short) getNotificationStatus());
+ }
+ if (getMasInstanceId() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) MAS_INSTANCE_ID);
+ appParamBuf.put((byte) MAS_INSTANCE_ID_LEN);
+ appParamBuf.put((byte) getMasInstanceId());
+ }
+ if (getParameterMask() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) PARAMETER_MASK);
+ appParamBuf.put((byte) PARAMETER_MASK_LEN);
+ appParamBuf.putInt((int) getParameterMask());
+ }
+ if (getFolderListingSize() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FOLDER_LISTING_SIZE);
+ appParamBuf.put((byte) FOLDER_LISTING_SIZE_LEN);
+ appParamBuf.putShort((short) getFolderListingSize());
+ }
+ if (getMessageListingSize() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) MESSAGE_LISTING_SIZE);
+ appParamBuf.put((byte) MESSAGE_LISTING_SIZE_LEN);
+ appParamBuf.putShort((short) getMessageListingSize());
+ }
+ if (getSubjectLength() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) SUBJECT_LENGTH);
+ appParamBuf.put((byte) SUBJECT_LENGTH_LEN);
+ appParamBuf.put((byte) getSubjectLength());
+ }
+ if (getCharset() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) CHARSET);
+ appParamBuf.put((byte) CHARSET_LEN);
+ appParamBuf.put((byte) getCharset());
+ }
+ if (getFractionRequest() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FRACTION_REQUEST);
+ appParamBuf.put((byte) FRACTION_REQUEST_LEN);
+ appParamBuf.put((byte) getFractionRequest());
+ }
+ if (getFractionDeliver() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) FRACTION_DELIVER);
+ appParamBuf.put((byte) FRACTION_DELIVER_LEN);
+ appParamBuf.put((byte) getFractionDeliver());
+ }
+ if (getStatusIndicator() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) STATUS_INDICATOR);
+ appParamBuf.put((byte) STATUS_INDICATOR_LEN);
+ appParamBuf.put((byte) getStatusIndicator());
+ }
+ if (getStatusValue() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) STATUS_VALUE);
+ appParamBuf.put((byte) STATUS_VALUE_LEN);
+ appParamBuf.put((byte) getStatusValue());
+ }
+ if (getMseTime() != INVALID_VALUE_PARAMETER) {
+ appParamBuf.put((byte) MSE_TIME);
+ appParamBuf.put((byte) getMseTimeString().getBytes("UTF-8").length);
+ appParamBuf.put(getMseTimeString().getBytes("UTF-8"));
+ }
+ // We need to reduce the length of the array to match the content
+ retBuf = Arrays.copyOfRange(appParamBuf.array(), appParamBuf.arrayOffset(),
+ appParamBuf.arrayOffset() + appParamBuf.position());
+ return retBuf;
+ }
+
+ public int getMaxListCount() {
+ return maxListCount;
+ }
+
+ public void setMaxListCount(int maxListCount) throws IllegalArgumentException {
+ if (maxListCount < 0 || maxListCount > 0xFFFF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
+ this.maxListCount = maxListCount;
+ }
+
+ public int getStartOffset() {
+ return startOffset;
+ }
+
+ public void setStartOffset(int startOffset) throws IllegalArgumentException {
+ if (startOffset < 0 || startOffset > 0xFFFF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
+ this.startOffset = startOffset;
+ }
+
+ public int getFilterMessageType() {
+ return filterMessageType;
+ }
+
+ public void setFilterMessageType(int filterMessageType) throws IllegalArgumentException {
+ if (filterMessageType < 0 || filterMessageType > 0x000F)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x000F");
+ this.filterMessageType = filterMessageType;
+ }
+
+ public long getFilterPeriodBegin() {
+ return filterPeriodBegin;
+ }
+
+ public String getFilterPeriodBeginString() {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = new Date(filterPeriodBegin);
+ return format.format(date); // Format to YYYYMMDDTHHMMSS local time
+ }
+
+ public void setFilterPeriodBegin(long filterPeriodBegin) {
+ this.filterPeriodBegin = filterPeriodBegin;
+ }
+
+ public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = format.parse(filterPeriodBegin);
+ this.filterPeriodBegin = date.getTime();
+ }
+
+ public long getFilterPeriodEnd() {
+ return filterPeriodEnd;
+ }
+
+ public String getFilterPeriodEndString() {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = new Date(filterPeriodEnd);
+ return format.format(date); // Format to YYYYMMDDTHHMMSS local time
+ }
+
+ public void setFilterPeriodEnd(long filterPeriodEnd) {
+ this.filterPeriodEnd = filterPeriodEnd;
+ }
+
+ public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = format.parse(filterPeriodEnd);
+ this.filterPeriodEnd = date.getTime();
+ }
+
+ public int getFilterReadStatus() {
+ return filterReadStatus;
+ }
+
+ public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException {
+ if (filterReadStatus < 0 || filterReadStatus > 0x0002)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
+ this.filterReadStatus = filterReadStatus;
+ }
+
+ public String getFilterRecipient() {
+ return filterRecipient;
+ }
+
+ public void setFilterRecipient(String filterRecipient) {
+ this.filterRecipient = filterRecipient;
+ }
+
+ public String getFilterOriginator() {
+ return filterOriginator;
+ }
+
+ public void setFilterOriginator(String filterOriginator) {
+ this.filterOriginator = filterOriginator;
+ }
+
+ public int getFilterPriority() {
+ return filterPriority;
+ }
+
+ public void setFilterPriority(int filterPriority) throws IllegalArgumentException {
+ if (filterPriority < 0 || filterPriority > 0x0002)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
+ this.filterPriority = filterPriority;
+ }
+
+ public int getAttachment() {
+ return attachment;
+ }
+
+ public void setAttachment(int attachment) throws IllegalArgumentException {
+ if (attachment < 0 || attachment > 0x0001)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.attachment = attachment;
+ }
+
+ public int getTransparent() {
+ return transparent;
+ }
+
+ public void setTransparent(int transparent) throws IllegalArgumentException {
+ if (transparent < 0 || transparent > 0x0001)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.transparent = transparent;
+ }
+
+ public int getRetry() {
+ return retry;
+ }
+
+ public void setRetry(int retry) throws IllegalArgumentException {
+ if (retry < 0 || retry > 0x0001)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.retry = retry;
+ }
+
+ public int getNewMessage() {
+ return newMessage;
+ }
+
+ public void setNewMessage(int newMessage) throws IllegalArgumentException {
+ if (newMessage < 0 || newMessage > 0x0001)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.newMessage = newMessage;
+ }
+
+ public int getNotificationStatus() {
+ return notificationStatus;
+ }
+
+ public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException {
+ if (notificationStatus < 0 || notificationStatus > 0x0001)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.notificationStatus = notificationStatus;
+ }
+
+ public int getMasInstanceId() {
+ return masInstanceId;
+ }
+
+ public void setMasInstanceId(int masInstanceId) {
+ if (masInstanceId < 0 || masInstanceId > 0x00FF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
+ this.masInstanceId = masInstanceId;
+ }
+
+ public long getParameterMask() {
+ return parameterMask;
+ }
+
+ public void setParameterMask(long parameterMask) {
+ if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
+ this.parameterMask = parameterMask;
+ }
+
+ public int getFolderListingSize() {
+ return folderListingSize;
+ }
+
+ public void setFolderListingSize(int folderListingSize) {
+ if (folderListingSize < 0 || folderListingSize > 0xFFFF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
+ this.folderListingSize = folderListingSize;
+ }
+
+ public int getMessageListingSize() {
+ return messageListingSize;
+ }
+
+ public void setMessageListingSize(int messageListingSize) {
+ if (messageListingSize < 0 || messageListingSize > 0xFFFF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
+ this.messageListingSize = messageListingSize;
+ }
+
+ public int getSubjectLength() {
+ return subjectLength;
+ }
+
+ public void setSubjectLength(int subjectLength) {
+ if (subjectLength < 0 || subjectLength > 0xFF)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
+ this.subjectLength = subjectLength;
+ }
+
+ public int getCharset() {
+ return charset;
+ }
+
+ public void setCharset(int charset) {
+ if (charset < 0 || charset > 0x1)
+ throw new IllegalArgumentException("Out of range: " + charset + ", valid range is 0x0000 to 0x0001");
+ this.charset = charset;
+ }
+
+ public int getFractionRequest() {
+ return fractionRequest;
+ }
+
+ public void setFractionRequest(int fractionRequest) {
+ if (fractionRequest < 0 || fractionRequest > 0x1)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.fractionRequest = fractionRequest;
+ }
+
+ public int getFractionDeliver() {
+ return fractionDeliver;
+ }
+
+ public void setFractionDeliver(int fractionDeliver) {
+ if (fractionDeliver < 0 || fractionDeliver > 0x1)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.fractionDeliver = fractionDeliver;
+ }
+
+ public int getStatusIndicator() {
+ return statusIndicator;
+ }
+
+ public void setStatusIndicator(int statusIndicator) {
+ if (statusIndicator < 0 || statusIndicator > 0x1)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.statusIndicator = statusIndicator;
+ }
+
+ public int getStatusValue() {
+ return statusValue;
+ }
+
+ public void setStatusValue(int statusValue) {
+ if (statusValue < 0 || statusValue > 0x1)
+ throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
+ this.statusValue = statusValue;
+ }
+
+ public long getMseTime() {
+ return mseTime;
+ }
+
+ public String getMseTimeString() {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
+ Date date = new Date(getMseTime());
+ return format.format(date); // Format to YYYYMMDDTHHMMSS±hhmm UTC time ± offset
+ }
+
+ public void setMseTime(long mseTime) {
+ this.mseTime = mseTime;
+ }
+
+ public void setMseTime(String mseTime) throws ParseException {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
+ Date date = format.parse(mseTime);
+ this.mseTime = date.getTime();
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapAuthenticator.java b/src/com/android/bluetooth/map/BluetoothMapAuthenticator.java
new file mode 100644
index 0000000..2d345a1
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapAuthenticator.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import javax.obex.Authenticator;
+import javax.obex.PasswordAuthentication;
+
+/**
+ * BluetoothMapAuthenticator is a used by BluetoothObexServer for obex
+ * authentication procedure.
+ */
+public class BluetoothMapAuthenticator implements Authenticator {
+ private static final String TAG = "BluetoothMapAuthenticator";
+
+ private boolean mChallenged;
+
+ private boolean mAuthCancelled;
+
+ private String mSessionKey;
+
+ private Handler mCallback;
+
+ public BluetoothMapAuthenticator(final Handler callback) {
+ mCallback = callback;
+ mChallenged = false;
+ mAuthCancelled = false;
+ mSessionKey = null;
+ }
+
+ public final synchronized void setChallenged(final boolean bool) {
+ mChallenged = bool;
+ }
+
+ public final synchronized void setCancelled(final boolean bool) {
+ mAuthCancelled = bool;
+ }
+
+ public final synchronized void setSessionKey(final String string) {
+ mSessionKey = string;
+ }
+
+ private void waitUserConfirmation() {
+ Message msg = Message.obtain(mCallback);
+ msg.what = BluetoothMapService.MSG_OBEX_AUTH_CHALL;
+ msg.sendToTarget();
+ synchronized (this) {
+ while (!mChallenged && !mAuthCancelled) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting on isChallenged");
+ }
+ }
+ }
+ }
+
+ public PasswordAuthentication onAuthenticationChallenge(final String description,
+ final boolean isUserIdRequired, final boolean isFullAccess) {
+ waitUserConfirmation();
+ if (mSessionKey.trim().length() != 0) {
+ PasswordAuthentication pa = new PasswordAuthentication(null, mSessionKey.getBytes());
+ return pa;
+ }
+ return null;
+ }
+
+ // TODO: Reserved for future use only, in case MSE challenge MCE
+ public byte[] onAuthenticationResponse(final byte[] userName) {
+ byte[] b = null;
+ return b;
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapContent.java b/src/com/android/bluetooth/map/BluetoothMapContent.java
new file mode 100644
index 0000000..1108a48
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapContent.java
@@ -0,0 +1,1651 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.text.ParseException;
+
+import org.apache.http.util.ByteArrayBuffer;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.Telephony.Mms;
+import android.provider.Telephony.Sms;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+import com.google.android.mms.pdu.CharacterSets;
+
+public class BluetoothMapContent {
+ private static final String TAG = "BluetoothMapContent";
+
+ private static final boolean D = false;
+ private static final boolean V = false;
+
+ private static final int MASK_SUBJECT = 0x1;
+ private static final int MASK_DATETIME = 0x2;
+ private static final int MASK_SENDER_NAME = 0x4;
+ private static final int MASK_SENDER_ADDRESSING = 0x8;
+
+ private static final int MASK_RECIPIENT_NAME = 0x10;
+ private static final int MASK_RECIPIENT_ADDRESSING = 0x20;
+ private static final int MASK_TYPE = 0x40;
+ private static final int MASK_SIZE = 0x80;
+
+ private static final int MASK_RECEPTION_STATUS = 0x100;
+ private static final int MASK_TEXT = 0x200;
+ private static final int MASK_ATTACHMENT_SIZE = 0x400;
+ private static final int MASK_PRIORITY = 0x800;
+
+ private static final int MASK_READ = 0x1000;
+ private static final int MASK_SENT = 0x2000;
+ private static final int MASK_PROTECTED = 0x4000;
+ private static final int MASK_REPLYTO_ADDRESSING = 0x8000;
+
+ /* Type of MMS address. From Telephony.java it must be one of PduHeaders.BCC, */
+ /* PduHeaders.CC, PduHeaders.FROM, PduHeaders.TO. These are from PduHeaders.java */
+ public static final int MMS_FROM = 0x89;
+ public static final int MMS_TO = 0x97;
+ public static final int MMS_BCC = 0x81;
+ public static final int MMS_CC = 0x82;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+
+ static final String[] SMS_PROJECTION = new String[] {
+ BaseColumns._ID,
+ Sms.THREAD_ID,
+ Sms.ADDRESS,
+ Sms.BODY,
+ Sms.DATE,
+ Sms.READ,
+ Sms.TYPE,
+ Sms.STATUS,
+ Sms.LOCKED,
+ Sms.ERROR_CODE,
+ };
+
+ static final String[] MMS_PROJECTION = new String[] {
+ BaseColumns._ID,
+ Mms.THREAD_ID,
+ Mms.MESSAGE_ID,
+ Mms.MESSAGE_SIZE,
+ Mms.SUBJECT,
+ Mms.CONTENT_TYPE,
+ Mms.TEXT_ONLY,
+ Mms.DATE,
+ Mms.DATE_SENT,
+ Mms.READ,
+ Mms.MESSAGE_BOX,
+ Mms.STATUS,
+ };
+
+ private class FilterInfo {
+ public static final int TYPE_SMS = 0;
+ public static final int TYPE_MMS = 1;
+
+ int msgType = TYPE_SMS;
+ int phoneType = 0;
+ String phoneNum = null;
+ String phoneAlphaTag = null;
+ }
+
+ public BluetoothMapContent(final Context context) {
+ mContext = context;
+ mResolver = mContext.getContentResolver();
+ if (mResolver == null) {
+ Log.d(TAG, "getContentResolver failed");
+ }
+ }
+
+ private void addSmsEntry() {
+ if (D) Log.d(TAG, "*** Adding dummy sms ***");
+
+ ContentValues mVal = new ContentValues();
+ mVal.put(Sms.ADDRESS, "1234");
+ mVal.put(Sms.BODY, "Hello!!!");
+ mVal.put(Sms.DATE, System.currentTimeMillis());
+ mVal.put(Sms.READ, "0");
+
+ Uri mUri = mResolver.insert(Sms.CONTENT_URI, mVal);
+ }
+
+ private BluetoothMapAppParams buildAppParams() {
+ BluetoothMapAppParams ap = new BluetoothMapAppParams();
+ try {
+ int paramMask = (MASK_SUBJECT
+ | MASK_DATETIME
+ | MASK_SENDER_NAME
+ | MASK_SENDER_ADDRESSING
+ | MASK_RECIPIENT_NAME
+ | MASK_RECIPIENT_ADDRESSING
+ | MASK_TYPE
+ | MASK_SIZE
+ | MASK_RECEPTION_STATUS
+ | MASK_TEXT
+ | MASK_ATTACHMENT_SIZE
+ | MASK_PRIORITY
+ | MASK_READ
+ | MASK_SENT
+ | MASK_PROTECTED
+ );
+ ap.setMaxListCount(5);
+ ap.setStartOffset(0);
+ ap.setFilterMessageType(0);
+ ap.setFilterPeriodBegin("20130101T000000");
+ ap.setFilterPeriodEnd("20131230T000000");
+ ap.setFilterReadStatus(0);
+ ap.setParameterMask(paramMask);
+ ap.setSubjectLength(10);
+ /* ap.setFilterOriginator("Sms*"); */
+ /* ap.setFilterRecipient("41*"); */
+ } catch (ParseException e) {
+ return null;
+ }
+ return ap;
+ }
+
+ private void printSms(Cursor c) {
+ String body = c.getString(c.getColumnIndex(Sms.BODY));
+ if (D) Log.d(TAG, "printSms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) +
+ " " + Sms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Sms.THREAD_ID)) +
+ " " + Sms.ADDRESS + " : " + c.getString(c.getColumnIndex(Sms.ADDRESS)) +
+ " " + Sms.BODY + " : " + body.substring(0, Math.min(body.length(), 8)) +
+ " " + Sms.DATE + " : " + c.getLong(c.getColumnIndex(Sms.DATE)) +
+ " " + Sms.TYPE + " : " + c.getInt(c.getColumnIndex(Sms.TYPE)));
+ }
+
+ private void printMms(Cursor c) {
+ if (D) Log.d(TAG, "printMms " + BaseColumns._ID + ": " + c.getLong(c.getColumnIndex(BaseColumns._ID)) +
+ "\n " + Mms.THREAD_ID + " : " + c.getLong(c.getColumnIndex(Mms.THREAD_ID)) +
+ "\n " + Mms.MESSAGE_ID + " : " + c.getString(c.getColumnIndex(Mms.MESSAGE_ID)) +
+ "\n " + Mms.SUBJECT + " : " + c.getString(c.getColumnIndex(Mms.SUBJECT)) +
+ "\n " + Mms.CONTENT_TYPE + " : " + c.getString(c.getColumnIndex(Mms.CONTENT_TYPE)) +
+ "\n " + Mms.TEXT_ONLY + " : " + c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) +
+ "\n " + Mms.DATE + " : " + c.getLong(c.getColumnIndex(Mms.DATE)) +
+ "\n " + Mms.DATE_SENT + " : " + c.getLong(c.getColumnIndex(Mms.DATE_SENT)) +
+ "\n " + Mms.READ + " : " + c.getInt(c.getColumnIndex(Mms.READ)) +
+ "\n " + Mms.MESSAGE_BOX + " : " + c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)) +
+ "\n " + Mms.STATUS + " : " + c.getInt(c.getColumnIndex(Mms.STATUS)));
+ }
+
+ private void printMmsAddr(long id) {
+ final String[] projection = null;
+ String selection = new String("msg_id=" + id);
+ String uriStr = String.format("content://mms/%d/addr", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(
+ uriAddress,
+ projection,
+ selection,
+ null, null);
+
+ if (c.moveToFirst()) {
+ do {
+ String add = c.getString(c.getColumnIndex("address"));
+ Integer type = c.getInt(c.getColumnIndex("type"));
+ if (type == MMS_TO) {
+ if (D) Log.d(TAG, " recipient: " + add + " (type: " + type + ")");
+ } else if (type == MMS_FROM) {
+ if (D) Log.d(TAG, " originator: " + add + " (type: " + type + ")");
+ } else {
+ if (D) Log.d(TAG, " address other: " + add + " (type: " + type + ")");
+ }
+
+ } while(c.moveToNext());
+ }
+ }
+
+ private void printMmsPartImage(long partid) {
+ String uriStr = String.format("content://mms/part/%d", partid);
+ Uri uriAddress = Uri.parse(uriStr);
+ int ch;
+ StringBuffer sb = new StringBuffer("");
+ InputStream is = null;
+
+ try {
+ is = mResolver.openInputStream(uriAddress);
+
+ while ((ch = is.read()) != -1) {
+ sb.append((char)ch);
+ }
+ if (D) Log.d(TAG, sb.toString());
+
+ } catch (IOException e) {
+ // do nothing for now
+ e.printStackTrace();
+ }
+ }
+
+ private void printMmsParts(long id) {
+ final String[] projection = null;
+ String selection = new String("mid=" + id);
+ String uriStr = String.format("content://mms/%d/part", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(
+ uriAddress,
+ projection,
+ selection,
+ null, null);
+
+ if (D) Log.d(TAG, " parts:");
+ if (c.moveToFirst()) {
+ do {
+ Long partid = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String ct = c.getString(c.getColumnIndex("ct"));
+ String name = c.getString(c.getColumnIndex("name"));
+ String charset = c.getString(c.getColumnIndex("chset"));
+ String filename = c.getString(c.getColumnIndex("fn"));
+ String text = c.getString(c.getColumnIndex("text"));
+ Integer fd = c.getInt(c.getColumnIndex("_data"));
+ String cid = c.getString(c.getColumnIndex("cid"));
+ String cl = c.getString(c.getColumnIndex("cl"));
+ String cdisp = c.getString(c.getColumnIndex("cd"));
+
+ if (D) Log.d(TAG, " _id : " + partid +
+ "\n ct : " + ct +
+ "\n partname : " + name +
+ "\n charset : " + charset +
+ "\n filename : " + filename +
+ "\n text : " + text +
+ "\n fd : " + fd +
+ "\n cid : " + cid +
+ "\n cl : " + cl +
+ "\n cdisp : " + cdisp);
+
+ /* if (ct.equals("image/jpeg")) { */
+ /* printMmsPartImage(partid); */
+ /* } */
+ } while(c.moveToNext());
+ }
+ }
+
+ public void dumpMmsTable() {
+ if (D) Log.d(TAG, "**** Dump of mms table ****");
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, null, null, "_id DESC");
+ if (c != null) {
+ if (D) Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printMms(c);
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ printMmsAddr(id);
+ printMmsParts(id);
+ }
+ } else {
+ Log.d(TAG, "query failed");
+ c.close();
+ }
+ }
+
+ public void dumpSmsTable() {
+ addSmsEntry();
+ if (D) Log.d(TAG, "**** Dump of sms table ****");
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, null, null, "_id DESC");
+ if (c != null) {
+ if (D) Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printSms(c);
+ }
+ } else {
+ Log.d(TAG, "query failed");
+ c.close();
+ }
+
+ }
+
+ public void dumpMessages() {
+ dumpSmsTable();
+ dumpMmsTable();
+
+ BluetoothMapAppParams ap = buildAppParams();
+ if (D) Log.d(TAG, "message listing size = " + msgListingSize("inbox", ap));
+ BluetoothMapMessageListing mList = msgListing("inbox", ap);
+ try {
+ mList.encode();
+ } catch (UnsupportedEncodingException ex) {
+ /* do nothing */
+ }
+ mList = msgListing("sent", ap);
+ try {
+ mList.encode();
+ } catch (UnsupportedEncodingException ex) {
+ /* do nothing */
+ }
+ }
+
+ private void setProtected(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_PROTECTED) != 0) {
+ String protect = "no";
+ if (D) Log.d(TAG, "setProtected: " + protect);
+ e.setProtect(protect);
+ }
+ }
+
+ private void setSent(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_SENT) != 0) {
+ int msgType = 0;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ msgType = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
+ }
+ String sent = null;
+ if (msgType == 2) {
+ sent = "yes";
+ } else {
+ sent = "no";
+ }
+ if (D) Log.d(TAG, "setSent: " + sent);
+ e.setSent(sent);
+ }
+ }
+
+ private void setRead(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ int read = 0;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ read = c.getInt(c.getColumnIndex(Sms.READ));
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ read = c.getInt(c.getColumnIndex(Mms.READ));
+ }
+ String setread = null;
+ if (read == 1) {
+ setread = "yes";
+ } else {
+ setread = "no";
+ }
+ if (D) Log.d(TAG, "setRead: " + setread);
+ e.setRead(setread, ((ap.getParameterMask() & MASK_READ) != 0));
+ }
+
+ private void setPriority(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_PRIORITY) != 0) {
+ String priority = "no";
+ if (D) Log.d(TAG, "setPriority: " + priority);
+ e.setPriority(priority);
+ }
+ }
+
+ /**
+ * For SMS we set the attachment size to 0, as all data will be text data, hence
+ * attachments for SMS is not possible.
+ * For MMS all data is actually attachments, hence we do set the attachment size to
+ * the total message size. To provide a more accurate attachment size, one could
+ * extract the length (in bytes) of the text parts.
+ */
+ private void setAttachmentSize(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_ATTACHMENT_SIZE) != 0) {
+ int size = 0;
+ if (fi.msgType == FilterInfo.TYPE_MMS) {
+ size = c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE));
+ }
+ if (D) Log.d(TAG, "setAttachmentSize: " + size);
+ e.setAttachmentSize(size);
+ }
+ }
+
+ private void setText(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_TEXT) != 0) {
+ String hasText = "";
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ hasText = "yes";
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ int textOnly = c.getInt(c.getColumnIndex(Mms.TEXT_ONLY));
+ if (textOnly == 1) {
+ hasText = "yes";
+ } else {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String text = getTextPartsMms(id);
+ if (text != null && text.length() > 0) {
+ hasText = "yes";
+ } else {
+ hasText = "no";
+ }
+ }
+ }
+ if (D) Log.d(TAG, "setText: " + hasText);
+ e.setText(hasText);
+ }
+ }
+
+ private void setReceptionStatus(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_RECEPTION_STATUS) != 0) {
+ String status = "complete";
+ if (D) Log.d(TAG, "setReceptionStatus: " + status);
+ e.setReceptionStatus(status);
+ }
+ }
+
+ private void setSize(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_SIZE) != 0) {
+ int size = 0;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ String subject = c.getString(c.getColumnIndex(Sms.BODY));
+ size = subject.length();
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ size = c.getInt(c.getColumnIndex(Mms.MESSAGE_SIZE));
+ }
+ if (D) Log.d(TAG, "setSize: " + size);
+ e.setSize(size);
+ }
+ }
+
+ private void setType(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_TYPE) != 0) {
+ TYPE type = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ if (fi.phoneType == TelephonyManager.PHONE_TYPE_GSM) {
+ type = TYPE.SMS_GSM;
+ } else if (fi.phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+ type = TYPE.SMS_CDMA;
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ type = TYPE.MMS;
+ }
+ if (D) Log.d(TAG, "setType: " + type);
+ e.setType(type);
+ }
+ }
+
+ private void setRecipientAddressing(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_RECIPIENT_ADDRESSING) != 0) {
+ String address = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType == 1) {
+ address = fi.phoneNum;
+ } else {
+ address = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ address = getAddressMms(mResolver, id, MMS_TO);
+ }
+ if (D) Log.d(TAG, "setRecipientAddressing: " + address);
+ e.setRecipientAddressing(address);
+ }
+ }
+
+ private void setRecipientName(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_RECIPIENT_NAME) != 0) {
+ String name = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType != 1) {
+ String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ name = getContactNameFromPhone(phone);
+ } else {
+ name = fi.phoneAlphaTag;
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String phone = getAddressMms(mResolver, id, MMS_TO);
+ name = getContactNameFromPhone(phone);
+ }
+ if (D) Log.d(TAG, "setRecipientName: " + name);
+ e.setRecipientName(name);
+ }
+ }
+
+ private void setSenderAddressing(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_SENDER_ADDRESSING) != 0) {
+ String address = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType == 1) {
+ address = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ } else {
+ address = fi.phoneNum;
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ address = getAddressMms(mResolver, id, MMS_FROM);
+ }
+ if (D) Log.d(TAG, "setSenderAddressing: " + address);
+ e.setSenderAddressing(address);
+ }
+ }
+
+ private void setSenderName(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ if ((ap.getParameterMask() & MASK_SENDER_NAME) != 0) {
+ String name = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType == 1) {
+ String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ name = getContactNameFromPhone(phone);
+ } else {
+ name = fi.phoneAlphaTag;
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String phone = getAddressMms(mResolver, id, MMS_FROM);
+ name = getContactNameFromPhone(phone);
+ }
+ if (D) Log.d(TAG, "setSenderName: " + name);
+ e.setSenderName(name);
+ }
+ }
+
+ private void setDateTime(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ long date = 0;
+
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ date = c.getLong(c.getColumnIndex(Sms.DATE));
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ /* Use Mms.DATE for all messages. Although contract class states */
+ /* Mms.DATE_SENT are for outgoing messages. But that is not working. */
+ date = c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L;
+
+ /* int msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX)); */
+ /* if (msgBox == Mms.MESSAGE_BOX_INBOX) { */
+ /* date = c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L; */
+ /* } else { */
+ /* date = c.getLong(c.getColumnIndex(Mms.DATE_SENT)) * 1000L; */
+ /* } */
+ }
+ e.setDateTime(date);
+ }
+
+ private String getTextPartsMms(long id) {
+ String text = "";
+ String selection = new String("mid=" + id);
+ String uriStr = String.format("content://mms/%d/part", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(uriAddress, null, selection,
+ null, null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ String ct = c.getString(c.getColumnIndex("ct"));
+ if (ct.equals("text/plain")) {
+ text += c.getString(c.getColumnIndex("text"));
+ }
+ } while(c.moveToNext());
+ }
+ if (c != null) {
+ c.close();
+ }
+ return text;
+ }
+
+ private void setSubject(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ String subject = "";
+ int subLength = ap.getSubjectLength();
+ if(subLength == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
+ subLength = 256;
+
+ if ((ap.getParameterMask() & MASK_SUBJECT) != 0) {
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ subject = c.getString(c.getColumnIndex(Sms.BODY));
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ subject = c.getString(c.getColumnIndex(Mms.SUBJECT));
+ if (subject == null || subject.length() == 0) {
+ /* Get subject from mms text body parts - if any exists */
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ subject = getTextPartsMms(id);
+ }
+ }
+ if (subject != null) {
+ subject = subject.substring(0, Math.min(subject.length(),
+ subLength));
+ }
+ if (D) Log.d(TAG, "setSubject: " + subject);
+ e.setSubject(subject);
+ }
+ }
+
+ private void setHandle(BluetoothMapMessageListingElement e, Cursor c,
+ FilterInfo fi, BluetoothMapAppParams ap) {
+ long handle = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ TYPE type = null;
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ if (fi.phoneType == TelephonyManager.PHONE_TYPE_GSM) {
+ type = TYPE.SMS_GSM;
+ } else if (fi.phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+ type = TYPE.SMS_CDMA;
+ }
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ type = TYPE.MMS;
+ }
+ if (D) Log.d(TAG, "setHandle: " + handle + " - Type: " + type.name());
+ e.setHandle(handle, type);
+ }
+
+ private BluetoothMapMessageListingElement element(Cursor c, FilterInfo fi,
+ BluetoothMapAppParams ap) {
+ BluetoothMapMessageListingElement e = new BluetoothMapMessageListingElement();
+
+ setHandle(e, c, fi, ap);
+ setSubject(e, c, fi, ap);
+ setDateTime(e, c, fi, ap);
+ setSenderName(e, c, fi, ap);
+ setSenderAddressing(e, c, fi, ap);
+ setRecipientName(e, c, fi, ap);
+ setRecipientAddressing(e, c, fi, ap);
+ setType(e, c, fi, ap);
+ setSize(e, c, fi, ap);
+ setReceptionStatus(e, c, fi, ap);
+ setText(e, c, fi, ap);
+ setAttachmentSize(e, c, fi, ap);
+ setPriority(e, c, fi, ap);
+ setRead(e, c, fi, ap);
+ setSent(e, c, fi, ap);
+ setProtected(e, c, fi, ap);
+ return e;
+ }
+
+ private String getContactNameFromPhone(String phone) {
+ String name = null;
+
+ Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(phone));
+
+ String[] projection = {Contacts._ID, Contacts.DISPLAY_NAME};
+ String selection = Contacts.IN_VISIBLE_GROUP + "=1";
+ String orderBy = Contacts.DISPLAY_NAME + " ASC";
+
+ Cursor c = mResolver.query(uri, projection, selection, null, orderBy);
+
+ if (c != null && c.getCount() >= 1) {
+ c.moveToFirst();
+ name = c.getString(c.getColumnIndex(Contacts.DISPLAY_NAME));
+ }
+
+ c.close();
+ return name;
+ }
+
+ static public String getAddressMms(ContentResolver r, long id, int type) {
+ String selection = new String("msg_id=" + id + " AND type=" + type);
+ String uriStr = String.format("content://mms/%d/addr", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ String addr = null;
+ Cursor c = r.query(uriAddress, null, selection, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ addr = c.getString(c.getColumnIndex("address"));
+ }
+
+ if (c != null) {
+ c.close();
+ }
+ return addr;
+ }
+
+ private boolean matchRecipientMms(Cursor c, FilterInfo fi, String recip) {
+ boolean res;
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String phone = getAddressMms(mResolver, id, MMS_TO);
+ if (phone != null && phone.length() > 0) {
+ if (phone.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient phone = " + phone);
+ res = true;
+ } else {
+ String name = getContactNameFromPhone(phone);
+ if (name != null && name.length() > 0 && name.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ } else {
+ res = false;
+ }
+ return res;
+ }
+
+ private boolean matchRecipientSms(Cursor c, FilterInfo fi, String recip) {
+ boolean res;
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType == 1) {
+ String phone = fi.phoneNum;
+ String name = fi.phoneAlphaTag;
+ if (phone != null && phone.length() > 0 && phone.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient phone = " + phone);
+ res = true;
+ } else if (name != null && name.length() > 0 && name.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ else {
+ String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ if (phone != null && phone.length() > 0) {
+ if (phone.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient phone = " + phone);
+ res = true;
+ } else {
+ String name = getContactNameFromPhone(phone);
+ if (name != null && name.length() > 0 && name.matches(recip)) {
+ if (D) Log.d(TAG, "match recipient name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ } else {
+ res = false;
+ }
+ }
+ return res;
+ }
+
+ private boolean matchRecipient(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
+ boolean res;
+ String recip = ap.getFilterRecipient();
+ if (recip != null && recip.length() > 0) {
+ recip = recip.replace("*", ".*");
+ recip = ".*" + recip + ".*";
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ res = matchRecipientSms(c, fi, recip);
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ res = matchRecipientMms(c, fi, recip);
+ } else {
+ if (D) Log.d(TAG, "Unknown msg type: " + fi.msgType);
+ res = false;
+ }
+ } else {
+ res = true;
+ }
+ return res;
+ }
+
+ private boolean matchOriginatorMms(Cursor c, FilterInfo fi, String orig) {
+ boolean res;
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String phone = getAddressMms(mResolver, id, MMS_FROM);
+ if (phone != null && phone.length() > 0) {
+ if (phone.matches(orig)) {
+ if (D) Log.d(TAG, "match originator phone = " + phone);
+ res = true;
+ } else {
+ String name = getContactNameFromPhone(phone);
+ if (name != null && name.length() > 0 && name.matches(orig)) {
+ if (D) Log.d(TAG, "match originator name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ } else {
+ res = false;
+ }
+ return res;
+ }
+
+ private boolean matchOriginatorSms(Cursor c, FilterInfo fi, String orig) {
+ boolean res;
+ int msgType = c.getInt(c.getColumnIndex(Sms.TYPE));
+ if (msgType == 1) {
+ String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ if (phone !=null && phone.length() > 0) {
+ if (phone.matches(orig)) {
+ if (D) Log.d(TAG, "match originator phone = " + phone);
+ res = true;
+ } else {
+ String name = getContactNameFromPhone(phone);
+ if (name != null && name.length() > 0 && name.matches(orig)) {
+ if (D) Log.d(TAG, "match originator name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ } else {
+ res = false;
+ }
+ }
+ else {
+ String phone = fi.phoneNum;
+ String name = fi.phoneAlphaTag;
+ if (phone != null && phone.length() > 0 && phone.matches(orig)) {
+ if (D) Log.d(TAG, "match originator phone = " + phone);
+ res = true;
+ } else if (name != null && name.length() > 0 && name.matches(orig)) {
+ if (D) Log.d(TAG, "match originator name = " + name);
+ res = true;
+ } else {
+ res = false;
+ }
+ }
+ return res;
+ }
+
+ private boolean matchOriginator(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
+ boolean res;
+ String orig = ap.getFilterOriginator();
+ if (orig != null && orig.length() > 0) {
+ orig = orig.replace("*", ".*");
+ orig = ".*" + orig + ".*";
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ res = matchOriginatorSms(c, fi, orig);
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ res = matchOriginatorMms(c, fi, orig);
+ } else {
+ Log.d(TAG, "Unknown msg type: " + fi.msgType);
+ res = false;
+ }
+ } else {
+ res = true;
+ }
+ return res;
+ }
+
+ private boolean matchAddresses(Cursor c, FilterInfo fi, BluetoothMapAppParams ap) {
+ if (matchOriginator(c, fi, ap) && matchRecipient(c, fi, ap)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private String setWhereFilterFolderTypeSms(String folder) {
+ String where = "";
+ if ("inbox".equalsIgnoreCase(folder)) {
+ where = "type = 1 AND thread_id <> -1";
+ }
+ else if ("outbox".equalsIgnoreCase(folder)) {
+ where = "(type = 4 OR type = 5 OR type = 6) AND thread_id <> -1";
+ }
+ else if ("sent".equalsIgnoreCase(folder)) {
+ where = "type = 2 AND thread_id <> -1";
+ }
+ else if ("draft".equalsIgnoreCase(folder)) {
+ where = "type = 3 AND thread_id <> -1";
+ }
+ else if ("deleted".equalsIgnoreCase(folder)) {
+ where = "thread_id = -1";
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterFolderTypeMms(String folder) {
+ String where = "";
+ if ("inbox".equalsIgnoreCase(folder)) {
+ where = "msg_box = 1 AND thread_id <> -1";
+ }
+ else if ("outbox".equalsIgnoreCase(folder)) {
+ where = "msg_box = 4 AND thread_id <> -1";
+ }
+ else if ("sent".equalsIgnoreCase(folder)) {
+ where = "msg_box = 2 AND thread_id <> -1";
+ }
+ else if ("draft".equalsIgnoreCase(folder)) {
+ where = "msg_box = 3 AND thread_id <> -1";
+ }
+ else if ("deleted".equalsIgnoreCase(folder)) {
+ where = "thread_id = -1";
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterFolderType(String folder, FilterInfo fi) {
+ String where = "";
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ where = setWhereFilterFolderTypeSms(folder);
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ where = setWhereFilterFolderTypeMms(folder);
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterReadStatus(BluetoothMapAppParams ap) {
+ String where = "";
+ if (ap.getFilterReadStatus() != -1) {
+ if ((ap.getFilterReadStatus() & 0x01) != 0) {
+ where = " AND read=0 ";
+ }
+
+ if ((ap.getFilterReadStatus() & 0x02) != 0) {
+ where = " AND read=1 ";
+ }
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterPeriod(BluetoothMapAppParams ap, FilterInfo fi) {
+ String where = "";
+ if ((ap.getFilterPeriodBegin() != -1)) {
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ where = " AND date >= " + ap.getFilterPeriodBegin();
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ where = " AND date >= " + (ap.getFilterPeriodBegin() / 1000L);
+ }
+ }
+
+ if ((ap.getFilterPeriodEnd() != -1)) {
+ if (fi.msgType == FilterInfo.TYPE_SMS) {
+ where += " AND date < " + ap.getFilterPeriodEnd();
+ } else if (fi.msgType == FilterInfo.TYPE_MMS) {
+ where += " AND date < " + (ap.getFilterPeriodEnd() / 1000L);
+ }
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterPhones(String str) {
+ String where = "";
+ str = str.replace("*", "%");
+
+ Cursor c = mResolver.query(ContactsContract.Contacts.CONTENT_URI, null,
+ ContactsContract.Contacts.DISPLAY_NAME + " like ?",
+ new String[]{str},
+ ContactsContract.Contacts.DISPLAY_NAME + " ASC");
+
+ while (c != null && c.moveToNext()) {
+ String contactId = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));
+
+ Cursor p = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
+ ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
+ new String[]{contactId},
+ null);
+
+ while (p != null && p.moveToNext()) {
+ String number = p.getString(
+ p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
+
+ where += " address = " + "'" + number + "'";
+ if (!p.isLast()) {
+ where += " OR ";
+ }
+ }
+ if (!c.isLast()) {
+ where += " OR ";
+ }
+ p.close();
+ }
+ c.close();
+
+ if (str != null && str.length() > 0) {
+ if (where.length() > 0) {
+ where += " OR ";
+ }
+ where += " address like " + "'" + str + "'";
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterOriginator(BluetoothMapAppParams ap,
+ FilterInfo fi) {
+ String where = "";
+ String orig = ap.getFilterOriginator();
+
+ if (orig != null && orig.length() > 0) {
+ String phones = setWhereFilterPhones(orig);
+
+ if (phones.length() > 0) {
+ where = " AND ((type <> 1) OR ( " + phones + " ))";
+ } else {
+ where = " AND (type <> 1)";
+ }
+
+ orig = orig.replace("*", ".*");
+ orig = ".*" + orig + ".*";
+
+ boolean localPhoneMatchOrig = false;
+ if (fi.phoneNum != null && fi.phoneNum.length() > 0
+ && fi.phoneNum.matches(orig)) {
+ localPhoneMatchOrig = true;
+ }
+
+ if (fi.phoneAlphaTag != null && fi.phoneAlphaTag.length() > 0
+ && fi.phoneAlphaTag.matches(orig)) {
+ localPhoneMatchOrig = true;
+ }
+
+ if (!localPhoneMatchOrig) {
+ where += " AND (type = 1)";
+ }
+ }
+
+ return where;
+ }
+
+ private String setWhereFilterRecipient(BluetoothMapAppParams ap,
+ FilterInfo fi) {
+ String where = "";
+ String recip = ap.getFilterRecipient();
+
+ if (recip != null && recip.length() > 0) {
+ String phones = setWhereFilterPhones(recip);
+
+ if (phones.length() > 0) {
+ where = " AND ((type = 1) OR ( " + phones + " ))";
+ } else {
+ where = " AND (type = 1)";
+ }
+
+ recip = recip.replace("*", ".*");
+ recip = ".*" + recip + ".*";
+
+ boolean localPhoneMatchOrig = false;
+ if (fi.phoneNum != null && fi.phoneNum.length() > 0
+ && fi.phoneNum.matches(recip)) {
+ localPhoneMatchOrig = true;
+ }
+
+ if (fi.phoneAlphaTag != null && fi.phoneAlphaTag.length() > 0
+ && fi.phoneAlphaTag.matches(recip)) {
+ localPhoneMatchOrig = true;
+ }
+
+ if (!localPhoneMatchOrig) {
+ where += " AND (type <> 1)";
+ }
+ }
+
+ return where;
+ }
+
+ private String setWhereFilter(String folder, FilterInfo fi, BluetoothMapAppParams ap) {
+ String where = "";
+
+ where += setWhereFilterFolderType(folder, fi);
+ where += setWhereFilterReadStatus(ap);
+ where += setWhereFilterPeriod(ap, fi);
+ /* where += setWhereFilterOriginator(ap, fi); */
+ /* where += setWhereFilterRecipient(ap, fi); */
+
+ if (D) Log.d(TAG, "where: " + where);
+
+ return where;
+ }
+
+ private boolean smsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
+ int msgType = ap.getFilterMessageType();
+ int phoneType = fi.phoneType;
+
+ if (msgType == -1)
+ return true;
+ if ((msgType & 0x03) == 0)
+ return true;
+
+ if (((msgType & 0x01) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_GSM))
+ return true;
+
+ if (((msgType & 0x02) == 0) && (phoneType == TelephonyManager.PHONE_TYPE_CDMA))
+ return true;
+
+ return false;
+ }
+
+ private boolean mmsSelected(FilterInfo fi, BluetoothMapAppParams ap) {
+ int msgType = ap.getFilterMessageType();
+
+ if (msgType == -1)
+ return true;
+
+ if ((msgType & 0x08) == 0)
+ return true;
+
+ return false;
+ }
+
+ private void setFilterInfo(FilterInfo fi) {
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ if (tm != null) {
+ fi.phoneType = tm.getPhoneType();
+ fi.phoneNum = tm.getLine1Number();
+ fi.phoneAlphaTag = tm.getLine1AlphaTag();
+ if (D) Log.d(TAG, "phone type = " + fi.phoneType +
+ " phone num = " + fi.phoneNum +
+ " phone alpha tag = " + fi.phoneAlphaTag);
+ }
+ }
+
+ public BluetoothMapMessageListing msgListing(String folder, BluetoothMapAppParams ap) {
+ Log.d(TAG, "msgListing: folder = " + folder);
+ BluetoothMapMessageListing bmList = new BluetoothMapMessageListing();
+ BluetoothMapMessageListingElement e = null;
+
+ /* Cache some info used throughout filtering */
+ FilterInfo fi = new FilterInfo();
+ setFilterInfo(fi);
+
+ if (smsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_SMS;
+
+ String where = setWhereFilter(folder, fi, ap);
+
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ while (c.moveToNext()) {
+ if (matchAddresses(c, fi, ap)) {
+ printSms(c);
+ e = element(c, fi, ap);
+ bmList.add(e);
+ }
+ }
+ c.close();
+ }
+ }
+
+ if (mmsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_MMS;
+
+ String where = setWhereFilter(folder, fi, ap);
+
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ int cnt = 0;
+ while (c.moveToNext()) {
+ if (matchAddresses(c, fi, ap)) {
+ printMms(c);
+ e = element(c, fi, ap);
+ bmList.add(e);
+ }
+ }
+ c.close();
+ }
+ }
+
+ /* Enable this if post sorting and segmenting needed */
+ bmList.sort();
+ bmList.segment(ap.getMaxListCount(), ap.getStartOffset());
+
+ return bmList;
+ }
+
+ public int msgListingSize(String folder, BluetoothMapAppParams ap) {
+ if (D) Log.d(TAG, "msgListingSize: folder = " + folder);
+ int cnt = 0;
+
+ /* Cache some info used throughout filtering */
+ FilterInfo fi = new FilterInfo();
+ setFilterInfo(fi);
+
+ if (smsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_SMS;
+ String where = setWhereFilter(folder, fi, ap);
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ cnt = c.getCount();
+ c.close();
+ }
+ }
+
+ if (mmsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_MMS;
+ String where = setWhereFilter(folder, fi, ap);
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ cnt += c.getCount();
+ c.close();
+ }
+ }
+
+ if (D) Log.d(TAG, "msgListingSize: size = " + cnt);
+ return cnt;
+ }
+ /**
+ * Return true if there are unread messages in the requested list of messages
+ * @param folder folder where the message listing should come from
+ * @param ap application parameter object
+ * @return true if unread messages are in the list, else false
+ */
+ public boolean msgListingHasUnread(String folder, BluetoothMapAppParams ap) {
+ if (D) Log.d(TAG, "msgListingHasUnread: folder = " + folder);
+ int cnt = 0;
+
+ /* Cache some info used throughout filtering */
+ FilterInfo fi = new FilterInfo();
+ setFilterInfo(fi);
+
+ if (smsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_SMS;
+ String where = setWhereFilterFolderType(folder, fi);
+ where += " AND read=0 ";
+ where += setWhereFilterPeriod(ap, fi);
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ cnt = c.getCount();
+ c.close();
+ }
+ }
+
+ if (mmsSelected(fi, ap)) {
+ fi.msgType = FilterInfo.TYPE_MMS;
+ String where = setWhereFilterFolderType(folder, fi);
+ where += " AND read=0 ";
+ where += setWhereFilterPeriod(ap, fi);
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, where, null, "date DESC");
+
+ if (c != null) {
+ cnt += c.getCount();
+ c.close();
+ }
+ }
+
+ if (D) Log.d(TAG, "msgListingHasUnread: numUnread = " + cnt);
+ return (cnt>0)?true:false;
+ }
+
+ /**
+ * Get the folder name of an SMS message or MMS message.
+ * @param c the cursor pointing at the message
+ * @return the folder name.
+ */
+ private String getFolderName(int type, int threadId) {
+
+ if(threadId == -1)
+ return "deleted";
+
+ switch(type) {
+ case 1:
+ return "inbox";
+ case 2:
+ return "sent";
+ case 3:
+ return "draft";
+ case 4: // Just name outbox, failed and queued "outbox"
+ case 5:
+ case 6:
+ return "outbox";
+ }
+ return "";
+ }
+
+ public byte[] getMessage(String handle, BluetoothMapAppParams appParams) throws UnsupportedEncodingException{
+ TYPE type = BluetoothMapUtils.getMsgTypeFromHandle(handle);
+ long id = BluetoothMapUtils.getCpHandle(handle);
+ switch(type) {
+ case SMS_GSM:
+ case SMS_CDMA:
+ return getSmsMessage(id, appParams.getCharset());
+ case MMS:
+ return getMmsMessage(id, appParams);
+ case EMAIL:
+ throw new IllegalArgumentException("Email not implemented - invalid message handle.");
+ }
+ throw new IllegalArgumentException("Invalid message handle.");
+ }
+
+ private void setVCardFromPhoneNumber(BluetoothMapbMessage message, String phone, boolean incoming) {
+ String contactId = null, contactName = null;
+ String[] phoneNumbers = null;
+ String[] emailAddresses = null;
+ Cursor p;
+
+ Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(phone));
+
+ String[] projection = {Contacts._ID, Contacts.DISPLAY_NAME};
+ String selection = Contacts.IN_VISIBLE_GROUP + "=1";
+ String orderBy = Contacts._ID + " ASC";
+
+ // Get the contact _ID and name
+ p = mResolver.query(uri, projection, selection, null, orderBy);
+ if (p != null && p.getCount() >= 1) {
+ p.moveToFirst();
+ contactId = p.getString(p.getColumnIndex(Contacts._ID));
+ contactName = p.getString(p.getColumnIndex(Contacts.DISPLAY_NAME));
+ }
+ p.close();
+
+ // Bail out if we are unable to find a contact, based on the phone number
+ if(contactId == null) {
+ phoneNumbers = new String[1];
+ phoneNumbers[0] = phone;
+ }
+ else {
+ // Fetch all contact phone numbers
+ p = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
+ ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
+ new String[]{contactId},
+ null);
+ if(p != null) {
+ int i = 0;
+ phoneNumbers = new String[p.getCount()];
+ while (p != null && p.moveToNext()) {
+ String number = p.getString(
+ p.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
+ phoneNumbers[i++] = number;
+ }
+ p.close();
+ }
+
+ // Fetch contact e-mail addresses
+ p = mResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
+ ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
+ new String[]{contactId},
+ null);
+ if(p != null) {
+ int i = 0;
+ emailAddresses = new String[p.getCount()];
+ while (p != null && p.moveToNext()) {
+ String emailAddress = p.getString(
+ p.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
+ emailAddresses[i++] = emailAddress;
+ }
+ p.close();
+ }
+ }
+ if(incoming == true)
+ message.addOriginator(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
+ else
+ message.addRecipient(contactName, contactName, phoneNumbers, emailAddresses); // Use version 3.0 as we only have a formatted name
+ }
+
+ public static final int MAP_MESSAGE_CHARSET_NATIVE = 0;
+ public static final int MAP_MESSAGE_CHARSET_UTF8 = 1;
+
+ public byte[] getSmsMessage(long id, int charset) throws UnsupportedEncodingException{
+ int type, threadId;
+ long time = -1;
+ String msgBody;
+ BluetoothMapbMessageSms message = new BluetoothMapbMessageSms();
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, "_ID = " + id, null, null);
+
+ if(c != null && c.moveToFirst())
+ {
+
+ if(V) Log.d(TAG,"c.count: " + c.getCount());
+
+ if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ message.setType(TYPE.SMS_GSM);
+ } else if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
+ message.setType(TYPE.SMS_CDMA);
+ }
+
+ String read = c.getString(c.getColumnIndex(Sms.READ));
+ if (read.equalsIgnoreCase("1"))
+ message.setStatus(true);
+ else
+ message.setStatus(false);
+
+ type = c.getInt(c.getColumnIndex(Sms.TYPE));
+ threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID));
+ message.setFolder(getFolderName(type, threadId));
+
+ msgBody = c.getString(c.getColumnIndex(Sms.BODY));
+
+ String phone = c.getString(c.getColumnIndex(Sms.ADDRESS));
+
+ time = c.getLong(c.getColumnIndex(Sms.DATE));
+ if(type == 1) // Inbox message needs to set the vCard as originator
+ setVCardFromPhoneNumber(message, phone, true);
+ else // Other messages sets the vCard as the recipient
+ setVCardFromPhoneNumber(message, phone, false);
+
+ if(charset == MAP_MESSAGE_CHARSET_NATIVE) {
+ if(type == 1) //Inbox
+ message.setSmsBodyPdus(BluetoothMapSmsPdu.getDeliverPdus(msgBody, phone, time));
+ else
+ message.setSmsBodyPdus(BluetoothMapSmsPdu.getSubmitPdus(msgBody, phone));
+ } else /*if (charset == MAP_MESSAGE_CHARSET_UTF8)*/ {
+ message.setSmsBody(msgBody);
+ }
+
+ c.close();
+
+ return message.encode();
+ }
+ throw new IllegalArgumentException("SMS handle not found");
+ }
+
+ private void extractMmsAddresses(long id, BluetoothMapbMessageMmsEmail message) {
+ final String[] projection = null;
+ String selection = new String("msg_id=" + id);
+ String uriStr = String.format("content://mms/%d/addr", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(
+ uriAddress,
+ projection,
+ selection,
+ null, null);
+ /* TODO: Change the setVCard...() to return the vCard, and use the name in message.addXxx() */
+ if (c.moveToFirst()) {
+ do {
+ String address = c.getString(c.getColumnIndex("address"));
+ Integer type = c.getInt(c.getColumnIndex("type"));
+ switch(type) {
+ case MMS_FROM:
+ setVCardFromPhoneNumber(message, address, true);
+ message.addFrom(null, address);
+ break;
+ case MMS_TO:
+ setVCardFromPhoneNumber(message, address, false);
+ message.addTo(null, address);
+ break;
+ case MMS_CC:
+ setVCardFromPhoneNumber(message, address, false);
+ message.addCc(null, address);
+ break;
+ case MMS_BCC:
+ setVCardFromPhoneNumber(message, address, false);
+ message.addBcc(null, address);
+ default:
+ break;
+ }
+ } while(c.moveToNext());
+ }
+ }
+
+ /**
+ * Read out a mms data part and return the data in a byte array.
+ * @param partid the content provider id of the mms.
+ * @return
+ */
+ private byte[] readMmsDataPart(long partid) {
+ String uriStr = String.format("content://mms/part/%d", partid);
+ Uri uriAddress = Uri.parse(uriStr);
+ InputStream is = null;
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ int bufferSize = 8192;
+ byte[] buffer = new byte[bufferSize];
+ byte[] retVal = null;
+
+ try {
+ is = mResolver.openInputStream(uriAddress);
+ int len = 0;
+ while ((len = is.read(buffer)) != -1) {
+ os.write(buffer, 0, len); // We need to specify the len, as it can be != bufferSize
+ }
+ retVal = os.toByteArray();
+ } catch (IOException e) {
+ // do nothing for now
+ Log.w(TAG,"Error reading part data",e);
+ } finally {
+ try {
+ os.close();
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Read out the mms parts and update the bMessage object provided i {@linkplain message}
+ * @param id the content provider ID of the message
+ * @param message the bMessage object to add the information to
+ */
+ private void extractMmsParts(long id, BluetoothMapbMessageMmsEmail message)
+ {
+ /* TODO: If the attachment appParam is set to "no", only add the text parts.
+ * (content type contains "text" - case insensitive) */
+ final String[] projection = null;
+ String selection = new String("mid=" + id);
+ String uriStr = String.format("content://mms/%d/part", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ BluetoothMapbMessageMmsEmail.MimePart part;
+ Cursor c = mResolver.query(
+ uriAddress,
+ projection,
+ selection,
+ null, null);
+
+ if (c.moveToFirst()) {
+ do {
+ Long partId = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String contentType = c.getString(c.getColumnIndex("ct"));
+ String name = c.getString(c.getColumnIndex("name"));
+ String charset = c.getString(c.getColumnIndex("chset"));
+ String filename = c.getString(c.getColumnIndex("fn"));
+ String text = c.getString(c.getColumnIndex("text"));
+ Integer fd = c.getInt(c.getColumnIndex("_data"));
+ String cid = c.getString(c.getColumnIndex("cid"));
+ String cl = c.getString(c.getColumnIndex("cl"));
+ String cdisp = c.getString(c.getColumnIndex("cd"));
+
+ if(D) Log.d(TAG, " _id : " + partId +
+ "\n ct : " + contentType +
+ "\n partname : " + name +
+ "\n charset : " + charset +
+ "\n filename : " + filename +
+ "\n text : " + text +
+ "\n fd : " + fd +
+ "\n cid : " + cid +
+ "\n cl : " + cl +
+ "\n cdisp : " + cdisp);
+
+ part = message.addMimePart();
+ part.contentType = contentType;
+ part.partName = name;
+ part.contentId = cid;
+ part.contentLocation = cl;
+ part.contentDisposition = cdisp;
+
+ try {
+ if(text != null) {
+ part.data = text.getBytes("UTF-8");
+ part.charsetName = "utf-8";
+ }
+ else {
+ part.data = readMmsDataPart(partId);
+ if(charset != null)
+ part.charsetName = CharacterSets.getMimeName(Integer.parseInt(charset));
+ }
+ } catch (NumberFormatException e) {
+ Log.d(TAG,"extractMmsParts",e);
+ part.data = null;
+ part.charsetName = null;
+ } catch (UnsupportedEncodingException e) {
+ Log.d(TAG,"extractMmsParts",e);
+ part.data = null;
+ part.charsetName = null;
+ } finally {
+ }
+ part.fileName = filename;
+ } while(c.moveToNext());
+ }
+ message.updateCharset();
+ }
+
+ /**
+ *
+ * @param id the content provider id for the message to fetch.
+ * @param appParams The application parameter object received from the client.
+ * @return a byte[] containing the utf-8 encoded bMessage to send to the client.
+ * @throws UnsupportedEncodingException if UTF-8 is not supported,
+ * which is guaranteed to be supported on an android device
+ */
+ public byte[] getMmsMessage(long id, BluetoothMapAppParams appParams) throws UnsupportedEncodingException {
+ int msgBox, threadId;
+ BluetoothMapbMessageMmsEmail message = new BluetoothMapbMessageMmsEmail();
+ Cursor c = mResolver.query(Mms.CONTENT_URI, MMS_PROJECTION, "_ID = " + id, null, null);
+ if(c != null && c.moveToFirst())
+ {
+ message.setType(TYPE.MMS);
+
+ // The MMS info:
+ String read = c.getString(c.getColumnIndex(Mms.READ));
+ if (read.equalsIgnoreCase("1"))
+ message.setStatus(true);
+ else
+ message.setStatus(false);
+
+ msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
+ threadId = c.getInt(c.getColumnIndex(Mms.THREAD_ID));
+ message.setFolder(getFolderName(msgBox, threadId));
+
+ message.setSubject(c.getString(c.getColumnIndex(Mms.SUBJECT)));
+ message.setMessageId(c.getString(c.getColumnIndex(Mms.MESSAGE_ID)));
+ message.setContentType(c.getString(c.getColumnIndex(Mms.CONTENT_TYPE)));
+ message.setDate(c.getLong(c.getColumnIndex(Mms.DATE)) * 1000L);
+ message.setTextOnly(c.getInt(c.getColumnIndex(Mms.TEXT_ONLY)) == 0 ? false : true); // - TODO: Do we need this - yes, if we have only text, we should not make this a multipart message
+ message.setIncludeAttachments(appParams.getAttachment() == 0 ? false : true);
+ // c.getLong(c.getColumnIndex(Mms.DATE_SENT)); - this is never used
+ // c.getInt(c.getColumnIndex(Mms.STATUS)); - don't know what this is
+
+ // The parts
+ extractMmsParts(id, message);
+
+ // The addresses
+ extractMmsAddresses(id, message);
+
+ c.close();
+
+ return message.encode();
+ }
+ else if(c != null) {
+ c.close();
+ }
+
+ throw new IllegalArgumentException("MMS handle not found");
+ }
+
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
new file mode 100644
index 0000000..11ff0ff
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
@@ -0,0 +1,1196 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.BaseColumns;
+import android.provider.Telephony;
+import android.provider.Telephony.Mms;
+import android.provider.Telephony.MmsSms;
+import android.provider.Telephony.Sms;
+import android.provider.Telephony.Sms.Inbox;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+import com.android.bluetooth.map.BluetoothMapbMessageMmsEmail.MimePart;
+import com.google.android.mms.pdu.PduHeaders;
+
+public class BluetoothMapContentObserver {
+ private static final String TAG = "BluetoothMapContentObserver";
+
+ private static final boolean D = false;
+ private static final boolean V = false;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private BluetoothMnsObexClient mMnsClient;
+ private int mMasId;
+
+ public static final int DELETED_THREAD_ID = -1;
+
+ /* X-Mms-Message-Type field types. These are from PduHeaders.java */
+ public static final int MESSAGE_TYPE_RETRIEVE_CONF = 0x84;
+
+ private TYPE mSmsType;
+
+ static final String[] SMS_PROJECTION = new String[] {
+ BaseColumns._ID,
+ Sms.THREAD_ID,
+ Sms.ADDRESS,
+ Sms.BODY,
+ Sms.DATE,
+ Sms.READ,
+ Sms.TYPE,
+ Sms.STATUS,
+ Sms.LOCKED,
+ Sms.ERROR_CODE,
+ };
+
+ static final String[] MMS_PROJECTION = new String[] {
+ BaseColumns._ID,
+ Mms.THREAD_ID,
+ Mms.MESSAGE_ID,
+ Mms.MESSAGE_SIZE,
+ Mms.SUBJECT,
+ Mms.CONTENT_TYPE,
+ Mms.TEXT_ONLY,
+ Mms.DATE,
+ Mms.DATE_SENT,
+ Mms.READ,
+ Mms.MESSAGE_BOX,
+ Mms.MESSAGE_TYPE,
+ Mms.STATUS,
+ };
+
+ public BluetoothMapContentObserver(final Context context) {
+ mContext = context;
+ mResolver = mContext.getContentResolver();
+
+ mSmsType = getSmsType();
+ }
+
+ private TYPE getSmsType() {
+ TYPE smsType = null;
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+ if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ smsType = TYPE.SMS_GSM;
+ } else if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
+ smsType = TYPE.SMS_CDMA;
+ }
+
+ return smsType;
+ }
+
+ private final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ onChange(selfChange, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (V) Log.d(TAG, "onChange on thread: " + Thread.currentThread().getId()
+ + " Uri: " + uri.toString() + " selfchange: " + selfChange);
+
+ handleMsgListChanges();
+ }
+ };
+
+ private static final String folderSms[] = {
+ "",
+ "inbox",
+ "sent",
+ "draft",
+ "outbox",
+ "outbox",
+ "outbox",
+ "inbox",
+ "inbox",
+ };
+
+ private static final String folderMms[] = {
+ "",
+ "inbox",
+ "sent",
+ "draft",
+ "outbox",
+ };
+
+ private class Event {
+ String eventType;
+ long handle;
+ String folder;
+ String oldFolder;
+ TYPE msgType;
+
+ public Event(String eventType, long handle, String folder,
+ String oldFolder, TYPE msgType) {
+ String PATH = "telecom/msg/";
+ this.eventType = eventType;
+ this.handle = handle;
+ if (folder != null) {
+ this.folder = PATH + folder;
+ } else {
+ this.folder = null;
+ }
+ if (oldFolder != null) {
+ this.oldFolder = PATH + oldFolder;
+ } else {
+ this.oldFolder = null;
+ }
+ this.msgType = msgType;
+ }
+
+ public byte[] encode() throws UnsupportedEncodingException {
+ StringWriter sw = new StringWriter();
+ XmlSerializer xmlEvtReport = Xml.newSerializer();
+ try {
+ xmlEvtReport.setOutput(sw);
+ xmlEvtReport.startDocument(null, null);
+ xmlEvtReport.text("\n");
+ xmlEvtReport.startTag("", "MAP-event-report");
+ xmlEvtReport.attribute("", "version", "1.0");
+
+ xmlEvtReport.startTag("", "event");
+ xmlEvtReport.attribute("", "type", eventType);
+ xmlEvtReport.attribute("", "handle", BluetoothMapUtils.getMapHandle(handle, msgType));
+ if (folder != null) {
+ xmlEvtReport.attribute("", "folder", folder);
+ }
+ if (oldFolder != null) {
+ xmlEvtReport.attribute("", "old_folder", oldFolder);
+ }
+ xmlEvtReport.attribute("", "msg_type", msgType.name());
+ xmlEvtReport.endTag("", "event");
+
+ xmlEvtReport.endTag("", "MAP-event-report");
+ xmlEvtReport.endDocument();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (V) System.out.println(sw.toString());
+
+ return sw.toString().getBytes("UTF-8");
+ }
+ }
+
+ private class Msg {
+ long id;
+ int type;
+
+ public Msg(long id, int type) {
+ this.id = id;
+ this.type = type;
+ }
+ }
+
+ private Map<Long, Msg> mMsgListSms =
+ Collections.synchronizedMap(new HashMap<Long, Msg>());
+
+ private Map<Long, Msg> mMsgListMms =
+ Collections.synchronizedMap(new HashMap<Long, Msg>());
+
+ public void registerObserver(BluetoothMnsObexClient mns, int masId) {
+ if (V) Log.d(TAG, "registerObserver");
+ /* Use MmsSms Uri since the Sms Uri is not notified on deletes */
+ mMasId = masId;
+ mMnsClient = mns;
+ mResolver.registerContentObserver(MmsSms.CONTENT_URI, false, mObserver);
+ initMsgList();
+ }
+
+ public void unregisterObserver() {
+ if (V) Log.d(TAG, "unregisterObserver");
+ mResolver.unregisterContentObserver(mObserver);
+ mMnsClient = null;
+ }
+
+ private void sendEvent(Event evt) {
+ Log.d(TAG, "sendEvent: " + evt.eventType + " " + evt.handle + " "
+ + evt.folder + " " + evt.oldFolder + " " + evt.msgType.name());
+
+ if (mMnsClient == null) {
+ Log.d(TAG, "sendEvent: No MNS client registered - don't send event");
+ return;
+ }
+
+ try {
+ mMnsClient.sendEvent(evt.encode(), mMasId);
+ } catch (UnsupportedEncodingException ex) {
+ /* do nothing */
+ }
+ }
+
+ private void initMsgList() {
+ if (V) Log.d(TAG, "initMsgList");
+
+ mMsgListSms.clear();
+ mMsgListMms.clear();
+
+ HashMap<Long, Msg> msgListSms = new HashMap<Long, Msg>();
+
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, null, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ int type = c.getInt(c.getColumnIndex(Sms.TYPE));
+
+ Msg msg = new Msg(id, type);
+ msgListSms.put(id, msg);
+ } while (c.moveToNext());
+ c.close();
+ }
+
+ mMsgListSms = msgListSms;
+
+ HashMap<Long, Msg> msgListMms = new HashMap<Long, Msg>();
+
+ c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, null, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ int type = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
+
+ Msg msg = new Msg(id, type);
+ msgListMms.put(id, msg);
+ } while (c.moveToNext());
+ c.close();
+ }
+
+ mMsgListMms = msgListMms;
+ }
+
+ private void handleMsgListChangesSms() {
+ if (V) Log.d(TAG, "handleMsgListChangesSms");
+
+ HashMap<Long, Msg> msgListSms = new HashMap<Long, Msg>();
+
+ Cursor c = mResolver.query(Sms.CONTENT_URI,
+ SMS_PROJECTION, null, null, null);
+
+ synchronized(mMsgListSms) {
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ int type = c.getInt(c.getColumnIndex(Sms.TYPE));
+
+ Msg msg = mMsgListSms.remove(id);
+
+ if (msg == null) {
+ /* New message */
+ msg = new Msg(id, type);
+ msgListSms.put(id, msg);
+
+ if (folderSms[type].equals("inbox")) {
+ Event evt = new Event("NewMessage", id, folderSms[type],
+ null, mSmsType);
+ sendEvent(evt);
+ }
+ } else {
+ /* Existing message */
+ if (type != msg.type) {
+ Log.d(TAG, "new type: " + type + " old type: " + msg.type);
+ Event evt = new Event("MessageShift", id, folderSms[type],
+ folderSms[msg.type], mSmsType);
+ sendEvent(evt);
+ msg.type = type;
+ }
+ msgListSms.put(id, msg);
+ }
+ } while (c.moveToNext());
+ c.close();
+ }
+
+ for (Msg msg : mMsgListSms.values()) {
+ Event evt = new Event("MessageDeleted", msg.id, "deleted",
+ folderSms[msg.type], mSmsType);
+ sendEvent(evt);
+ }
+
+ mMsgListSms = msgListSms;
+ }
+ }
+
+ private void handleMsgListChangesMms() {
+ if (V) Log.d(TAG, "handleMsgListChangesMms");
+
+ HashMap<Long, Msg> msgListMms = new HashMap<Long, Msg>();
+
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ MMS_PROJECTION, null, null, null);
+
+ synchronized(mMsgListMms) {
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ int type = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
+ int mtype = c.getInt(c.getColumnIndex(Mms.MESSAGE_TYPE));
+
+ Msg msg = mMsgListMms.remove(id);
+
+ if (msg == null) {
+ /* New message - only notify on retrieve conf */
+ if (folderMms[type].equals("inbox") &&
+ mtype != MESSAGE_TYPE_RETRIEVE_CONF) {
+ continue;
+ }
+
+ msg = new Msg(id, type);
+ msgListMms.put(id, msg);
+
+ if (folderMms[type].equals("inbox")) {
+ Event evt = new Event("NewMessage", id, folderMms[type],
+ null, TYPE.MMS);
+ sendEvent(evt);
+ }
+ } else {
+ /* Existing message */
+ if (type != msg.type) {
+ Log.d(TAG, "new type: " + type + " old type: " + msg.type);
+ Event evt = new Event("MessageShift", id, folderMms[type],
+ folderMms[msg.type], TYPE.MMS);
+ sendEvent(evt);
+ msg.type = type;
+
+ if (folderMms[type].equals("sent")) {
+ evt = new Event("SendingSuccess", id,
+ folderSms[type], null, TYPE.MMS);
+ sendEvent(evt);
+ }
+ }
+ msgListMms.put(id, msg);
+ }
+ } while (c.moveToNext());
+ c.close();
+ }
+
+ for (Msg msg : mMsgListMms.values()) {
+ Event evt = new Event("MessageDeleted", msg.id, "deleted",
+ folderMms[msg.type], TYPE.MMS);
+ sendEvent(evt);
+ }
+
+ mMsgListMms = msgListMms;
+ }
+ }
+
+ private void handleMsgListChanges() {
+ handleMsgListChangesSms();
+ handleMsgListChangesMms();
+ }
+
+ private boolean deleteMessageMms(long handle) {
+ boolean res = false;
+ Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+ if (c != null && c.moveToFirst()) {
+ /* Move to deleted folder, or delete if already in deleted folder */
+ int threadId = c.getInt(c.getColumnIndex(Mms.THREAD_ID));
+ if (threadId != DELETED_THREAD_ID) {
+ /* Set deleted thread id */
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Mms.THREAD_ID, DELETED_THREAD_ID);
+ mResolver.update(uri, contentValues, null, null);
+ } else {
+ /* Delete from observer message list to avoid delete notifications */
+ mMsgListMms.remove(handle);
+ /* Delete message */
+ mResolver.delete(uri, null, null);
+ }
+ res = true;
+ }
+ if (c != null) {
+ c.close();
+ }
+ return res;
+ }
+
+ private void updateThreadIdMms(Uri uri, long threadId) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Mms.THREAD_ID, threadId);
+ mResolver.update(uri, contentValues, null, null);
+ }
+
+ private boolean unDeleteMessageMms(long handle) {
+ boolean res = false;
+ Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ int threadId = c.getInt(c.getColumnIndex(Mms.THREAD_ID));
+ if (threadId == DELETED_THREAD_ID) {
+ /* Restore thread id from address, or if no thread for address
+ * create new thread by insert and remove of fake message */
+ String address;
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ int msgBox = c.getInt(c.getColumnIndex(Mms.MESSAGE_BOX));
+ if (msgBox == Mms.MESSAGE_BOX_INBOX) {
+ address = BluetoothMapContent.getAddressMms(mResolver, id,
+ BluetoothMapContent.MMS_FROM);
+ } else {
+ address = BluetoothMapContent.getAddressMms(mResolver, id,
+ BluetoothMapContent.MMS_TO);
+ }
+ Set<String> recipients = new HashSet<String>();
+ recipients.addAll(Arrays.asList(address));
+ updateThreadIdMms(uri, Telephony.Threads.getOrCreateThreadId(mContext, recipients));
+ } else {
+ Log.d(TAG, "Message not in deleted folder: handle " + handle
+ + " threadId " + threadId);
+ }
+ res = true;
+ }
+ if (c != null) {
+ c.close();
+ }
+ return res;
+ }
+
+ private boolean deleteMessageSms(long handle) {
+ boolean res = false;
+ Uri uri = ContentUris.withAppendedId(Sms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ /* Move to deleted folder, or delete if already in deleted folder */
+ int threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID));
+ if (threadId != DELETED_THREAD_ID) {
+ /* Set deleted thread id */
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Sms.THREAD_ID, DELETED_THREAD_ID);
+ mResolver.update(uri, contentValues, null, null);
+ } else {
+ /* Delete from observer message list to avoid delete notifications */
+ mMsgListSms.remove(handle);
+ /* Delete message */
+ mResolver.delete(uri, null, null);
+ }
+ res = true;
+ }
+ if (c != null) {
+ c.close();
+ }
+ return res;
+ }
+
+ private void updateThreadIdSms(Uri uri, long threadId) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Sms.THREAD_ID, threadId);
+ mResolver.update(uri, contentValues, null, null);
+ }
+
+ private boolean unDeleteMessageSms(long handle) {
+ boolean res = false;
+ Uri uri = ContentUris.withAppendedId(Sms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+
+ if (c != null && c.moveToFirst()) {
+ int threadId = c.getInt(c.getColumnIndex(Sms.THREAD_ID));
+ if (threadId == DELETED_THREAD_ID) {
+ String address = c.getString(c.getColumnIndex(Sms.ADDRESS));
+ Set<String> recipients = new HashSet<String>();
+ recipients.addAll(Arrays.asList(address));
+ updateThreadIdSms(uri, Telephony.Threads.getOrCreateThreadId(mContext, recipients));
+ } else {
+ Log.d(TAG, "Message not in deleted folder: handle " + handle
+ + " threadId " + threadId);
+ }
+ res = true;
+ }
+ if (c != null) {
+ c.close();
+ }
+ return res;
+ }
+
+ public boolean setMessageStatusDeleted(long handle, TYPE type, int statusValue) {
+ boolean res = false;
+ if (D) Log.d(TAG, "setMessageStatusDeleted: handle " + handle
+ + " type " + type + " value " + statusValue);
+
+ if (statusValue == BluetoothMapAppParams.STATUS_VALUE_YES) {
+ if (type == TYPE.SMS_GSM || type == TYPE.SMS_CDMA) {
+ res = deleteMessageSms(handle);
+ } else if (type == TYPE.MMS) {
+ res = deleteMessageMms(handle);
+ }
+ } else if (statusValue == BluetoothMapAppParams.STATUS_VALUE_NO) {
+ if (type == TYPE.SMS_GSM || type == TYPE.SMS_CDMA) {
+ res = unDeleteMessageSms(handle);
+ } else if (type == TYPE.MMS) {
+ res = unDeleteMessageMms(handle);
+ }
+ }
+ return res;
+ }
+
+ public boolean setMessageStatusRead(long handle, TYPE type, int statusValue) {
+ boolean res = true;
+
+ if (D) Log.d(TAG, "setMessageStatusRead: handle " + handle
+ + " type " + type + " value " + statusValue);
+
+ /* Approved MAP spec errata 3445 states that read status initiated */
+ /* by the MCE shall change the MSE read status. */
+
+ if (type == TYPE.SMS_GSM || type == TYPE.SMS_CDMA) {
+ Uri uri = ContentUris.withAppendedId(Sms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Sms.READ, statusValue);
+ mResolver.update(uri, contentValues, null, null);
+ } else if (type == TYPE.MMS) {
+ Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, handle);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Mms.READ, statusValue);
+ mResolver.update(uri, contentValues, null, null);
+ }
+
+ return res;
+ }
+
+ private class PushMsgInfo {
+ long id;
+ int transparent;
+ int retry;
+ String phone;
+ Uri uri;
+ int parts;
+ int partsSent;
+ int partsDelivered;
+ boolean resend;
+
+ public PushMsgInfo(long id, int transparent,
+ int retry, String phone, Uri uri) {
+ this.id = id;
+ this.transparent = transparent;
+ this.retry = retry;
+ this.phone = phone;
+ this.uri = uri;
+ this.resend = false;
+ };
+ }
+
+ private Map<Long, PushMsgInfo> mPushMsgList =
+ Collections.synchronizedMap(new HashMap<Long, PushMsgInfo>());
+
+ public long pushMessage(BluetoothMapbMessage msg, String folder,
+ BluetoothMapAppParams ap) throws IllegalArgumentException {
+ if (D) Log.d(TAG, "pushMessage");
+ ArrayList<BluetoothMapbMessage.vCard> recipientList = msg.getRecipients();
+ int transparent = (ap.getTransparent() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) ?
+ 0 : ap.getTransparent();
+ int retry = ap.getRetry();
+ int charset = ap.getCharset();
+ long handle = -1;
+
+ if (recipientList == null) {
+ Log.d(TAG, "empty recipient list");
+ return -1;
+ }
+
+ for (BluetoothMapbMessage.vCard recipient : recipientList) {
+ if(recipient.getEnvLevel() == 0) // Only send the message to the top level recipient
+ {
+ /* Only send to first address */
+ String phone = recipient.getFirstPhoneNumber();
+ boolean read = false;
+ boolean deliveryReport = true;
+
+ switch(msg.getType()){
+ case MMS:
+ {
+ /* Send message if folder is outbox */
+ /* to do, support MMS in the future */
+ /*
+ if (folder.equals("outbox")) {
+ handle = sendMmsMessage(folder, phone, (BluetoothMapbMessageMmsEmail)msg);
+ }
+ */
+ break;
+ }
+ case SMS_GSM: //fall-through
+ case SMS_CDMA:
+ {
+ /* Add the message to the database */
+ String msgBody = ((BluetoothMapbMessageSms) msg).getSmsBody();
+ Uri contentUri = Uri.parse("content://sms/" + folder);
+ Uri uri = Sms.addMessageToUri(mResolver, contentUri, phone, msgBody,
+ "", System.currentTimeMillis(), read, deliveryReport);
+
+ if (uri == null) {
+ Log.d(TAG, "pushMessage - failure on add to uri " + contentUri);
+ return -1;
+ }
+
+ handle = Long.parseLong(uri.getLastPathSegment());
+
+ /* Send message if folder is outbox */
+ if (folder.equals("outbox")) {
+ PushMsgInfo msgInfo = new PushMsgInfo(handle, transparent,
+ retry, phone, uri);
+ mPushMsgList.put(handle, msgInfo);
+ sendMessage(msgInfo, msgBody);
+ }
+ break;
+ }
+ case EMAIL:
+ {
+ break;
+ }
+ }
+
+ }
+ }
+
+ /* If multiple recipients return handle of last */
+ return handle;
+ }
+
+
+
+ public long sendMmsMessage(String folder,String to_address, BluetoothMapbMessageMmsEmail msg) {
+ /*
+ *strategy:
+ *1) parse message into parts
+ *if folder is outbox/drafts:
+ *2) push message to draft
+ *if folder is outbox:
+ *3) move message to outbox (to trigger the mms app to add msg to pending_messages list)
+ *4) send intent to mms app in order to wake it up.
+ *else if folder !outbox:
+ *1) push message to folder
+ * */
+ if (folder != null && (folder.equalsIgnoreCase("outbox")|| folder.equalsIgnoreCase("drafts"))) {
+ long handle = pushMmsToFolder(Mms.MESSAGE_BOX_DRAFTS, to_address, msg);
+ /* if invalid handle (-1) then just return the handle - else continue sending (if folder is outbox) */
+ if (BluetoothMapAppParams.INVALID_VALUE_PARAMETER != handle && folder.equalsIgnoreCase("outbox")) {
+ moveDraftToOutbox(handle);
+
+ Intent sendIntent = new Intent("android.intent.action.MMS_SEND_OUTBOX_MSG");
+ Log.d(TAG, "broadcasting intent: "+sendIntent.toString());
+ mContext.sendBroadcast(sendIntent);
+ }
+ return handle;
+ } else {
+ /* not allowed to push mms to anything but outbox/drafts */
+ throw new IllegalArgumentException("Cannot push message to other folders than outbox/drafts");
+ }
+
+ }
+
+
+ private void moveDraftToOutbox(long handle) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ /*Move message by changing the msg_box value in the content provider database */
+ if (handle != -1) {
+ String whereClause = " _id= " + handle;
+ Uri uri = Uri.parse("content://mms");
+ Cursor queryResult = contentResolver.query(uri, null, whereClause, null, null);
+ if (queryResult != null) {
+ if (queryResult.getCount() > 0) {
+ queryResult.moveToFirst();
+ ContentValues data = new ContentValues();
+ /* set folder to be outbox */
+ data.put("msg_box", Mms.MESSAGE_BOX_OUTBOX);
+ contentResolver.update(uri, data, whereClause, null);
+ Log.d(TAG, "moved draft MMS to outbox");
+ }
+ queryResult.close();
+ }else {
+ Log.d(TAG, "Could not move draft to outbox ");
+ }
+ }
+ }
+ private long pushMmsToFolder(int folder, String to_address, BluetoothMapbMessageMmsEmail msg) {
+ /**
+ * strategy:
+ * 1) parse msg into parts + header
+ * 2) create thread id (abuse the ease of adding an SMS to get id for thread)
+ * 3) push parts into content://mms/parts/ table
+ * 3)
+ */
+
+ ContentValues values = new ContentValues();
+ values.put("msg_box", folder);
+
+ values.put("read", 0);
+ values.put("seen", 0);
+ values.put("sub", msg.getSubject());
+ values.put("sub_cs", 106);
+ values.put("ct_t", "application/vnd.wap.multipart.related");
+ values.put("exp", 604800);
+ values.put("m_cls", PduHeaders.MESSAGE_CLASS_PERSONAL_STR);
+ values.put("m_type", PduHeaders.MESSAGE_TYPE_SEND_REQ);
+ values.put("v", PduHeaders.CURRENT_MMS_VERSION);
+ values.put("pri", PduHeaders.PRIORITY_NORMAL);
+ values.put("rr", PduHeaders.VALUE_NO);
+ values.put("tr_id", "T"+ Long.toHexString(System.currentTimeMillis()));
+ values.put("d_rpt", PduHeaders.VALUE_NO);
+ values.put("locked", 0);
+ if(msg.getTextOnly() == true)
+ values.put("text_only", true);
+
+ values.put("m_size", msg.getSize());
+
+ // Get thread id
+ Set<String> recipients = new HashSet<String>();
+ recipients.addAll(Arrays.asList(to_address));
+ values.put("thread_id", Telephony.Threads.getOrCreateThreadId(mContext, recipients));
+ Uri uri = Uri.parse("content://mms");
+
+ ContentResolver cr = mContext.getContentResolver();
+ uri = cr.insert(uri, values);
+
+ if (uri == null) {
+ // unable to insert MMS
+ Log.e(TAG, "Unabled to insert MMS " + values + "Uri: " + uri);
+ return -1;
+ }
+
+ long handle = Long.parseLong(uri.getLastPathSegment());
+ if (V){
+ Log.v(TAG, " NEW URI " + uri.toString());
+ }
+ try {
+ if(V) Log.v(TAG, "Adding " + msg.getMimeParts().size() + " parts to the data base.");
+ for(MimePart part : msg.getMimeParts()) {
+ int count = 0;
+ count++;
+ values.clear();
+ if(part.contentType != null && part.contentType.toUpperCase().contains("TEXT")) {
+ values.put("ct", "text/plain");
+ values.put("chset", 106);
+ if(part.partName != null) {
+ values.put("fn", part.partName);
+ values.put("name", part.partName);
+ } else if(part.contentId == null && part.contentLocation == null) {
+ /* We must set at least one part identifier */
+ values.put("fn", "text_" + count +".txt");
+ values.put("name", "text_" + count +".txt");
+ }
+ if(part.contentId != null) {
+ values.put("cid", part.contentId);
+ }
+ if(part.contentLocation != null)
+ values.put("cl", part.contentLocation);
+ if(part.contentDisposition != null)
+ values.put("cd", part.contentDisposition);
+ values.put("text", new String(part.data, "UTF-8"));
+ uri = Uri.parse("content://mms/" + handle + "/part");
+ uri = cr.insert(uri, values);
+ if(V) Log.v(TAG, "Added TEXT part");
+
+ } else if (part.contentType != null && part.contentType.toUpperCase().contains("SMIL")){
+
+ values.put("seq", -1);
+ values.put("ct", "application/smil");
+ if(part.contentId != null)
+ values.put("cid", part.contentId);
+ if(part.contentLocation != null)
+ values.put("cl", part.contentLocation);
+ if(part.contentDisposition != null)
+ values.put("cd", part.contentDisposition);
+ values.put("fn", "smil.xml");
+ values.put("name", "smil.xml");
+ values.put("text", new String(part.data, "UTF-8"));
+
+ uri = Uri.parse("content://mms/" + handle + "/part");
+ uri = cr.insert(uri, values);
+ if(V) Log.v(TAG, "Added SMIL part");
+
+ }else /*VIDEO/AUDIO/IMAGE*/ {
+ writeMmsDataPart(handle, part, count);
+ if(V) Log.v(TAG, "Added OTHER part");
+ }
+ if (uri != null && V){
+ Log.v(TAG, "Added part with content-type: "+ part.contentType + " to Uri: " + uri.toString());
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, e);
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ }
+
+ values.clear();
+ values.put("contact_id", "null");
+ values.put("address", "insert-address-token");
+ values.put("type", BluetoothMapContent.MMS_FROM);
+ values.put("charset", 106);
+
+ uri = Uri.parse("content://mms/" + handle + "/addr");
+ uri = cr.insert(uri, values);
+ if (uri != null && V){
+ Log.v(TAG, " NEW URI " + uri.toString());
+ }
+
+ values.clear();
+ values.put("contact_id", "null");
+ values.put("address", to_address);
+ values.put("type", BluetoothMapContent.MMS_TO);
+ values.put("charset", 106);
+
+ uri = Uri.parse("content://mms/" + handle + "/addr");
+ uri = cr.insert(uri, values);
+ if (uri != null && V){
+ Log.v(TAG, " NEW URI " + uri.toString());
+ }
+ return handle;
+ }
+
+
+ private void writeMmsDataPart(long handle, MimePart part, int count) throws IOException{
+ ContentValues values = new ContentValues();
+ values.put("mid", handle);
+ if(part.contentType != null)
+ values.put("ct", part.contentType);
+ if(part.contentId != null)
+ values.put("cid", part.contentId);
+ if(part.contentLocation != null)
+ values.put("cl", part.contentLocation);
+ if(part.contentDisposition != null)
+ values.put("cd", part.contentDisposition);
+ if(part.partName != null) {
+ values.put("fn", part.partName);
+ values.put("name", part.partName);
+ } else if(part.contentId == null && part.contentLocation == null) {
+ /* We must set at least one part identifier */
+ values.put("fn", "part_" + count + ".dat");
+ values.put("name", "part_" + count + ".dat");
+ }
+ Uri partUri = Uri.parse("content://mms/" + handle + "/part");
+ Uri res = mResolver.insert(partUri, values);
+
+ // Add data to part
+ OutputStream os = mResolver.openOutputStream(res);
+ os.write(part.data);
+ os.close();
+ }
+
+
+ public void sendMessage(PushMsgInfo msgInfo, String msgBody) {
+
+ SmsManager smsMng = SmsManager.getDefault();
+ ArrayList<String> parts = smsMng.divideMessage(msgBody);
+ msgInfo.parts = parts.size();
+
+ ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(msgInfo.parts);
+ ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(msgInfo.parts);
+
+ for (int i = 0; i < msgInfo.parts; i++) {
+ Intent intent;
+ intent = new Intent(ACTION_MESSAGE_DELIVERY, null);
+ intent.putExtra("HANDLE", msgInfo.id);
+ deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT));
+
+ intent = new Intent(ACTION_MESSAGE_SENT, null);
+ intent.putExtra("HANDLE", msgInfo.id);
+ sentIntents.add(PendingIntent.getBroadcast(mContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+
+ Log.d(TAG, "sendMessage to " + msgInfo.phone);
+
+ smsMng.sendMultipartTextMessage(msgInfo.phone, null, parts, sentIntents,
+ deliveryIntents);
+ }
+
+ private static final String ACTION_MESSAGE_DELIVERY =
+ "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY";
+ private static final String ACTION_MESSAGE_SENT =
+ "com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT";
+
+ private SmsBroadcastReceiver mSmsBroadcastReceiver = new SmsBroadcastReceiver();
+
+ private class SmsBroadcastReceiver extends BroadcastReceiver {
+ private final String[] ID_PROJECTION = new String[] { Sms._ID };
+ private final Uri UPDATE_STATUS_URI = Uri.parse("content://sms/status");
+
+ public void register() {
+ Handler handler = new Handler();
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_MESSAGE_DELIVERY);
+ intentFilter.addAction(ACTION_MESSAGE_SENT);
+ mContext.registerReceiver(this, intentFilter, null, handler);
+ }
+
+ public void unregister() {
+ try {
+ mContext.unregisterReceiver(this);
+ } catch (IllegalArgumentException e) {
+ /* do nothing */
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ long handle = intent.getLongExtra("HANDLE", -1);
+ PushMsgInfo msgInfo = mPushMsgList.get(handle);
+
+ Log.d(TAG, "onReceive: action" + action);
+
+ if (msgInfo == null) {
+ Log.d(TAG, "onReceive: no msgInfo found for handle " + handle);
+ return;
+ }
+
+ if (action.equals(ACTION_MESSAGE_SENT)) {
+ msgInfo.partsSent++;
+ if (msgInfo.partsSent == msgInfo.parts) {
+ actionMessageSent(context, intent, msgInfo);
+ }
+ } else if (action.equals(ACTION_MESSAGE_DELIVERY)) {
+ msgInfo.partsDelivered++;
+ if (msgInfo.partsDelivered == msgInfo.parts) {
+ actionMessageDelivery(context, intent, msgInfo);
+ }
+ } else {
+ Log.d(TAG, "onReceive: Unknown action " + action);
+ }
+ }
+
+ private void actionMessageSent(Context context, Intent intent,
+ PushMsgInfo msgInfo) {
+ int result = getResultCode();
+ boolean delete = false;
+
+ if (result == Activity.RESULT_OK) {
+ Log.d(TAG, "actionMessageSent: result OK");
+ if (msgInfo.transparent == 0) {
+ if (!Sms.moveMessageToFolder(context, msgInfo.uri,
+ Sms.MESSAGE_TYPE_SENT, 0)) {
+ Log.d(TAG, "Failed to move " + msgInfo.uri + " to SENT");
+ }
+ } else {
+ delete = true;
+ }
+
+ Event evt = new Event("SendingSuccess", msgInfo.id,
+ folderSms[Sms.MESSAGE_TYPE_SENT], null, mSmsType);
+ sendEvent(evt);
+
+ } else {
+ if (msgInfo.retry == 1) {
+ /* Notify failure, but keep message in outbox for resending */
+ msgInfo.resend = true;
+ Event evt = new Event("SendingFailure", msgInfo.id,
+ folderSms[Sms.MESSAGE_TYPE_OUTBOX], null, mSmsType);
+ sendEvent(evt);
+ } else {
+ if (msgInfo.transparent == 0) {
+ if (!Sms.moveMessageToFolder(context, msgInfo.uri,
+ Sms.MESSAGE_TYPE_FAILED, 0)) {
+ Log.d(TAG, "Failed to move " + msgInfo.uri + " to FAILED");
+ }
+ } else {
+ delete = true;
+ }
+
+ Event evt = new Event("SendingFailure", msgInfo.id,
+ folderSms[Sms.MESSAGE_TYPE_FAILED], null, mSmsType);
+ sendEvent(evt);
+ }
+ }
+
+ if (delete == true) {
+ /* Delete from Observer message list to avoid delete notifications */
+ mMsgListSms.remove(msgInfo.id);
+
+ /* Delete from DB */
+ mResolver.delete(msgInfo.uri, null, null);
+ }
+ }
+
+ private void actionMessageDelivery(Context context, Intent intent,
+ PushMsgInfo msgInfo) {
+ Uri messageUri = intent.getData();
+ byte[] pdu = intent.getByteArrayExtra("pdu");
+ String format = intent.getStringExtra("format");
+
+ SmsMessage message = SmsMessage.createFromPdu(pdu, format);
+ if (message == null) {
+ Log.d(TAG, "actionMessageDelivery: Can't get message from pdu");
+ return;
+ }
+ int status = message.getStatus();
+
+ Cursor cursor = mResolver.query(msgInfo.uri, ID_PROJECTION, null, null, null);
+
+ try {
+ if (cursor.moveToFirst()) {
+ int messageId = cursor.getInt(0);
+
+ Uri updateUri = ContentUris.withAppendedId(UPDATE_STATUS_URI, messageId);
+ boolean isStatusReport = message.isStatusReportMessage();
+
+ Log.d(TAG, "actionMessageDelivery: uri=" + messageUri + ", status=" + status +
+ ", isStatusReport=" + isStatusReport);
+
+ ContentValues contentValues = new ContentValues(2);
+
+ contentValues.put(Sms.STATUS, status);
+ contentValues.put(Inbox.DATE_SENT, System.currentTimeMillis());
+ mResolver.update(updateUri, contentValues, null, null);
+ } else {
+ Log.d(TAG, "Can't find message for status update: " + messageUri);
+ }
+ } finally {
+ cursor.close();
+ }
+
+ if (status == 0) {
+ Event evt = new Event("DeliverySuccess", msgInfo.id,
+ folderSms[Sms.MESSAGE_TYPE_SENT], null, mSmsType);
+ sendEvent(evt);
+ } else {
+ Event evt = new Event("DeliveryFailure", msgInfo.id,
+ folderSms[Sms.MESSAGE_TYPE_SENT], null, mSmsType);
+ sendEvent(evt);
+ }
+
+ mPushMsgList.remove(msgInfo.id);
+ }
+ }
+
+ private void registerPhoneServiceStateListener() {
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ tm.listen(mPhoneListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ }
+
+ private void unRegisterPhoneServiceStateListener() {
+ TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ tm.listen(mPhoneListener, PhoneStateListener.LISTEN_NONE);
+ }
+
+ private void resendPendingMessages() {
+ /* Send pending messages in outbox */
+ String where = "type = " + Sms.MESSAGE_TYPE_OUTBOX;
+ Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null,
+ null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String msgBody = c.getString(c.getColumnIndex(Sms.BODY));
+ PushMsgInfo msgInfo = mPushMsgList.get(id);
+ if (msgInfo == null || msgInfo.resend == false) {
+ continue;
+ }
+ sendMessage(msgInfo, msgBody);
+ } while (c.moveToNext());
+ c.close();
+ }
+ }
+
+ private void failPendingMessages() {
+ /* Move pending messages from outbox to failed */
+ String where = "type = " + Sms.MESSAGE_TYPE_OUTBOX;
+ Cursor c = mResolver.query(Sms.CONTENT_URI, SMS_PROJECTION, where, null,
+ null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ String msgBody = c.getString(c.getColumnIndex(Sms.BODY));
+ PushMsgInfo msgInfo = mPushMsgList.get(id);
+ if (msgInfo == null || msgInfo.resend == false) {
+ continue;
+ }
+ Sms.moveMessageToFolder(mContext, msgInfo.uri,
+ Sms.MESSAGE_TYPE_FAILED, 0);
+ } while (c.moveToNext());
+ }
+ if (c != null) c.close();
+ }
+
+ private void removeDeletedMessages() {
+ /* Remove messages from virtual "deleted" folder (thread_id -1) */
+ mResolver.delete(Uri.parse("content://sms/"),
+ "thread_id = " + DELETED_THREAD_ID, null);
+ }
+
+ private PhoneStateListener mPhoneListener = new PhoneStateListener() {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ Log.d(TAG, "Phone service state change: " + serviceState.getState());
+ if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
+ resendPendingMessages();
+ }
+ }
+ };
+
+ public void init() {
+ mSmsBroadcastReceiver.register();
+ registerPhoneServiceStateListener();
+ }
+
+ public void deinit() {
+ mSmsBroadcastReceiver.unregister();
+ unRegisterPhoneServiceStateListener();
+ failPendingMessages();
+ removeDeletedMessages();
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapFolderElement.java b/src/com/android/bluetooth/map/BluetoothMapFolderElement.java
new file mode 100644
index 0000000..d3909dd
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapFolderElement.java
@@ -0,0 +1,133 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Xml;
+
+/**
+ * @author cbonde
+ *
+ */
+public class BluetoothMapFolderElement {
+ private String name;
+ private BluetoothMapFolderElement parent = null;
+ private ArrayList<BluetoothMapFolderElement> subFolders;
+
+ public BluetoothMapFolderElement( String name, BluetoothMapFolderElement parrent ){
+ this.name = name;
+ this.parent = parrent;
+ subFolders = new ArrayList<BluetoothMapFolderElement>();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Fetch the parent folder.
+ * @return the parent folder or null if we are at the root folder.
+ */
+ public BluetoothMapFolderElement getParent() {
+ return parent;
+ }
+
+ /**
+ * Fetch the root folder.
+ * @return the parent folder or null if we are at the root folder.
+ */
+ public BluetoothMapFolderElement getRoot() {
+ BluetoothMapFolderElement rootFolder = this;
+ while(rootFolder.getParent() != null)
+ rootFolder = rootFolder.getParent();
+ return rootFolder;
+ }
+
+ /**
+ * Add a folder.
+ * @param name the name of the folder to add.
+ * @return the added folder element.
+ */
+ public BluetoothMapFolderElement addFolder(String name){
+ BluetoothMapFolderElement newFolder = new BluetoothMapFolderElement(name, this);
+ subFolders.add(newFolder);
+ return newFolder;
+ }
+
+ /**
+ * Fetch the number of sub folders.
+ * @return returns the number of sub folders.
+ */
+ public int getSubFolderCount(){
+ return subFolders.size();
+ }
+
+ /**
+ * Returns the subFolder element matching the supplied folder name.
+ * @param folderName the name of the subFolder to find.
+ * @return the subFolder element if found {@code null} otherwise.
+ */
+ public BluetoothMapFolderElement getSubFolder(String folderName){
+ for(BluetoothMapFolderElement subFolder : subFolders){
+ if(subFolder.getName().equals(folderName))
+ return subFolder;
+ }
+ return null;
+ }
+
+ public byte[] encode(int offset, int count) throws UnsupportedEncodingException {
+ StringWriter sw = new StringWriter();
+ XmlSerializer xmlMsgElement = Xml.newSerializer();
+ int i, stopIndex;
+ if(offset > subFolders.size())
+ throw new IllegalArgumentException("FolderListingEncode: offset > subFolders.size()");
+
+ stopIndex = offset + count;
+ if(stopIndex > subFolders.size())
+ stopIndex = subFolders.size();
+
+ try {
+ xmlMsgElement.setOutput(sw);
+ xmlMsgElement.startDocument(null, null);
+ xmlMsgElement.text("\n");
+ xmlMsgElement.startTag("", "folder-listing");
+ xmlMsgElement.attribute("", "version", "1.0");
+ for(i = offset; i<stopIndex; i++)
+ {
+ xmlMsgElement.startTag("", "folder");
+ xmlMsgElement.attribute("", "name", subFolders.get(i).getName());
+ xmlMsgElement.endTag("", "folder");
+ }
+ xmlMsgElement.endTag("", "folder-listing");
+ xmlMsgElement.endDocument();
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return sw.toString().getBytes("UTF-8");
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapMessageListing.java b/src/com/android/bluetooth/map/BluetoothMapMessageListing.java
new file mode 100644
index 0000000..ffa0568
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapMessageListing.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import android.util.Log;
+import android.util.Xml;
+
+public class BluetoothMapMessageListing {
+ private boolean hasUnread = false;
+ private static final String TAG = "BluetoothMapMessageListing";
+ private List<BluetoothMapMessageListingElement> list;
+
+ public BluetoothMapMessageListing(){
+ list = new ArrayList<BluetoothMapMessageListingElement>();
+ }
+ public void add(BluetoothMapMessageListingElement element) {
+ list.add(element);
+ /* update info regarding whether the list contains unread messages */
+ if (element.getRead().equalsIgnoreCase("no"))
+ {
+ hasUnread = true;
+ }
+ }
+
+ /**
+ * Used to fetch the number of BluetoothMapMessageListingElement elements in the list.
+ * @return the number of elements in the list.
+ */
+ public int getCount() {
+ if(list != null)
+ {
+ return list.size();
+ }
+ return 0;
+ }
+
+ /**
+ * does the list contain any unread messages
+ * @return true if unread messages have been added to the list, else false
+ */
+ public boolean hasUnread()
+ {
+ return hasUnread;
+ }
+
+ /**
+ * Encode the list of BluetoothMapMessageListingElement(s) into a UTF-8
+ * formatted XML-string in a trimmed byte array
+ *
+ * @return a reference to the encoded byte array.
+ * @throws UnsupportedEncodingException
+ * if UTF-8 encoding is unsupported on the platform.
+ */
+ public byte[] encode() throws UnsupportedEncodingException {
+ StringWriter sw = new StringWriter();
+ XmlSerializer xmlMsgElement = Xml.newSerializer();
+ try {
+ xmlMsgElement.setOutput(sw);
+ xmlMsgElement.startDocument(null, null);
+ xmlMsgElement.startTag("", "MAP-msg-listing");
+ xmlMsgElement.attribute("", "version", "1.0");
+ // Do the XML encoding of list
+ for (BluetoothMapMessageListingElement element : list) {
+ element.encode(xmlMsgElement); // Append the list element
+ }
+ xmlMsgElement.endTag("", "MAP-msg-listing");
+ xmlMsgElement.endDocument();
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, e.toString());
+ } catch (IllegalStateException e) {
+ Log.w(TAG, e.toString());
+ } catch (IOException e) {
+ Log.w(TAG, e.toString());
+ }
+ return sw.toString().getBytes("UTF-8");
+ }
+
+ public void sort() {
+ Collections.sort(list);
+ }
+
+ public void segment(int count, int offset) {
+ count = Math.min(count, list.size());
+ if (offset + count <= list.size()) {
+ list = list.subList(offset, offset + count);
+ } else {
+ list = null;
+ }
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java b/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java
new file mode 100644
index 0000000..9f70759
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapMessageListingElement.java
@@ -0,0 +1,262 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+
+public class BluetoothMapMessageListingElement
+ implements Comparable<BluetoothMapMessageListingElement> {
+
+ private static final String TAG = "BluetoothMapMessageListingElement";
+ private static final boolean D = false;
+ private static final boolean V = false;
+
+ private long cpHandle = 0; /* The content provider handle - without type information */
+ private String mapHandle = null; /* The map hex-string handle with type information */
+ private String subject = null;
+ private long dateTime = 0;
+ private String senderName = null;
+ private String senderAddressing = null;
+ private String replytoAddressing = null;
+ private String recipientName = null;
+ private String recipientAddressing = null;
+ private TYPE type = null;
+ private int size = -1;
+ private String text = null;
+ private String receptionStatus = null;
+ private int attachmentSize = -1;
+ private String priority = null;
+ private String read = null;
+ private String sent = null;
+ private String protect = null;
+ private boolean reportRead;
+ public long getHandle() {
+ return cpHandle;
+ }
+
+ public void setHandle(long handle, TYPE type) {
+ this.cpHandle = handle;
+ this.mapHandle = BluetoothMapUtils.getMapHandle(cpHandle, type);
+ }
+
+ public long getDateTime() {
+ return dateTime;
+ }
+
+ public String getDateTimeString() {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = new Date(dateTime);
+ return format.format(date); // Format to YYYYMMDDTHHMMSS local time
+ }
+
+ public void setDateTime(long dateTime) {
+ this.dateTime = dateTime;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ public String getSenderName() {
+ return senderName;
+ }
+
+ public void setSenderName(String senderName) {
+ this.senderName = senderName;
+ }
+
+ public String getSenderAddressing() {
+ return senderAddressing;
+ }
+
+ public void setSenderAddressing(String senderAddressing) {
+ /* TODO: This should depend on the type - for email, the addressing is an email address
+ * Consider removing this again - to allow strings.
+ */
+ this.senderAddressing = PhoneNumberUtils.extractNetworkPortion(senderAddressing);
+ if(this.senderAddressing == null || this.senderAddressing.length() < 2){
+ this.senderAddressing = "11"; // Ensure we have at least two digits to
+ }
+ }
+
+ public String getReplyToAddressing() {
+ return replytoAddressing;
+ }
+
+ public void setReplytoAddressing(String replytoAddressing) {
+ this.replytoAddressing = replytoAddressing;
+ }
+
+ public String getRecipientName() {
+ return recipientName;
+ }
+
+ public void setRecipientName(String recipientName) {
+ this.recipientName = recipientName;
+ }
+
+ public String getRecipientAddressing() {
+ return recipientAddressing;
+ }
+
+ public void setRecipientAddressing(String recipientAddressing) {
+ this.recipientAddressing = recipientAddressing;
+ }
+
+ public TYPE getType() {
+ return type;
+ }
+
+ public void setType(TYPE type) {
+ this.type = type;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public String getReceptionStatus() {
+ return receptionStatus;
+ }
+
+ public void setReceptionStatus(String receptionStatus) {
+ this.receptionStatus = receptionStatus;
+ }
+
+ public int getAttachmentSize() {
+ return attachmentSize;
+ }
+
+ public void setAttachmentSize(int attachmentSize) {
+ this.attachmentSize = attachmentSize;
+ }
+
+ public String getPriority() {
+ return priority;
+ }
+
+ public void setPriority(String priority) {
+ this.priority = priority;
+ }
+
+ public String getRead() {
+ return read;
+ }
+
+ public void setRead(String read, boolean reportRead) {
+ this.read = read;
+ this.reportRead = reportRead;
+ }
+
+ public String getSent() {
+ return sent;
+ }
+
+ public void setSent(String sent) {
+ this.sent = sent;
+ }
+
+ public String getProtect() {
+ return protect;
+ }
+
+ public void setProtect(String protect) {
+ this.protect = protect;
+ }
+
+ public int compareTo(BluetoothMapMessageListingElement e) {
+ if (this.dateTime < e.dateTime) {
+ return 1;
+ } else if (this.dateTime > e.dateTime) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ /* Encode the MapMessageListingElement into the StringBuilder reference.
+ * */
+ public void encode(XmlSerializer xmlMsgElement) throws IllegalArgumentException, IllegalStateException, IOException
+ {
+
+ // contruct the XML tag for a single msg in the msglisting
+ xmlMsgElement.startTag("", "msg");
+ xmlMsgElement.attribute("", "handle", mapHandle);
+ if(subject != null)
+ xmlMsgElement.attribute("", "subject", subject);
+ if(dateTime != 0)
+ xmlMsgElement.attribute("", "datetime", this.getDateTimeString());
+ if(senderName != null)
+ xmlMsgElement.attribute("", "sender_name", senderName);
+ if(senderAddressing != null)
+ xmlMsgElement.attribute("", "sender_addressing", senderAddressing);
+ if(replytoAddressing != null)
+ xmlMsgElement.attribute("", "replyto_addressing",replytoAddressing);
+ if(recipientName != null)
+ xmlMsgElement.attribute("", "recipient_name",recipientName);
+ if(recipientAddressing != null)
+ xmlMsgElement.attribute("", "recipient_addressing", recipientAddressing);
+ if(type != null)
+ xmlMsgElement.attribute("", "type", type.name());
+ if(size != -1)
+ xmlMsgElement.attribute("", "size", Integer.toString(size));
+ if(text != null)
+ xmlMsgElement.attribute("", "text", text);
+ if(receptionStatus != null)
+ xmlMsgElement.attribute("", "reception_status", receptionStatus);
+ if(attachmentSize != -1)
+ xmlMsgElement.attribute("", "attachment_size", Integer.toString(attachmentSize));
+ if(priority != null)
+ xmlMsgElement.attribute("", "priority", priority);
+ if(read != null && reportRead)
+ xmlMsgElement.attribute("", "read", read);
+ if(sent != null)
+ xmlMsgElement.attribute("", "sent", sent);
+ if(protect != null)
+ xmlMsgElement.attribute("", "protect", protect);
+ xmlMsgElement.endTag("", "msg");
+
+ }
+}
+
+
diff --git a/src/com/android/bluetooth/map/BluetoothMapObexServer.java b/src/com/android/bluetooth/map/BluetoothMapObexServer.java
new file mode 100644
index 0000000..a876740
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapObexServer.java
@@ -0,0 +1,704 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Calendar;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+import javax.obex.ResponseCodes;
+import javax.obex.ServerRequestHandler;
+
+import com.android.bluetooth.map.BluetoothMapUtils;
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class BluetoothMapObexServer extends ServerRequestHandler {
+
+ private static final String TAG = "BluetoothMapObexServer";
+
+ private static final boolean D = BluetoothMapService.DEBUG;
+ private static final boolean V = BluetoothMapService.VERBOSE;
+
+ private static final int UUID_LENGTH = 16;
+
+ // 128 bit UUID for MAP
+ private static final byte[] MAP_TARGET = new byte[] {
+ (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x40,
+ (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB,
+ (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00,
+ (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66
+ };
+
+ /* Message types */
+ private static final String TYPE_GET_FOLDER_LISTING = "x-obex/folder-listing";
+ private static final String TYPE_GET_MESSAGE_LISTING = "x-bt/MAP-msg-listing";
+ private static final String TYPE_MESSAGE = "x-bt/message";
+ private static final String TYPE_SET_MESSAGE_STATUS = "x-bt/messageStatus";
+ private static final String TYPE_SET_NOTIFICATION_REGISTRATION = "x-bt/MAP-NotificationRegistration";
+ private static final String TYPE_MESSAGE_UPDATE = "x-bt/MAP-messageUpdate";
+
+ private BluetoothMapFolderElement mCurrentFolder;
+
+ private BluetoothMnsObexClient mMnsClient;
+
+ private Handler mCallback = null;
+
+ private Context mContext;
+
+ public static boolean sIsAborted = false;
+
+ BluetoothMapContent mOutContent;
+
+ public BluetoothMapObexServer(Handler callback, Context context,
+ BluetoothMnsObexClient mns) {
+ super();
+ mCallback = callback;
+ mContext = context;
+ mOutContent = new BluetoothMapContent(mContext);
+ mMnsClient = mns;
+ buildFolderStructure(); /* Build the default folder structure, and set
+ mCurrentFolder to root folder */
+ }
+
+ /**
+ * Build the default minimal folder structure, as defined in the MAP specification.
+ */
+ private void buildFolderStructure(){
+ mCurrentFolder = new BluetoothMapFolderElement("root", null); // This will be the root element
+ BluetoothMapFolderElement tmpFolder;
+ tmpFolder = mCurrentFolder.addFolder("telecom"); // root/telecom
+ tmpFolder = tmpFolder.addFolder("msg"); // root/telecom/msg
+ tmpFolder.addFolder("inbox"); // root/telecom/msg/inbox
+ tmpFolder.addFolder("outbox");
+ tmpFolder.addFolder("sent");
+ tmpFolder.addFolder("deleted");
+ tmpFolder.addFolder("draft");
+ }
+
+ @Override
+ public int onConnect(final HeaderSet request, HeaderSet reply) {
+ if (D) Log.d(TAG, "onConnect():");
+ if (V) logHeader(request);
+ try {
+ byte[] uuid = (byte[])request.getHeader(HeaderSet.TARGET);
+ if (uuid == null) {
+ return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
+ }
+ if (D) Log.d(TAG, "onConnect(): uuid=" + Arrays.toString(uuid));
+
+ if (uuid.length != UUID_LENGTH) {
+ Log.w(TAG, "Wrong UUID length");
+ return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
+ }
+ for (int i = 0; i < UUID_LENGTH; i++) {
+ if (uuid[i] != MAP_TARGET[i]) {
+ Log.w(TAG, "Wrong UUID");
+ return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
+ }
+ }
+ reply.setHeader(HeaderSet.WHO, uuid);
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+ try {
+ byte[] remote = (byte[])request.getHeader(HeaderSet.WHO);
+ if (remote != null) {
+ if (D) Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote));
+ reply.setHeader(HeaderSet.TARGET, remote);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ }
+
+ if (V) Log.v(TAG, "onConnect(): uuid is ok, will send out " +
+ "MSG_SESSION_ESTABLISHED msg.");
+
+
+ Message msg = Message.obtain(mCallback);
+ msg.what = BluetoothMapService.MSG_SESSION_ESTABLISHED;
+ msg.sendToTarget();
+
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ @Override
+ public void onDisconnect(final HeaderSet req, final HeaderSet resp) {
+ if (D) Log.d(TAG, "onDisconnect(): enter");
+ if (V) logHeader(req);
+
+ resp.responseCode = ResponseCodes.OBEX_HTTP_OK;
+ if (mCallback != null) {
+ Message msg = Message.obtain(mCallback);
+ msg.what = BluetoothMapService.MSG_SESSION_DISCONNECTED;
+ msg.sendToTarget();
+ if (V) Log.v(TAG, "onDisconnect(): msg MSG_SESSION_DISCONNECTED sent out.");
+ }
+ }
+
+ @Override
+ public int onAbort(HeaderSet request, HeaderSet reply) {
+ if (D) Log.d(TAG, "onAbort(): enter.");
+ sIsAborted = true;
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ @Override
+ public int onPut(final Operation op) {
+ if (D) Log.d(TAG, "onPut(): enter");
+ HeaderSet request = null;
+ String type, name;
+ byte[] appParamRaw;
+ BluetoothMapAppParams appParams = null;
+
+ try {
+ request = op.getReceivedHeader();
+ type = (String)request.getHeader(HeaderSet.TYPE);
+ name = (String)request.getHeader(HeaderSet.NAME);
+ appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ if(appParamRaw != null)
+ appParams = new BluetoothMapAppParams(appParamRaw);
+ } catch (Exception e) {
+ Log.e(TAG, "request headers error");
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ if(D) Log.d(TAG,"type = " + type + ", name = " + name);
+ if (type.equals(TYPE_MESSAGE_UPDATE)) {
+ if(V) {
+ Log.d(TAG,"TYPE_MESSAGE_UPDATE:");
+ }
+ return ResponseCodes.OBEX_HTTP_OK;
+ }else if(type.equals(TYPE_SET_NOTIFICATION_REGISTRATION)) {
+ if(V) {
+ Log.d(TAG,"TYPE_SET_NOTIFICATION_REGISTRATION: NotificationStatus: " + appParams.getNotificationStatus());
+ }
+ return setNotificationRegistration(appParams);
+ }else if(type.equals(TYPE_SET_MESSAGE_STATUS)) {
+ if(V) {
+ Log.d(TAG,"TYPE_SET_MESSAGE_STATUS: StatusIndicator: " + appParams.getStatusIndicator() + ", StatusValue: " + appParams.getStatusValue());
+ }
+ return setMessageStatus(name, appParams);
+ } else if (type.equals(TYPE_MESSAGE)) {
+ if(V) {
+ Log.d(TAG,"TYPE_MESSAGE: Transparet: " + appParams.getTransparent() + ", Retry: " + appParams.getRetry());
+ Log.d(TAG," charset: " + appParams.getCharset());
+ }
+ return pushMessage(op, name, appParams);
+
+ }
+
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ private int setNotificationRegistration(BluetoothMapAppParams appParams) {
+ // Forward the request to the MNS thread as a message - including the MAS instance ID.
+ Handler mns = mMnsClient.getMessageHandler();
+ if(mns != null) {
+ Message msg = Message.obtain(mns);
+ msg.what = BluetoothMnsObexClient.MSG_MNS_NOTIFICATION_REGISTRATION;
+ msg.arg1 = 0; // TODO: Add correct MAS ID, as specified in the SDP record.
+ msg.arg2 = appParams.getNotificationStatus();
+ msg.sendToTarget();
+ if(D) Log.d(TAG,"MSG_MNS_NOTIFICATION_REGISTRATION");
+ return ResponseCodes.OBEX_HTTP_OK;
+ } else {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // This should not happen.
+ }
+ }
+
+ private int pushMessage(final Operation op, String folderName, BluetoothMapAppParams appParams) {
+ if(appParams.getCharset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) {
+ if(D) Log.d(TAG, "Missing charset - unable to decode message content. appParams.getCharset() = " + appParams.getCharset());
+ return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
+ }
+ try {
+ if(folderName == null || folderName.equals("")) {
+ folderName = mCurrentFolder.getName();
+ }
+ if(!folderName.equals("outbox") && !folderName.equals("draft")) {
+ if(D) Log.d(TAG, "Push message only allowed to outbox and draft. folderName: " + folderName);
+ return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
+ }
+ /* - Read out the message
+ * - Decode into a bMessage
+ * - send it.
+ */
+ InputStream bMsgStream;
+ BluetoothMapbMessage message;
+ bMsgStream = op.openInputStream();
+ message = BluetoothMapbMessage.parse(bMsgStream, appParams.getCharset()); // Decode the messageBody
+ // Send message
+ BluetoothMapContentObserver observer = mMnsClient.getContentObserver();
+ if (observer == null) {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // Should not happen.
+ }
+
+ long handle = observer.pushMessage(message, folderName, appParams);
+ if (D) Log.d(TAG, "pushMessage handle: " + handle);
+ if (handle < 0) {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // Should not happen.
+ }
+ HeaderSet replyHeaders = new HeaderSet();
+ String handleStr = BluetoothMapUtils.getMapHandle(handle, message.getType());
+ if (D) Log.d(TAG, "handleStr: " + handleStr + " message.getType(): " + message.getType());
+ replyHeaders.setHeader(HeaderSet.NAME, handleStr);
+ op.sendHeaders(replyHeaders);
+
+ bMsgStream.close();
+ } catch (IllegalArgumentException e) {
+ if(D) Log.w(TAG, "Wrongly formatted bMessage received", e);
+ return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
+ } catch (Exception e) {
+ // TODO: Change to IOException after debug
+ Log.e(TAG, "Exception occured: ", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ private int setMessageStatus(String msgHandle, BluetoothMapAppParams appParams) {
+ int indicator = appParams.getStatusIndicator();
+ int value = appParams.getStatusValue();
+ long handle;
+ BluetoothMapUtils.TYPE msgType;
+
+ if(indicator == BluetoothMapAppParams.INVALID_VALUE_PARAMETER ||
+ value == BluetoothMapAppParams.INVALID_VALUE_PARAMETER ||
+ msgHandle == null) {
+ return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
+ }
+ BluetoothMapContentObserver observer = mMnsClient.getContentObserver();
+ if (observer == null) {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // Should not happen.
+ }
+
+ try {
+ handle = BluetoothMapUtils.getCpHandle(msgHandle);
+ msgType = BluetoothMapUtils.getMsgTypeFromHandle(msgHandle);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Wrongly formatted message handle: " + msgHandle);
+ return ResponseCodes.OBEX_HTTP_PRECON_FAILED;
+ }
+
+ if( indicator == BluetoothMapAppParams.STATUS_INDICATOR_DELETED) {
+ if (!observer.setMessageStatusDeleted(handle, msgType, value)) {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
+ } else /* BluetoothMapAppParams.STATUS_INDICATOR_READE */ {
+ if (!observer.setMessageStatusRead(handle, msgType, value)) {
+ return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
+ }
+ }
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ @Override
+ public int onSetPath(final HeaderSet request, final HeaderSet reply, final boolean backup,
+ final boolean create) {
+ String folderName;
+ BluetoothMapFolderElement folder;
+ try {
+ folderName = (String)request.getHeader(HeaderSet.NAME);
+ } catch (Exception e) {
+ Log.e(TAG, "request headers error");
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ if (V) logHeader(request);
+ if (D) Log.d(TAG, "onSetPath name is " + folderName + " backup: " + backup
+ + "create: " + create);
+
+ if(backup == true){
+ if(mCurrentFolder.getParent() != null)
+ mCurrentFolder = mCurrentFolder.getParent();
+ else
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ if (folderName == null || folderName == "") {
+ if(backup == false)
+ mCurrentFolder = mCurrentFolder.getRoot();
+ }
+ else {
+ folder = mCurrentFolder.getSubFolder(folderName);
+ if(folder != null)
+ mCurrentFolder = folder;
+ else
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+ if (V) Log.d(TAG, "Current Folder: " + mCurrentFolder.getName());
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ @Override
+ public void onClose() {
+ if (mCallback != null) {
+ Message msg = Message.obtain(mCallback);
+ msg.what = BluetoothMapService.MSG_SERVERSESSION_CLOSE;
+ msg.sendToTarget();
+ if (D) Log.d(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out.");
+ }
+ }
+
+ @Override
+ public int onGet(Operation op) {
+ sIsAborted = false;
+ HeaderSet request;
+ String type;
+ String name;
+ byte[] appParamRaw = null;
+ BluetoothMapAppParams appParams = null;
+ try {
+ request = op.getReceivedHeader();
+ type = (String)request.getHeader(HeaderSet.TYPE);
+ name = (String)request.getHeader(HeaderSet.NAME);
+ appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ if(appParamRaw != null)
+ appParams = new BluetoothMapAppParams(appParamRaw);
+
+ if (V) logHeader(request);
+ if (D) Log.d(TAG, "OnGet type is " + type + " name is " + name);
+
+ if (type == null) {
+ if (V) Log.d(TAG, "type is null?" + type);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ if (type.equals(TYPE_GET_FOLDER_LISTING)) {
+ if (V && appParams != null) {
+ Log.d(TAG,"TYPE_GET_FOLDER_LISTING: MaxListCount = " + appParams.getMaxListCount() +
+ ", ListStartOffset = " + appParams.getStartOffset());
+ }
+ return sendFolderListingRsp(op, appParams); // Block until all packets have been send.
+ }
+ else if (type.equals(TYPE_GET_MESSAGE_LISTING)){
+ if (V && appParams != null) {
+ Log.d(TAG,"TYPE_GET_MESSAGE_LISTING: MaxListCount = " + appParams.getMaxListCount() +
+ ", ListStartOffset = " + appParams.getStartOffset());
+ Log.d(TAG,"SubjectLength = " + appParams.getSubjectLength() + ", ParameterMask = " +
+ appParams.getParameterMask());
+ Log.d(TAG,"FilterMessageType = " + appParams.getFilterMessageType() +
+ ", FilterPeriodBegin = " + appParams.getFilterPeriodBegin());
+ Log.d(TAG,"FilterPeriodEnd = " + appParams.getFilterPeriodBegin() +
+ ", FilterReadStatus = " + appParams.getFilterReadStatus());
+ Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient() +
+ ", FilterOriginator = " + appParams.getFilterOriginator());
+ Log.d(TAG,"FilterPriority = " + appParams.getFilterPriority());
+ }
+ return sendMessageListingRsp(op, appParams, name); // Block until all packets have been send.
+ }
+ else if (type.equals(TYPE_MESSAGE)){
+ if(V && appParams != null) {
+ Log.d(TAG,"TYPE_MESSAGE (GET): Attachment = " + appParams.getAttachment() + ", Charset = " + appParams.getCharset() +
+ ", FractionRequest = " + appParams.getFractionRequest());
+ }
+ return sendGetMessageRsp(op, name, appParams); // Block until all packets have been send.
+ }
+ else {
+ Log.w(TAG, "unknown type request: " + type);
+ return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
+ }
+ } catch (Exception e) {
+ // TODO: Move to the part that actually throws exceptions, and change to the correat exception type
+ Log.e(TAG, "request headers error, Exception:", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+ }
+
+ /**
+ * Generate and send the message listing response based on an application
+ * parameter header. This function call will block until complete or aborted
+ * by the peer. Fragmentation of packets larger than the obex packet size
+ * will be handled by this function.
+ *
+ * @param op
+ * The OBEX operation.
+ * @param appParams
+ * The application parameter header
+ * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or
+ * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error.
+ */
+ private int sendMessageListingRsp(Operation op, BluetoothMapAppParams appParams, String folderName){
+ OutputStream outStream = null;
+ byte[] outBytes = null;
+ int maxChunkSize, bytesToWrite, bytesWritten = 0, listSize;
+ boolean hasUnread = false;
+ HeaderSet replyHeaders = new HeaderSet();
+ BluetoothMapAppParams outAppParams = new BluetoothMapAppParams();
+ BluetoothMapMessageListing outList;
+ if(folderName == null) {
+ folderName = mCurrentFolder.getName();
+ }
+ if(appParams == null){
+ appParams = new BluetoothMapAppParams();
+ appParams.setMaxListCount(1024);
+ appParams.setStartOffset(0);
+ }
+
+ // Check to see if we only need to send the size - hence no need to encode.
+ try {
+ // Open the OBEX body stream
+ outStream = op.openOutputStream();
+
+ if(appParams.getMaxListCount() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
+ appParams.setMaxListCount(1024);
+
+ if(appParams.getStartOffset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
+ appParams.setStartOffset(0);
+
+ if(appParams.getMaxListCount() != 0) {
+ outList = mOutContent.msgListing(folderName, appParams);
+ // Generate the byte stream
+ outAppParams.setMessageListingSize(outList.getCount());
+ outBytes = outList.encode();
+ hasUnread = outList.hasUnread();
+ }
+ else {
+ listSize = mOutContent.msgListingSize(folderName, appParams);
+ hasUnread = mOutContent.msgListingHasUnread(folderName, appParams);
+ outAppParams.setMessageListingSize(listSize);
+ op.noBodyHeader();
+ }
+
+ // Build the application parameter header
+
+ // let the peer know if there are unread messages in the list
+ if(hasUnread)
+ {
+ outAppParams.setNewMessage(1);
+ }else{
+ outAppParams.setNewMessage(0);
+ }
+
+ outAppParams.setMseTime(Calendar.getInstance().getTime().getTime());
+ replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams());
+ op.sendHeaders(replyHeaders);
+
+ } catch (IOException e) {
+ Log.w(TAG,"sendMessageListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,"sendMessageListingRsp: IllegalArgumentException - sending OBEX_HTTP_BAD_REQUEST", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers.
+ if(outBytes != null) {
+ try {
+ while (bytesWritten < outBytes.length && sIsAborted == false) {
+ bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten);
+ outStream.write(outBytes, bytesWritten, bytesToWrite);
+ bytesWritten += bytesToWrite;
+ }
+ } catch (IOException e) {
+ if(V) Log.w(TAG,e);
+ // We were probably aborted or disconnected
+ } finally {
+ if(outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ // If an error occurs during close, there is no more cleanup to do
+ }
+ }
+ }
+ if(bytesWritten != outBytes.length)
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ } else {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ // If an error occurs during close, there is no more cleanup to do
+ }
+ }
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ /**
+ * Generate and send the Folder listing response based on an application
+ * parameter header. This function call will block until complete or aborted
+ * by the peer. Fragmentation of packets larger than the obex packet size
+ * will be handled by this function.
+ *
+ * @param op
+ * The OBEX operation.
+ * @param appParams
+ * The application parameter header
+ * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or
+ * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error.
+ */
+ private int sendFolderListingRsp(Operation op, BluetoothMapAppParams appParams){
+ OutputStream outStream = null;
+ byte[] outBytes = null;
+ BluetoothMapAppParams outAppParams = new BluetoothMapAppParams();
+ int maxChunkSize, bytesWritten = 0;
+ HeaderSet replyHeaders = new HeaderSet();
+ int bytesToWrite, maxListCount, listStartOffset;
+ if(appParams == null){
+ appParams = new BluetoothMapAppParams();
+ appParams.setMaxListCount(1024);
+ }
+
+ if(V)
+ Log.v(TAG,"sendFolderList for " + mCurrentFolder.getName());
+
+ try {
+ maxListCount = appParams.getMaxListCount();
+ listStartOffset = appParams.getStartOffset();
+
+ if(listStartOffset == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
+ listStartOffset = 0;
+
+ if(maxListCount == BluetoothMapAppParams.INVALID_VALUE_PARAMETER)
+ maxListCount = 1024;
+
+ if(maxListCount != 0)
+ {
+ outBytes = mCurrentFolder.encode(listStartOffset, maxListCount);
+ outStream = op.openOutputStream();
+ }
+
+ // Build and set the application parameter header
+ outAppParams.setFolderListingSize(mCurrentFolder.getSubFolderCount());
+ replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams());
+ op.sendHeaders(replyHeaders);
+
+ } catch (IOException e1) {
+ Log.w(TAG,"sendFolderListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST Exception:", e1);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ } catch (IllegalArgumentException e1) {
+ Log.w(TAG,"sendFolderListingRsp: IllegalArgumentException - sending OBEX_HTTP_BAD_REQUEST Exception:", e1);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers.
+
+ if(outBytes != null) {
+ try {
+ while (bytesWritten < outBytes.length && sIsAborted == false) {
+ bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten);
+ outStream.write(outBytes, bytesWritten, bytesToWrite);
+ bytesWritten += bytesToWrite;
+ }
+ } catch (IOException e) {
+ // We were probably aborted or disconnected
+ } finally {
+ if(outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ // If an error occurs during close, there is no more cleanup to do
+ }
+ }
+ }
+ if(V)
+ Log.v(TAG,"sendFolderList sent " + bytesWritten + " bytes out of "+ outBytes.length);
+ if(bytesWritten == outBytes.length)
+ return ResponseCodes.OBEX_HTTP_OK;
+ else
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+ /**
+ * Generate and send the get message response based on an application
+ * parameter header and a handle.
+ *
+ * @param op
+ * The OBEX operation.
+ * @param appParams
+ * The application parameter header
+ * @param handle
+ * The handle of the requested message
+ * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or
+ * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error.
+ */
+ private int sendGetMessageRsp(Operation op, String handle, BluetoothMapAppParams appParams){
+ OutputStream outStream ;
+ byte[] outBytes;
+ int maxChunkSize, bytesToWrite, bytesWritten = 0;
+ long msgHandle;
+
+ try {
+ outBytes = mOutContent.getMessage(handle, appParams);
+ outStream = op.openOutputStream();
+
+ } catch (IOException e) {
+ Log.w(TAG,"sendGetMessageRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,"sendGetMessageRsp: IllegalArgumentException (e.g. invalid handle) - sending OBEX_HTTP_BAD_REQUEST", e);
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers.
+
+ if(outBytes != null) {
+ try {
+ while (bytesWritten < outBytes.length && sIsAborted == false) {
+ bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten);
+ outStream.write(outBytes, bytesWritten, bytesToWrite);
+ bytesWritten += bytesToWrite;
+ }
+ } catch (IOException e) {
+ // We were probably aborted or disconnected
+ } finally {
+ if(outStream != null) {
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ // If an error occurs during close, there is no more cleanup to do
+ }
+ }
+ }
+ if(bytesWritten == outBytes.length)
+ return ResponseCodes.OBEX_HTTP_OK;
+ else
+ return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
+ }
+
+ return ResponseCodes.OBEX_HTTP_OK;
+ }
+
+
+ private static final void logHeader(HeaderSet hs) {
+ Log.v(TAG, "Dumping HeaderSet " + hs.toString());
+ try {
+ Log.v(TAG, "CONNECTION_ID : " + hs.getHeader(HeaderSet.CONNECTION_ID));
+ Log.v(TAG, "NAME : " + hs.getHeader(HeaderSet.NAME));
+ Log.v(TAG, "TYPE : " + hs.getHeader(HeaderSet.TYPE));
+ Log.v(TAG, "TARGET : " + hs.getHeader(HeaderSet.TARGET));
+ Log.v(TAG, "WHO : " + hs.getHeader(HeaderSet.WHO));
+ Log.v(TAG, "APPLICATION_PARAMETER : " + hs.getHeader(HeaderSet.APPLICATION_PARAMETER));
+ } catch (IOException e) {
+ Log.e(TAG, "dump HeaderSet error " + e);
+ }
+ Log.v(TAG, "NEW!!! Dumping HeaderSet END");
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapRfcommTransport.java b/src/com/android/bluetooth/map/BluetoothMapRfcommTransport.java
new file mode 100644
index 0000000..90437d8
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapRfcommTransport.java
@@ -0,0 +1,72 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import android.bluetooth.BluetoothSocket;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.obex.ObexTransport;
+
+public class BluetoothMapRfcommTransport implements ObexTransport {
+ private BluetoothSocket mSocket = null;
+
+ public BluetoothMapRfcommTransport(BluetoothSocket rfs) {
+ super();
+ this.mSocket = rfs;
+ }
+
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ public InputStream openInputStream() throws IOException {
+ return mSocket.getInputStream();
+ }
+
+ public OutputStream openOutputStream() throws IOException {
+ return mSocket.getOutputStream();
+ }
+
+ public void connect() throws IOException {
+ }
+
+ public void create() throws IOException {
+ }
+
+ public void disconnect() throws IOException {
+ }
+
+ public void listen() throws IOException {
+ }
+
+ public boolean isConnected() throws IOException {
+ return true;
+ }
+
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapService.java b/src/com/android/bluetooth/map/BluetoothMapService.java
new file mode 100644
index 0000000..c5c03ef
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapService.java
@@ -0,0 +1,794 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.obex.ServerSession;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothMap;
+import android.bluetooth.BluetoothUuid;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.ParcelUuid;
+import android.text.TextUtils;
+import android.util.Log;
+import android.provider.Settings;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+
+import com.android.bluetooth.R;
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.btservice.ProfileService;
+import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
+
+
+public class BluetoothMapService extends ProfileService {
+ private static final String TAG = "BluetoothMapService";
+
+ /**
+ * To enable MAP DEBUG/VERBOSE logging - run below cmd in adb shell, and
+ * restart com.android.bluetooth process. only enable DEBUG log:
+ * "setprop log.tag.BluetoothMapService DEBUG"; enable both VERBOSE and
+ * DEBUG log: "setprop log.tag.BluetoothMapService VERBOSE"
+ */
+
+ public static final boolean DEBUG = true;
+
+ public static final boolean VERBOSE = false;
+
+ /**
+ * Intent indicating incoming obex authentication request which is from
+ * PCE(Carkit)
+ */
+ public static final String AUTH_CHALL_ACTION = "com.android.bluetooth.map.authchall";
+
+ /**
+ * Intent indicating timeout for user confirmation, which is sent to
+ * BluetoothMapActivity
+ */
+ public static final String USER_CONFIRM_TIMEOUT_ACTION =
+ "com.android.bluetooth.map.userconfirmtimeout";
+
+ /**
+ * Intent Extra name indicating session key which is sent from
+ * BluetoothMapActivity
+ */
+ public static final String EXTRA_SESSION_KEY = "com.android.bluetooth.map.sessionkey";
+
+ public static final String THIS_PACKAGE_NAME = "com.android.bluetooth";
+
+ public static final int MSG_SERVERSESSION_CLOSE = 5000;
+
+ public static final int MSG_SESSION_ESTABLISHED = 5001;
+
+ public static final int MSG_SESSION_DISCONNECTED = 5002;
+
+ public static final int MSG_OBEX_AUTH_CHALL = 5003;
+
+ private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+ private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+
+ private static final int START_LISTENER = 1;
+
+ private static final int USER_TIMEOUT = 2;
+
+ private static final int DISCONNECT_MAP = 3;
+
+ private PowerManager.WakeLock mWakeLock = null;
+
+ private BluetoothAdapter mAdapter;
+
+ private SocketAcceptThread mAcceptThread = null;
+
+ private BluetoothMapAuthenticator mAuth = null;
+
+ private BluetoothMapObexServer mMapServer;
+
+ private ServerSession mServerSession = null;
+
+ private BluetoothMnsObexClient mBluetoothMnsObexClient = null;
+
+ private BluetoothServerSocket mServerSocket = null;
+
+ private BluetoothSocket mConnSocket = null;
+
+ private BluetoothDevice mRemoteDevice = null;
+
+ private static String sRemoteDeviceName = null;
+
+ private volatile boolean mInterrupted;
+
+ private int mState;
+
+ private boolean isWaitingAuthorization = false;
+
+ // package and class name to which we send intent to check message access access permission
+ private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings";
+ private static final String ACCESS_AUTHORITY_CLASS =
+ "com.android.settings.bluetooth.BluetoothPermissionRequest";
+
+ private static final ParcelUuid[] MAP_UUIDS = {
+ BluetoothUuid.MAP,
+ BluetoothUuid.MNS,
+ };
+
+ public BluetoothMapService() {
+ mState = BluetoothMap.STATE_DISCONNECTED;
+ }
+
+ private void startRfcommSocketListener() {
+ if (DEBUG) Log.d(TAG, "Map Service startRfcommSocketListener");
+
+ if (mAcceptThread == null) {
+ mAcceptThread = new SocketAcceptThread();
+ mAcceptThread.setName("BluetoothMapAcceptThread");
+ mAcceptThread.start();
+ }
+ }
+
+ private final boolean initSocket() {
+ if (DEBUG) Log.d(TAG, "Map Service initSocket");
+
+ boolean initSocketOK = false;
+ final int CREATE_RETRY_TIME = 10;
+
+ // It's possible that create will fail in some cases. retry for 10 times
+ for (int i = 0; (i < CREATE_RETRY_TIME) && !mInterrupted; i++) {
+ initSocketOK = true;
+ try {
+ // It is mandatory for MSE to support initiation of bonding and
+ // encryption.
+ mServerSocket = mAdapter.listenUsingEncryptedRfcommWithServiceRecord
+ ("MAP SMS/MMS", BluetoothUuid.MAS.getUuid());
+
+ } catch (IOException e) {
+ Log.e(TAG, "Error create RfcommServerSocket " + e.toString());
+ initSocketOK = false;
+ }
+ if (!initSocketOK) {
+ // Need to break out of this loop if BT is being turned off.
+ if (mAdapter == null) break;
+ int state = mAdapter.getState();
+ if ((state != BluetoothAdapter.STATE_TURNING_ON) &&
+ (state != BluetoothAdapter.STATE_ON)) {
+ Log.w(TAG, "initServerSocket failed as BT is (being) turned off");
+ break;
+ }
+ try {
+ if (VERBOSE) Log.v(TAG, "wait 300 ms");
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "socketAcceptThread thread was interrupted (3)");
+ }
+ } else {
+ break;
+ }
+ }
+ if (mInterrupted) {
+ initSocketOK = false;
+ // close server socket to avoid resource leakage
+ closeServerSocket();
+ }
+
+ if (initSocketOK) {
+ if (VERBOSE) Log.v(TAG, "Succeed to create listening socket ");
+
+ } else {
+ Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try");
+ }
+ return initSocketOK;
+ }
+
+ private final synchronized void closeServerSocket() {
+ // exit SocketAcceptThread early
+ if (mServerSocket != null) {
+ try {
+ // this will cause mServerSocket.accept() return early with IOException
+ mServerSocket.close();
+ mServerSocket = null;
+ } catch (IOException ex) {
+ Log.e(TAG, "Close Server Socket error: " + ex);
+ }
+ }
+ }
+ private final synchronized void closeConnectionSocket() {
+ if (mConnSocket != null) {
+ try {
+ mConnSocket.close();
+ mConnSocket = null;
+ } catch (IOException e) {
+ Log.e(TAG, "Close Connection Socket error: " + e.toString());
+ }
+ }
+ }
+
+ private final void closeService() {
+ if (DEBUG) Log.d(TAG, "MAP Service closeService in");
+
+ // exit initSocket early
+ mInterrupted = true;
+ closeServerSocket();
+
+ if (mAcceptThread != null) {
+ try {
+ mAcceptThread.shutdown();
+ mAcceptThread.join();
+ mAcceptThread = null;
+ } catch (InterruptedException ex) {
+ Log.w(TAG, "mAcceptThread close error" + ex);
+ }
+ }
+
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+
+ if (mServerSession != null) {
+ mServerSession.close();
+ mServerSession = null;
+ }
+
+ if (mBluetoothMnsObexClient != null) {
+ mBluetoothMnsObexClient.shutdown();
+ mBluetoothMnsObexClient = null;
+ }
+
+ closeConnectionSocket();
+
+ if (mSessionStatusHandler != null) {
+ mSessionStatusHandler.removeCallbacksAndMessages(null);
+ }
+ isWaitingAuthorization = false;
+
+ if (VERBOSE) Log.v(TAG, "MAP Service closeService out");
+ }
+
+ private final void startObexServerSession() throws IOException {
+ if (DEBUG) Log.d(TAG, "Map Service startObexServerSession");
+
+ // acquire the wakeLock before start Obex transaction thread
+ if (mWakeLock == null) {
+ PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "StartingObexMapTransaction");
+ mWakeLock.setReferenceCounted(false);
+ mWakeLock.acquire();
+ }
+
+ mBluetoothMnsObexClient = new BluetoothMnsObexClient(this, mRemoteDevice);
+ mMapServer = new BluetoothMapObexServer(mSessionStatusHandler, this,
+ mBluetoothMnsObexClient);
+ synchronized (this) {
+ // We need to get authentication now that obex server is up
+ mAuth = new BluetoothMapAuthenticator(mSessionStatusHandler);
+ mAuth.setChallenged(false);
+ mAuth.setCancelled(false);
+ }
+ // setup RFCOMM transport
+ BluetoothMapRfcommTransport transport = new BluetoothMapRfcommTransport(mConnSocket);
+ mServerSession = new ServerSession(transport, mMapServer, mAuth);
+ setState(BluetoothMap.STATE_CONNECTED);
+ if (VERBOSE) {
+ Log.v(TAG, "startObexServerSession() success!");
+ }
+ }
+
+ private void stopObexServerSession() {
+ if (DEBUG) Log.d(TAG, "MAP Service stopObexServerSession");
+
+ // Release the wake lock if obex transaction is over
+ if (mWakeLock != null) {
+ mWakeLock.release();
+ mWakeLock = null;
+ }
+
+ if (mServerSession != null) {
+ mServerSession.close();
+ mServerSession = null;
+ }
+
+ mAcceptThread = null;
+
+ if(mBluetoothMnsObexClient != null) {
+ mBluetoothMnsObexClient.shutdown();
+ mBluetoothMnsObexClient = null;
+ }
+ closeConnectionSocket();
+
+ // Last obex transaction is finished, we start to listen for incoming
+ // connection again
+ if (mAdapter.isEnabled()) {
+ startRfcommSocketListener();
+ }
+ setState(BluetoothMap.STATE_DISCONNECTED);
+ }
+
+
+
+ /**
+ * A thread that runs in the background waiting for remote rfcomm
+ * connect.Once a remote socket connected, this thread shall be
+ * shutdown.When the remote disconnect,this thread shall run again waiting
+ * for next request.
+ */
+ private class SocketAcceptThread extends Thread {
+
+ private boolean stopped = false;
+
+ @Override
+ public void run() {
+ BluetoothServerSocket serverSocket;
+ if (mServerSocket == null) {
+ if (!initSocket()) {
+ return;
+ }
+ }
+
+ while (!stopped) {
+ try {
+ if (DEBUG) Log.d(TAG, "Accepting socket connection...");
+ serverSocket = mServerSocket;
+ if(serverSocket == null) {
+ Log.w(TAG, "mServerSocket is null");
+ break;
+ }
+ mConnSocket = serverSocket.accept();
+ if (DEBUG) Log.d(TAG, "Accepted socket connection...");
+ synchronized (BluetoothMapService.this) {
+ if (mConnSocket == null) {
+ Log.w(TAG, "mConnSocket is null");
+ break;
+ }
+ mRemoteDevice = mConnSocket.getRemoteDevice();
+ }
+ if (mRemoteDevice == null) {
+ Log.i(TAG, "getRemoteDevice() = null");
+ break;
+ }
+
+ sRemoteDeviceName = mRemoteDevice.getName();
+ // In case getRemoteName failed and return null
+ if (TextUtils.isEmpty(sRemoteDeviceName)) {
+ sRemoteDeviceName = getString(R.string.defaultname);
+ }
+ boolean trust = mRemoteDevice.getTrustState();
+ if (DEBUG) Log.d(TAG, "GetTrustState() = " + trust);
+
+
+ if (trust) {
+ try {
+ if (DEBUG) Log.d(TAG, "incoming connection accepted from: "
+ + sRemoteDeviceName + " automatically as trusted device");
+ startObexServerSession();
+ } catch (IOException ex) {
+ Log.e(TAG, "catch exception starting obex server session"
+ + ex.toString());
+ }
+ } else {
+ Intent intent = new
+ Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
+ intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
+ intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+
+ isWaitingAuthorization = true;
+ sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+
+ if (DEBUG) Log.d(TAG, "waiting for authorization for connection from: "
+ + sRemoteDeviceName);
+
+ }
+ stopped = true; // job done ,close this thread;
+ } catch (IOException ex) {
+ stopped=true;
+ if (VERBOSE) Log.v(TAG, "Accept exception: " + ex.toString());
+ }
+ }
+ }
+
+ void shutdown() {
+ stopped = true;
+ interrupt();
+ }
+ }
+
+ private final Handler mSessionStatusHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (VERBOSE) Log.v(TAG, "Handler(): got msg=" + msg.what);
+
+ switch (msg.what) {
+ case START_LISTENER:
+ if (mAdapter.isEnabled()) {
+ startRfcommSocketListener();
+ }
+ break;
+ case USER_TIMEOUT:
+ Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL);
+ intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
+ intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS);
+ sendBroadcast(intent);
+ isWaitingAuthorization = false;
+ stopObexServerSession();
+ break;
+ case MSG_SERVERSESSION_CLOSE:
+ stopObexServerSession();
+ break;
+ case MSG_SESSION_ESTABLISHED:
+ break;
+ case MSG_SESSION_DISCONNECTED:
+ // handled elsewhere
+ break;
+ case DISCONNECT_MAP:
+ disconnectMap((BluetoothDevice)msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+
+ public int getState() {
+ return mState;
+ }
+
+ public BluetoothDevice getRemoteDevice() {
+ return mRemoteDevice;
+ }
+ private void setState(int state) {
+ setState(state, BluetoothMap.RESULT_SUCCESS);
+ }
+
+ private synchronized void setState(int state, int result) {
+ if (state != mState) {
+ if (DEBUG) Log.d(TAG, "Map state " + mState + " -> " + state + ", result = "
+ + result);
+ int prevState = mState;
+ mState = state;
+ Intent intent = new Intent(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
+ intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
+ intent.putExtra(BluetoothProfile.EXTRA_STATE, mState);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
+ sendBroadcast(intent, BLUETOOTH_PERM);
+ AdapterService s = AdapterService.getAdapterService();
+ if (s != null) {
+ s.onProfileConnectionStateChanged(mRemoteDevice, BluetoothProfile.MAP,
+ mState, prevState);
+ }
+ }
+ }
+
+ public static String getRemoteDeviceName() {
+ return sRemoteDeviceName;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(DISCONNECT_MAP, 0, 0, device));
+ return true;
+ }
+
+ public boolean disconnectMap(BluetoothDevice device) {
+ boolean result = false;
+ if (DEBUG) Log.d(TAG, "disconnectMap");
+ if (getRemoteDevice().equals(device)) {
+ switch (mState) {
+ case BluetoothMap.STATE_CONNECTED:
+ if (mServerSession != null) {
+ mServerSession.close();
+ mServerSession = null;
+ }
+ if(mBluetoothMnsObexClient != null) {
+ mBluetoothMnsObexClient.shutdown();
+ mBluetoothMnsObexClient = null;
+ }
+ closeConnectionSocket();
+
+ setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED);
+ result = true;
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+ synchronized(this) {
+ if (mState == BluetoothMap.STATE_CONNECTED && mRemoteDevice != null) {
+ devices.add(mRemoteDevice);
+ }
+ }
+ return devices;
+ }
+
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
+ Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
+ int connectionState;
+ synchronized (this) {
+ for (BluetoothDevice device : bondedDevices) {
+ ParcelUuid[] featureUuids = device.getUuids();
+ if (!BluetoothUuid.containsAnyUuid(featureUuids, MAP_UUIDS)) {
+ continue;
+ }
+ connectionState = getConnectionState(device);
+ for(int i = 0; i < states.length; i++) {
+ if (connectionState == states[i]) {
+ deviceList.add(device);
+ }
+ }
+ }
+ }
+ return deviceList;
+ }
+
+ public int getConnectionState(BluetoothDevice device) {
+ synchronized(this) {
+ if (getState() == BluetoothMap.STATE_CONNECTED && getRemoteDevice().equals(device)) {
+ return BluetoothProfile.STATE_CONNECTED;
+ } else {
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ }
+
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ Settings.Global.putInt(getContentResolver(),
+ Settings.Global.getBluetoothMapPriorityKey(device.getAddress()),
+ priority);
+ if (DEBUG) Log.d(TAG, "Saved priority " + device + " = " + priority);
+ return true;
+ }
+
+ public int getPriority(BluetoothDevice device) {
+ int priority = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.getBluetoothMapPriorityKey(device.getAddress()),
+ BluetoothProfile.PRIORITY_UNDEFINED);
+ return priority;
+ }
+
+ @Override
+ protected IProfileServiceBinder initBinder() {
+ return new BluetoothMapBinder(this);
+ }
+
+ @Override
+ protected boolean start() {
+ if (DEBUG) Log.d(TAG, "start()");
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ try {
+ registerReceiver(mMapReceiver, filter);
+ } catch (Exception e) {
+ Log.w(TAG,"Unable to register map receiver",e);
+ }
+ mInterrupted = false;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ // start RFCOMM listener
+ mSessionStatusHandler.sendMessage(mSessionStatusHandler
+ .obtainMessage(START_LISTENER));
+ return true;
+ }
+
+ @Override
+ protected boolean stop() {
+ if (DEBUG) Log.d(TAG, "stop()");
+ try {
+ unregisterReceiver(mMapReceiver);
+ } catch (Exception e) {
+ Log.w(TAG,"Unable to unregister map receiver",e);
+ }
+
+ setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED);
+ closeService();
+ return true;
+ }
+
+ public boolean cleanup() {
+ if (DEBUG) Log.d(TAG, "cleanup()");
+ setState(BluetoothMap.STATE_DISCONNECTED, BluetoothMap.RESULT_CANCELED);
+ closeService();
+ return true;
+ }
+
+ private MapBroadcastReceiver mMapReceiver = new MapBroadcastReceiver();
+
+ private class MapBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "onReceive");
+ String action = intent.getAction();
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ if (state == BluetoothAdapter.STATE_TURNING_OFF) {
+ if (DEBUG) Log.d(TAG, "STATE_TURNING_OFF");
+ // Release all resources
+ closeService();
+ } else if (state == BluetoothAdapter.STATE_ON) {
+ if (DEBUG) Log.d(TAG, "STATE_ON");
+ mInterrupted = false;
+ // start RFCOMM listener
+ mSessionStatusHandler.sendMessage(mSessionStatusHandler
+ .obtainMessage(START_LISTENER));
+ }
+ } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
+ int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
+ if (DEBUG) Log.d(TAG, "Received ACTION_CONNECTION_ACCESS_REPLY:" +
+ requestType + ":" + isWaitingAuthorization);
+ if ((!isWaitingAuthorization) ||
+ (requestType != BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS)) {
+ // this reply is not for us
+ return;
+ }
+
+ isWaitingAuthorization = false;
+
+ if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
+ BluetoothDevice.CONNECTION_ACCESS_NO) ==
+ BluetoothDevice.CONNECTION_ACCESS_YES) {
+ //bluetooth connection accepted by user
+ if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
+ boolean result = mRemoteDevice.setTrust(true);
+ if (DEBUG) Log.d(TAG, "setTrust() result=" + result);
+ }
+ try {
+ if (mConnSocket != null) {
+ // start obex server and rfcomm connection
+ startObexServerSession();
+ } else {
+ stopObexServerSession();
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Caught the error: " + ex.toString());
+ }
+ } else {
+ stopObexServerSession();
+ }
+ }
+ }
+ };
+
+ //Binder object: Must be static class or memory leak may occur
+ /**
+ * This class implements the IBluetoothMap interface - or actually it validates the
+ * preconditions for calling the actual functionality in the MapService, and calls it.
+ */
+ private static class BluetoothMapBinder extends IBluetoothMap.Stub
+ implements IProfileServiceBinder {
+ private BluetoothMapService mService;
+
+ private BluetoothMapService getService() {
+ if (!Utils.checkCaller()) {
+ Log.w(TAG,"MAP call not allowed for non-active user");
+ return null;
+ }
+
+ if (mService != null && mService.isAvailable()) {
+ mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ return mService;
+ }
+ return null;
+ }
+
+ BluetoothMapBinder(BluetoothMapService service) {
+ if (VERBOSE) Log.v(TAG, "BluetoothMapBinder()");
+ mService = service;
+ }
+
+ public boolean cleanup() {
+ mService = null;
+ return true;
+ }
+
+ public int getState() {
+ if (VERBOSE) Log.v(TAG, "getState()");
+ BluetoothMapService service = getService();
+ if (service == null) return BluetoothMap.STATE_DISCONNECTED;
+ return getService().getState();
+ }
+
+ public BluetoothDevice getClient() {
+ if (VERBOSE) Log.v(TAG, "getClient()");
+ BluetoothMapService service = getService();
+ if (service == null) return null;
+ Log.v(TAG, "getClient() - returning " + service.getRemoteDevice());
+ return service.getRemoteDevice();
+ }
+
+ public boolean isConnected(BluetoothDevice device) {
+ if (VERBOSE) Log.v(TAG, "isConnected()");
+ BluetoothMapService service = getService();
+ if (service == null) return false;
+ return service.getState() == BluetoothMap.STATE_CONNECTED && service.getRemoteDevice().equals(device);
+ }
+
+ public boolean connect(BluetoothDevice device) {
+ if (VERBOSE) Log.v(TAG, "connect()");
+ BluetoothMapService service = getService();
+ if (service == null) return false;
+ return false;
+ }
+
+ public boolean disconnect(BluetoothDevice device) {
+ if (VERBOSE) Log.v(TAG, "disconnect()");
+ BluetoothMapService service = getService();
+ if (service == null) return false;
+ return service.disconnect(device);
+ }
+
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VERBOSE) Log.v(TAG, "getConnectedDevices()");
+ BluetoothMapService service = getService();
+ if (service == null) return new ArrayList<BluetoothDevice>(0);
+ return service.getConnectedDevices();
+ }
+
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VERBOSE) Log.v(TAG, "getDevicesMatchingConnectionStates()");
+ BluetoothMapService service = getService();
+ if (service == null) return new ArrayList<BluetoothDevice>(0);
+ return service.getDevicesMatchingConnectionStates(states);
+ }
+
+ public int getConnectionState(BluetoothDevice device) {
+ if (VERBOSE) Log.v(TAG, "getConnectionState()");
+ BluetoothMapService service = getService();
+ if (service == null) return BluetoothProfile.STATE_DISCONNECTED;
+ return service.getConnectionState(device);
+ }
+
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ BluetoothMapService service = getService();
+ if (service == null) return false;
+ return service.setPriority(device, priority);
+ }
+
+ public int getPriority(BluetoothDevice device) {
+ BluetoothMapService service = getService();
+ if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
+ return service.getPriority(device);
+ }
+ };
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java b/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java
new file mode 100644
index 0000000..2070c26
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapSmsPdu.java
@@ -0,0 +1,748 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
+import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Random;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SmsMessage;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.telephony.*;
+/*import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.SmsConstants;*/
+import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
+import com.android.internal.telephony.cdma.sms.*;
+import com.android.internal.telephony.gsm.SmsMessage.SubmitPdu;
+
+public class BluetoothMapSmsPdu {
+
+ private static final String TAG = "BluetoothMapSmsPdu";
+ private static final boolean V = false;
+ private static int INVALID_VALUE = -1;
+ public static int SMS_TYPE_GSM = 1;
+ public static int SMS_TYPE_CDMA = 2;
+
+
+ /* TODO: We need to handle the SC-address mentioned in errata 4335.
+ * Since the definition could be read in three different ways, I have asked
+ * the car working group for clarification, and are awaiting confirmation that
+ * this clarification will go into the MAP spec:
+ * "The native format should be <sc_addr><tpdu> where <sc_addr> is <length><ton><1..10 octet of address>
+ * coded according to 24.011. The IEI is not to be used, as the fixed order of the data makes a type 4 LV
+ * information element sufficient. <length> is a single octet which value is the length of the value-field
+ * in octets including both the <ton> and the <address>."
+ * */
+
+
+ public static class SmsPdu {
+ private byte[] data;
+ private byte[] scAddress = {0}; // At the moment we do not use the scAddress, hence set the length to 0.
+ private int userDataMsgOffset = 0;
+ private int encoding;
+ private int languageTable;
+ private int languageShiftTable;
+ private int type;
+
+ /* Members used for pdu decoding */
+ private int userDataSeptetPadding = INVALID_VALUE;
+ private int msgSeptetCount = 0;
+
+ SmsPdu(byte[] data, int type){
+ this.data = data;
+ this.encoding = INVALID_VALUE;
+ this.type = type;
+ this.languageTable = INVALID_VALUE;
+ this.languageShiftTable = INVALID_VALUE;
+ this.userDataMsgOffset = gsmSubmitGetTpUdOffset(); // Assume no user data header
+ }
+
+ /**
+ * Create a pdu instance based on the data generated on this device.
+ * @param data
+ * @param encoding
+ * @param type
+ * @param languageTable
+ */
+ SmsPdu(byte[]data, int encoding, int type, int languageTable){
+ this.data = data;
+ this.encoding = encoding;
+ this.type = type;
+ this.languageTable = languageTable;
+ }
+ public byte[] getData(){
+ return data;
+ }
+ public byte[] getScAddress(){
+ return scAddress;
+ }
+ public void setEncoding(int encoding) {
+ this.encoding = encoding;
+ }
+ public int getEncoding(){
+ return encoding;
+ }
+ public int getType(){
+ return type;
+ }
+ public int getUserDataMsgOffset() {
+ return userDataMsgOffset;
+ }
+ /** The user data message payload size in bytes - excluding the user data header. */
+ public int getUserDataMsgSize() {
+ return data.length - userDataMsgOffset;
+ }
+
+ public int getLanguageShiftTable() {
+ return languageShiftTable;
+ }
+
+ public int getLanguageTable() {
+ return languageTable;
+ }
+
+ public int getUserDataSeptetPadding() {
+ return userDataSeptetPadding;
+ }
+
+ public int getMsgSeptetCount() {
+ return msgSeptetCount;
+ }
+
+
+ /* PDU parsing/modification functionality */
+ private final static byte TELESERVICE_IDENTIFIER = 0x00;
+ private final static byte SERVICE_CATEGORY = 0x01;
+ private final static byte ORIGINATING_ADDRESS = 0x02;
+ private final static byte ORIGINATING_SUB_ADDRESS = 0x03;
+ private final static byte DESTINATION_ADDRESS = 0x04;
+ private final static byte DESTINATION_SUB_ADDRESS = 0x05;
+ private final static byte BEARER_REPLY_OPTION = 0x06;
+ private final static byte CAUSE_CODES = 0x07;
+ private final static byte BEARER_DATA = 0x08;
+
+ /**
+ * Find and return the offset to the specified parameter ID
+ * @param parameterId The parameter ID to find
+ * @return the offset in number of bytes to the parameterID entry in the pdu data.
+ * The byte at the offset contains the parameter ID, the byte following contains the
+ * parameter length, and offset + 2 is the first byte of the parameter data.
+ */
+ private int cdmaGetParameterOffset(byte parameterId) {
+ ByteArrayInputStream pdu = new ByteArrayInputStream(data);
+ int offset = 0;
+ boolean found = false;
+
+ try {
+ pdu.skip(1); // Skip the message type
+
+ while (pdu.available() > 0) {
+ int currentId = pdu.read();
+ int currentLen = pdu.read();
+
+ if(currentId == parameterId) {
+ found = true;
+ break;
+ }
+ else {
+ pdu.skip(currentLen);
+ offset += 2 + currentLen;
+ }
+ }
+ pdu.close();
+ } catch (Exception e) {
+ Log.e(TAG, "cdmaGetParameterOffset: ", e);
+ }
+
+ if(found)
+ return offset;
+ else
+ return 0;
+ }
+
+ private final static byte BEARER_DATA_MSG_ID = 0x00;
+
+ private int cdmaGetSubParameterOffset(byte subParameterId) {
+ ByteArrayInputStream pdu = new ByteArrayInputStream(data);
+ int offset = 0;
+ boolean found = false;
+ offset = cdmaGetParameterOffset(BEARER_DATA) + 2; // Add to offset the BEARER_DATA parameter id and length bytes
+ pdu.skip(offset);
+ try {
+
+ while (pdu.available() > 0) {
+ int currentId = pdu.read();
+ int currentLen = pdu.read();
+
+ if(currentId == subParameterId) {
+ found = true;
+ break;
+ }
+ else {
+ pdu.skip(currentLen);
+ offset += 2 + currentLen;
+ }
+ }
+ pdu.close();
+ } catch (Exception e) {
+ Log.e(TAG, "cdmaGetParameterOffset: ", e);
+ }
+
+ if(found)
+ return offset;
+ else
+ return 0;
+ }
+
+
+ public void cdmaChangeToDeliverPdu(long date){
+ /* Things to change:
+ * - Message Type in bearer data (Not the overall point-to-point type)
+ * - Change address ID from destination to originating (sub addresses are not used)
+ * - A time stamp is not mandatory.
+ */
+ int offset;
+ offset = cdmaGetParameterOffset(DESTINATION_ADDRESS);
+ data[offset] = ORIGINATING_ADDRESS;
+ offset = cdmaGetParameterOffset(DESTINATION_SUB_ADDRESS);
+ data[offset] = ORIGINATING_SUB_ADDRESS;
+
+ offset = cdmaGetSubParameterOffset(BEARER_DATA_MSG_ID);
+
+// if(data != null && data.length > 2) {
+ int tmp = data[offset+2] & 0xff; // Skip the subParam ID and length, and read the first byte.
+ // Mask out the type
+ tmp &= 0x0f;
+ // Set the new type
+ tmp |= ((BearerData.MESSAGE_TYPE_DELIVER << 4) & 0xf0);
+ // Store the result
+ data[offset+2] = (byte) tmp;
+
+// }
+ /* TODO: Do we need to change anything in the user data? Not sure if the user data is
+ * just encoded using GSM encoding, or it is an actual GSM submit PDU embedded
+ * in the user data?
+ */
+
+ }
+
+ private static final byte TP_MIT_DELIVER = 0x00; // bit 0 and 1
+ private static final byte TP_MMS_NO_MORE = 0x04; // bit 2
+ private static final byte TP_RP_NO_REPLY_PATH = 0x00; // bit 7
+ private static final byte TP_UDHI_MASK = 0x40; // bit 6
+ private static final byte TP_SRI_NO_REPORT = 0x00; // bit 5
+
+ private int gsmSubmitGetTpPidOffset() {
+ /* calculate the offset to TP_PID.
+ * The TP-DA has variable length, and the length excludes the 2 byte length and type headers.
+ * The TP-DA is two bytes within the PDU */
+ int offset = 2 + ((data[2]+1) & 0xff)/2 + 2; // data[2] is the number of semi-octets in the phone number (ceil result)
+ if((offset > data.length) || (offset > (2 + 12))) // max length of TP_DA is 12 bytes + two byte offset.
+ throw new IllegalArgumentException("wrongly formatted gsm submit PDU. offset = " + offset);
+ return offset;
+ }
+
+ public int gsmSubmitGetTpDcs() {
+ return data[gsmSubmitGetTpDcsOffset()] & 0xff;
+ }
+
+ public boolean gsmSubmitHasUserDataHeader() {
+ return ((data[0] & 0xff) & TP_UDHI_MASK) == TP_UDHI_MASK;
+ }
+
+ private int gsmSubmitGetTpDcsOffset() {
+ return gsmSubmitGetTpPidOffset() + 1;
+ }
+
+ private int gsmSubmitGetTpUdlOffset() {
+ switch(((data[0] & 0xff) & (0x08 | 0x04))>>2) {
+ case 0: // Not TP-VP present
+ return gsmSubmitGetTpPidOffset() + 2;
+ case 1: // TP-VP relative format
+ return gsmSubmitGetTpPidOffset() + 2 + 1;
+ case 2: // TP-VP enhanced format
+ case 3: // TP-VP absolute format
+ break;
+ }
+ return gsmSubmitGetTpPidOffset() + 2 + 7;
+ }
+ private int gsmSubmitGetTpUdOffset() {
+ return gsmSubmitGetTpUdlOffset() + 1;
+ }
+
+ public void gsmDecodeUserDataHeader() {
+ ByteArrayInputStream pdu = new ByteArrayInputStream(data);
+
+ pdu.skip(gsmSubmitGetTpUdlOffset());
+ int userDataLength = pdu.read();
+ if(gsmSubmitHasUserDataHeader() == true) {
+ int userDataHeaderLength = pdu.read();
+
+ // This part is only needed to extract the language info, hence only needed for 7 bit encoding
+ if(encoding == SmsConstants.ENCODING_7BIT)
+ {
+ byte[] udh = new byte[userDataHeaderLength];
+ try {
+ pdu.read(udh);
+ } catch (IOException e) {
+ Log.w(TAG, "unable to read userDataHeader", e);
+ }
+ SmsHeader userDataHeader = SmsHeader.fromByteArray(udh);
+ languageTable = userDataHeader.languageTable;
+ languageShiftTable = userDataHeader.languageShiftTable;
+
+ int headerBits = (userDataHeaderLength + 1) * 8;
+ int headerSeptets = headerBits / 7;
+ headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
+ userDataSeptetPadding = (headerSeptets * 7) - headerBits;
+ msgSeptetCount = userDataLength - headerSeptets;
+ }
+ userDataMsgOffset = gsmSubmitGetTpUdOffset() + userDataHeaderLength + 1; // Add the byte containing the length
+ }
+ else
+ {
+ userDataSeptetPadding = 0;
+ msgSeptetCount = userDataLength;
+ userDataMsgOffset = gsmSubmitGetTpUdOffset();
+ }
+ if(V) {
+ Log.v(TAG, "encoding:" + encoding);
+ Log.v(TAG, "msgSeptetCount:" + msgSeptetCount);
+ Log.v(TAG, "userDataSeptetPadding:" + userDataSeptetPadding);
+ Log.v(TAG, "languageShiftTable:" + languageShiftTable);
+ Log.v(TAG, "languageTable:" + languageTable);
+ Log.v(TAG, "userDataMsgOffset:" + userDataMsgOffset);
+ }
+ }
+
+ private void gsmWriteDate(ByteArrayOutputStream header, long time) throws UnsupportedEncodingException {
+ SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss");
+ Date date = new Date(time);
+ String timeStr = format.format(date); // Format to YYMMDDTHHMMSS UTC time
+ if(V) Log.v(TAG, "Generated time string: " + timeStr);
+ byte[] timeChars = timeStr.getBytes("US-ASCII");
+
+ for(int i = 0, n = timeStr.length(); i < n; i+=2) {
+ header.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();
+ header.write((offsetChars[1]-0x30) << 4 | 0x40 | (offsetChars[0]-0x30));
+ }
+ else {
+ offsetString = String.format("%1$02d", offset);
+ char[] offsetChars = offsetString.toCharArray();
+ header.write((offsetChars[1]-0x30) << 4 | (offsetChars[0]-0x30));
+ }
+ }
+
+/* private void gsmSubmitExtractUserData() {
+ int userDataLength = data[gsmSubmitGetTpUdlOffset()];
+ userData = new byte[userDataLength];
+ System.arraycopy(userData, 0, data, gsmSubmitGetTpUdOffset(), userDataLength);
+
+ }*/
+
+ /**
+ * Change the GSM Submit Pdu data in this object to a deliver PDU:
+ * - Build the new header with deliver PDU type, originator and time stamp.
+ * - Extract encoding details from the submit PDU
+ * - Extract user data length and user data from the submitPdu
+ * - Build the new PDU
+ * @param date the time stamp to include (The value is the number of milliseconds since Jan. 1, 1970 GMT.)
+ * @param originator the phone number to include in the deliver PDU header. Any undesired characters,
+ * such as '-' will be striped from this string.
+ */
+ public void gsmChangeToDeliverPdu(long date, String originator)
+ {
+ ByteArrayOutputStream newPdu = new ByteArrayOutputStream(22); // 22 is the max length of the deliver pdu header
+ byte[] encodedAddress;
+ int userDataLength = 0;
+ try {
+ newPdu.write(TP_MIT_DELIVER | TP_MMS_NO_MORE | TP_RP_NO_REPLY_PATH | TP_SRI_NO_REPORT
+ | (data[0] & 0xff) & TP_UDHI_MASK);
+ encodedAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(originator);
+ if(encodedAddress != null) {
+ int padding = (encodedAddress[encodedAddress.length-1] & 0xf0) == 0xf0 ? 1 : 0;
+ encodedAddress[0] = (byte)((encodedAddress[0]-1)*2 - padding); // Convert from octet length to semi octet length
+ // Insert originator address into the header - this includes the length
+ newPdu.write(encodedAddress);
+ } else {
+ newPdu.write(0); /* zero length */
+ newPdu.write(0x81); /* International type */
+ }
+
+ newPdu.write(data[gsmSubmitGetTpPidOffset()]);
+ newPdu.write(data[gsmSubmitGetTpDcsOffset()]);
+ // Generate service center time stamp
+ gsmWriteDate(newPdu, date);
+ userDataLength = (data[gsmSubmitGetTpUdlOffset()] & 0xff);
+ newPdu.write(userDataLength);
+ // Copy the pdu user data - keep in mind that the userDataLength is not the length in bytes for 7-bit encoding.
+ newPdu.write(data, gsmSubmitGetTpUdOffset(), data.length - gsmSubmitGetTpUdOffset());
+ } catch (IOException e) {
+ Log.e(TAG, "", e);
+ throw new IllegalArgumentException("Failed to change type to deliver PDU.");
+ }
+ data = newPdu.toByteArray();
+ }
+
+ /* SMS encoding to bmessage strings */
+ /** get the encoding type as a bMessage string */
+ public String getEncodingString(){
+ if(type == SMS_TYPE_GSM)
+ {
+ switch(encoding){
+ case SmsMessage.ENCODING_7BIT:
+ if(languageTable == 0)
+ return "G-7BIT";
+ else
+ return "G-7BITEXT";
+ case SmsMessage.ENCODING_8BIT:
+ return "G-8BIT";
+ case SmsMessage.ENCODING_16BIT:
+ return "G-16BIT";
+ case SmsMessage.ENCODING_UNKNOWN:
+ default:
+ return "";
+ }
+ } else /* SMS_TYPE_CDMA */ {
+ switch(encoding){
+ case SmsMessage.ENCODING_7BIT:
+ return "C-7ASCII";
+ case SmsMessage.ENCODING_8BIT:
+ return "C-8BIT";
+ case SmsMessage.ENCODING_16BIT:
+ return "C-UNICODE";
+ case SmsMessage.ENCODING_KSC5601:
+ return "C-KOREAN";
+ case SmsMessage.ENCODING_UNKNOWN:
+ default:
+ return "";
+ }
+ }
+ }
+ }
+
+ private static int sConcatenatedRef = new Random().nextInt(256);
+
+ protected static int getNextConcatenatedRef() {
+ sConcatenatedRef += 1;
+ return sConcatenatedRef;
+ }
+ public static ArrayList<SmsPdu> getSubmitPdus(String messageText, String address){
+ /* Use the generic GSM/CDMA SMS Message functionality within Android to generate the
+ * SMS PDU's as once generated to send the SMS message.
+ */
+
+ int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); // TODO: Change to use: ((TelephonyManager)myContext.getSystemService(Context.TELEPHONY_SERVICE))
+ int phoneType;
+ GsmAlphabet.TextEncodingDetails ted = (PHONE_TYPE_CDMA == activePhone) ?
+ com.android.internal.telephony.cdma.SmsMessage.calculateLength((CharSequence)messageText, false) :
+ com.android.internal.telephony.gsm.SmsMessage.calculateLength((CharSequence)messageText, false);
+
+ SmsPdu newPdu;
+ String destinationAddress;
+ int msgCount = ted.msgCount;
+ int encoding;
+ int languageTable;
+ int languageShiftTable;
+ int refNumber = getNextConcatenatedRef() & 0x00FF;
+ ArrayList<String> smsFragments = SmsMessage.fragmentText(messageText);
+ ArrayList<SmsPdu> pdus = new ArrayList<SmsPdu>(msgCount);
+ byte[] data;
+
+ // Default to GSM, as this code should not be used, if we neither have CDMA not GSM.
+ phoneType = (activePhone == PHONE_TYPE_CDMA) ? SMS_TYPE_CDMA : SMS_TYPE_GSM;
+ encoding = ted.codeUnitSize;
+ languageTable = ted.languageTable;
+ languageShiftTable = ted.languageShiftTable;
+ destinationAddress = PhoneNumberUtils.stripSeparators(address);
+ if(destinationAddress == null || destinationAddress.length() < 2) {
+ destinationAddress = "12"; // Ensure we add a number at least 2 digits as specified in the GSM spec.
+ }
+
+ if(msgCount == 1){
+ data = SmsMessage.getSubmitPdu(null, destinationAddress, smsFragments.get(0), false).encodedMessage;
+ newPdu = new SmsPdu(data, encoding, phoneType, languageTable);
+ pdus.add(newPdu);
+ }
+ else
+ {
+ /* This code is a reduced copy of the actual code used in the Android SMS sub system,
+ * hence the comments have been left untouched. */
+ for(int i = 0; i < msgCount; i++){
+ SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
+ concatRef.refNumber = refNumber;
+ concatRef.seqNumber = i + 1; // 1-based sequence
+ concatRef.msgCount = msgCount;
+ // We currently set this to true since our messaging app will never
+ // send more than 255 parts (it converts the message to MMS well before that).
+ // However, we should support 3rd party messaging apps that might need 16-bit
+ // references
+ // Note: It's not sufficient to just flip this bit to true; it will have
+ // ripple effects (several calculations assume 8-bit ref).
+ concatRef.isEightBits = true;
+ SmsHeader smsHeader = new SmsHeader();
+ smsHeader.concatRef = concatRef;
+
+ /* Depending on the type, call either GSM or CDMA getSubmitPdu(). The encoding
+ * will be determined(again) by getSubmitPdu().
+ * All packets need to be encoded using the same encoding, as the bMessage
+ * only have one filed to describe the encoding for all messages in a concatenated
+ * SMS... */
+ if (encoding == SmsConstants.ENCODING_7BIT) {
+ smsHeader.languageTable = languageTable;
+ smsHeader.languageShiftTable = languageShiftTable;
+ }
+
+ if(phoneType == SMS_TYPE_GSM){
+ data = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, destinationAddress,
+ smsFragments.get(i), false, SmsHeader.toByteArray(smsHeader),
+ encoding, languageTable, languageShiftTable).encodedMessage;
+ } else { // SMS_TYPE_CDMA
+ UserData uData = new UserData();
+ uData.payloadStr = smsFragments.get(i);
+ uData.userDataHeader = smsHeader;
+ if (encoding == SmsConstants.ENCODING_7BIT) {
+ uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
+ } else { // assume UTF-16
+ uData.msgEncoding = UserData.ENCODING_UNICODE_16;
+ }
+ uData.msgEncodingSet = true;
+ data = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(destinationAddress,
+ uData, false).encodedMessage;
+ }
+ newPdu = new SmsPdu(data, encoding, phoneType, languageTable);
+ pdus.add(newPdu);
+ }
+ }
+
+ return pdus;
+ }
+
+ /**
+ * Generate a list of deliver PDUs. The messageText and address parameters must be different from null,
+ * for CDMA the date can be omitted (and will be ignored if supplied)
+ * @param messageText The text to include.
+ * @param address The originator address.
+ * @param date The delivery time stamp.
+ * @return
+ */
+ public static ArrayList<SmsPdu> getDeliverPdus(String messageText, String address, long date){
+ ArrayList<SmsPdu> deliverPdus = getSubmitPdus(messageText, address);
+
+ /*
+ * For CDMA the only difference between deliver and submit pdus are the messageType,
+ * which is set in encodeMessageId, (the higher 4 bits of the 1st byte
+ * of the Message identification sub parameter data.) and the address type.
+ *
+ * For GSM, a larger part of the header needs to be generated.
+ */
+ for(SmsPdu currentPdu : deliverPdus){
+ if(currentPdu.getType() == SMS_TYPE_CDMA){
+ currentPdu.cdmaChangeToDeliverPdu(date);
+ } else { /* SMS_TYPE_GSM */
+ currentPdu.gsmChangeToDeliverPdu(date, address);
+ }
+ }
+
+ return deliverPdus;
+ }
+
+ public static void testSendRawPdu(SmsPdu pdu){
+ if(pdu.getType() == SMS_TYPE_CDMA){
+ /* TODO: Try to send the message using SmsManager.sendData()?*/
+ }else {
+
+ }
+ }
+
+ /**
+ * The decoding only supports decoding the actual textual content of the PDU received
+ * from the MAP client. (As the Android system has no interface to send pre encoded PDUs)
+ * The destination address must be extracted from the bmessage vCard(s).
+ */
+ public static String decodePdu(byte[] data, int type) {
+ String ret;
+ if(type == SMS_TYPE_CDMA) {
+ /* This is able to handle both submit and deliver PDUs */
+ ret = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(0, data).getMessageBody();
+ } else {
+ /* For GSM, there is no submit pdu decoder, and most parser utils are private, and only minded for submit pdus */
+ ret = gsmParseSubmitPdu(data);
+ }
+ return ret;
+ }
+
+ /* At the moment we do not support using a SC-address. Use this function to strip off
+ * the SC-address before parsing it to the SmsPdu. (this was added in errata 4335)
+ */
+ private static byte[] gsmStripOffScAddress(byte[] data) {
+ /* The format of a native GSM SMS is: <sc-address><pdu> where sc-address is:
+ * <length-byte><type-byte><number-bytes> */
+ int addressLength = data[0] & 0xff; // Treat the byte value as an unsigned value
+ if(addressLength >= data.length) // We could verify that the address-length is no longer than 11 bytes
+ throw new IllegalArgumentException("Length of address exeeds the length of the PDU data.");
+ int pduLength = data.length-(1+addressLength);
+ byte[] newData = new byte[pduLength];
+ System.arraycopy(data, 1+addressLength, newData, 0, pduLength);
+ return newData;
+ }
+
+ private static String gsmParseSubmitPdu(byte[] data) {
+ /* Things to do:
+ * - extract hasUsrData bit
+ * - extract TP-DCS -> Character set, compressed etc.
+ * - extract user data header to get the language properties
+ * - extract user data
+ * - decode the string */
+ //Strip off the SC-address before parsing
+ SmsPdu pdu = new SmsPdu(gsmStripOffScAddress(data), SMS_TYPE_GSM);
+ boolean userDataCompressed = false;
+ int dataCodingScheme = pdu.gsmSubmitGetTpDcs();
+ int encodingType = SmsConstants.ENCODING_UNKNOWN;
+ String messageBody = null;
+
+ // Look up the data encoding scheme
+ if ((dataCodingScheme & 0x80) == 0) {
+ // Bits 7..4 == 0xxx
+ userDataCompressed = (0 != (dataCodingScheme & 0x20));
+
+ if (userDataCompressed) {
+ Log.w(TAG, "4 - Unsupported SMS data coding scheme "
+ + "(compression) " + (dataCodingScheme & 0xff));
+ } else {
+ switch ((dataCodingScheme >> 2) & 0x3) {
+ case 0: // GSM 7 bit default alphabet
+ encodingType = SmsConstants.ENCODING_7BIT;
+ break;
+
+ case 2: // UCS 2 (16bit)
+ encodingType = SmsConstants.ENCODING_16BIT;
+ break;
+
+ case 1: // 8 bit data
+ case 3: // reserved
+ Log.w(TAG, "1 - Unsupported SMS data coding scheme "
+ + (dataCodingScheme & 0xff));
+ encodingType = SmsConstants.ENCODING_8BIT;
+ break;
+ }
+ }
+ } else if ((dataCodingScheme & 0xf0) == 0xf0) {
+ userDataCompressed = false;
+
+ if (0 == (dataCodingScheme & 0x04)) {
+ // GSM 7 bit default alphabet
+ encodingType = SmsConstants.ENCODING_7BIT;
+ } else {
+ // 8 bit data
+ encodingType = SmsConstants.ENCODING_8BIT;
+ }
+ } else if ((dataCodingScheme & 0xF0) == 0xC0
+ || (dataCodingScheme & 0xF0) == 0xD0
+ || (dataCodingScheme & 0xF0) == 0xE0) {
+ // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
+
+ // 0xC0 == 7 bit, don't store
+ // 0xD0 == 7 bit, store
+ // 0xE0 == UCS-2, store
+
+ if ((dataCodingScheme & 0xF0) == 0xE0) {
+ encodingType = SmsConstants.ENCODING_16BIT;
+ } else {
+ encodingType = SmsConstants.ENCODING_7BIT;
+ }
+
+ userDataCompressed = false;
+
+ // bit 0x04 reserved
+ } else if ((dataCodingScheme & 0xC0) == 0x80) {
+ // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
+ // 0x80..0xBF == Reserved coding groups
+ if (dataCodingScheme == 0x84) {
+ // This value used for KSC5601 by carriers in Korea.
+ encodingType = SmsConstants.ENCODING_KSC5601;
+ } else {
+ Log.w(TAG, "5 - Unsupported SMS data coding scheme "
+ + (dataCodingScheme & 0xff));
+ }
+ } else {
+ Log.w(TAG, "3 - Unsupported SMS data coding scheme "
+ + (dataCodingScheme & 0xff));
+ }
+
+ /* TODO: This is NOT good design - to have the pdu class being depending on these two function calls.
+ * - move the encoding extraction into the pdu class */
+ pdu.setEncoding(encodingType);
+ pdu.gsmDecodeUserDataHeader();
+
+ try {
+ switch (encodingType) {
+ case SmsConstants.ENCODING_UNKNOWN:
+ case SmsConstants.ENCODING_8BIT:
+ Log.w(TAG, "Unknown encoding type: " + encodingType);
+ messageBody = null;
+ break;
+
+ case SmsConstants.ENCODING_7BIT:
+ messageBody = GsmAlphabet.gsm7BitPackedToString(pdu.getData(), pdu.getUserDataMsgOffset(),
+ pdu.getMsgSeptetCount(), pdu.getUserDataSeptetPadding(), pdu.getLanguageTable(),
+ pdu.getLanguageShiftTable());
+ Log.i(TAG, "Decoded as 7BIT: " + messageBody);
+
+ break;
+
+ case SmsConstants.ENCODING_16BIT:
+ messageBody = new String(pdu.getData(), pdu.getUserDataMsgOffset(), pdu.getUserDataMsgSize(), "utf-16");
+ Log.i(TAG, "Decoded as 16BIT: " + messageBody);
+ break;
+
+ case SmsConstants.ENCODING_KSC5601:
+ messageBody = new String(pdu.getData(), pdu.getUserDataMsgOffset(), pdu.getUserDataMsgSize(), "KSC5601");
+ Log.i(TAG, "Decoded as KSC5601: " + messageBody);
+ break;
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Unsupported encoding type???", e); // This should never happen.
+ return null;
+ }
+
+ return messageBody;
+ }
+
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapUtils.java b/src/com/android/bluetooth/map/BluetoothMapUtils.java
new file mode 100644
index 0000000..e57cf16
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapUtils.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+
+/**
+ * Various utility methods and generic defines that can be used throughout MAPS
+ */
+public class BluetoothMapUtils {
+
+ private static final String TAG = "MapUtils";
+ private static final boolean V = BluetoothMapService.VERBOSE;
+ /* We use the upper 5 bits for the type mask - avoid using the top bit, since it
+ * indicates a negative value, hence corrupting the formatter when converting to
+ * type String. (I really miss the unsigned type in Java:))
+ */
+ private static final long HANDLE_TYPE_MASK = 0xf<<59;
+ private static final long HANDLE_TYPE_MMS_MASK = 0x1<<59;
+ private static final long HANDLE_TYPE_EMAIL_MASK = 0x2<<59;
+ private static final long HANDLE_TYPE_SMS_GSM_MASK = 0x4<<59;
+ private static final long HANDLE_TYPE_SMS_CDMA_MASK = 0x8<<59;
+
+ /**
+ * This enum is used to convert from the bMessage type property to a type safe
+ * type. Hence do not change the names of the enum values.
+ */
+ public enum TYPE{
+ EMAIL,
+ SMS_GSM,
+ SMS_CDMA,
+ MMS
+ }
+
+ /**
+ * Convert a Content Provider handle and a Messagetype into a unique handle
+ * @param cpHandle content provider handle
+ * @param messageType message type (TYPE_MMS/TYPE_SMS_GSM/TYPE_SMS_CDMA/TYPE_EMAIL)
+ * @return String Formatted Map Handle
+ */
+ static public String getMapHandle(long cpHandle, TYPE messageType){
+ String mapHandle = "-1";
+ switch(messageType)
+ {
+ case MMS:
+ mapHandle = String.format("%016X",(cpHandle | HANDLE_TYPE_MMS_MASK));
+ break;
+ case SMS_GSM:
+ mapHandle = String.format("%016X",cpHandle | HANDLE_TYPE_SMS_GSM_MASK);
+ break;
+ case SMS_CDMA:
+ mapHandle = String.format("%016X",cpHandle | HANDLE_TYPE_SMS_CDMA_MASK);
+ break;
+ case EMAIL:
+ mapHandle = String.format("%016X",(cpHandle | HANDLE_TYPE_EMAIL_MASK)); //TODO correct when email support is implemented
+ break;
+ default:
+ throw new IllegalArgumentException("Message type not supported");
+ }
+ return mapHandle;
+
+ }
+
+ /**
+ * Convert a handle string the the raw long representation, including the type bit.
+ * @param mapHandle the handle string
+ * @return the handle value
+ */
+ static public long getMsgHandleAsLong(String mapHandle){
+ return Long.parseLong(mapHandle, 16);
+ }
+ /**
+ * Convert a Map Handle into a content provider Handle
+ * @param mapHandle handle to convert from
+ * @return content provider handle without message type mask
+ */
+ static public long getCpHandle(String mapHandle)
+ {
+ long cpHandle = getMsgHandleAsLong(mapHandle);
+ /* remove masks as the call should already know what type of message this handle is for */
+ cpHandle &= ~HANDLE_TYPE_MASK;
+ return cpHandle;
+ }
+
+ /**
+ * Extract the message type from the handle.
+ * @param mapHandle
+ * @return
+ */
+ static public TYPE getMsgTypeFromHandle(String mapHandle) {
+ long cpHandle = getMsgHandleAsLong(mapHandle);
+
+ if((cpHandle & HANDLE_TYPE_MMS_MASK) != 0)
+ return TYPE.MMS;
+ if((cpHandle & HANDLE_TYPE_EMAIL_MASK) != 0)
+ return TYPE.EMAIL;
+ if((cpHandle & HANDLE_TYPE_SMS_GSM_MASK) != 0)
+ return TYPE.SMS_GSM;
+ if((cpHandle & HANDLE_TYPE_SMS_CDMA_MASK) != 0)
+ return TYPE.SMS_CDMA;
+
+ throw new IllegalArgumentException("Message type not found in handle string.");
+ }
+}
+
diff --git a/src/com/android/bluetooth/map/BluetoothMapbMessage.java b/src/com/android/bluetooth/map/BluetoothMapbMessage.java
new file mode 100644
index 0000000..de3de66
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapbMessage.java
@@ -0,0 +1,876 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+import android.os.Environment;
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+
+public abstract class BluetoothMapbMessage {
+
+ protected static String TAG = "BluetoothMapbMessage";
+ protected static final boolean D = false;
+ protected static final boolean V = false;
+ private static final String VERSION = "VERSION:1.0";
+
+ public static int INVALID_VALUE = -1;
+
+ protected int appParamCharset = BluetoothMapAppParams.INVALID_VALUE_PARAMETER;
+
+ // TODO: Reevaluate if strings are the best types for the members.
+
+ /* BMSG attributes */
+ private String status = null; // READ/UNREAD
+ protected TYPE type = null; // SMS/MMS/EMAIL
+
+ private String folder = null;
+
+ /* BBODY attributes */
+ private long partId = INVALID_VALUE;
+ protected String encoding = null;
+ protected String charset = null;
+ private String language = null;
+
+ private int bMsgLength = INVALID_VALUE;
+
+ private ArrayList<vCard> originator = null;
+ private ArrayList<vCard> recipient = null;
+
+
+ public static class vCard {
+ /* VCARD attributes */
+ private String version;
+ private String name = null;
+ private String formattedName = null;
+ private String[] phoneNumbers = {};
+ private String[] emailAddresses = {};
+ private int envLevel = 0;
+
+ /**
+ * Construct a version 3.0 vCard
+ * @param name Structured
+ * @param formattedName Formatted name
+ * @param phoneNumbers a String[] of phone numbers
+ * @param emailAddresses a String[] of email addresses
+ * @param the bmessage envelope level (0 is the top/most outer level)
+ */
+ public vCard(String name, String formattedName, String[] phoneNumbers,
+ String[] emailAddresses, int envLevel) {
+ this.envLevel = envLevel;
+ this.version = "3.0";
+ this.name = name != null ? name : "";
+ this.formattedName = formattedName != null ? formattedName : "";
+ setPhoneNumbers(phoneNumbers);
+ if (emailAddresses != null)
+ this.emailAddresses = emailAddresses;
+ }
+
+ /**
+ * Construct a version 2.1 vCard
+ * @param name Structured name
+ * @param phoneNumbers a String[] of phone numbers
+ * @param emailAddresses a String[] of email addresses
+ * @param the bmessage envelope level (0 is the top/most outer level)
+ */
+ public vCard(String name, String[] phoneNumbers,
+ String[] emailAddresses, int envLevel) {
+ this.envLevel = envLevel;
+ this.version = "2.1";
+ this.name = name != null ? name : "";
+ setPhoneNumbers(phoneNumbers);
+ if (emailAddresses != null)
+ this.emailAddresses = emailAddresses;
+ }
+
+ /**
+ * Construct a version 3.0 vCard
+ * @param name Structured name
+ * @param formattedName Formatted name
+ * @param phoneNumbers a String[] of phone numbers
+ * @param emailAddresses a String[] of email addresses
+ */
+ public vCard(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) {
+ this.version = "3.0";
+ this.name = name != null ? name : "";
+ this.formattedName = formattedName != null ? formattedName : "";
+ setPhoneNumbers(phoneNumbers);
+ if (emailAddresses != null)
+ this.emailAddresses = emailAddresses;
+ }
+
+ /**
+ * Construct a version 2.1 vCard
+ * @param name Structured Name
+ * @param phoneNumbers a String[] of phone numbers
+ * @param emailAddresses a String[] of email addresses
+ */
+ public vCard(String name, String[] phoneNumbers, String[] emailAddresses) {
+ this.version = "2.1";
+ this.name = name != null ? name : "";
+ setPhoneNumbers(phoneNumbers);
+ if (emailAddresses != null)
+ this.emailAddresses = emailAddresses;
+ }
+
+ private void setPhoneNumbers(String[] numbers) {
+ if(numbers != null && numbers.length > 0)
+ {
+ phoneNumbers = new String[numbers.length];
+ for(int i = 0, n = numbers.length; i < n; i++){
+ phoneNumbers[i] = PhoneNumberUtils.extractNetworkPortion(numbers[i]);
+ }
+ }
+ }
+
+ public String getFirstPhoneNumber() {
+ if(phoneNumbers.length > 0) {
+ return phoneNumbers[0];
+ } else
+ throw new IllegalArgumentException("No Phone number");
+ }
+
+ public int getEnvLevel() {
+ return envLevel;
+ }
+
+ public void encode(StringBuilder sb)
+ {
+ sb.append("BEGIN:VCARD").append("\r\n");
+ sb.append("VERSION:").append(version).append("\r\n");
+ if(version.equals("3.0") && formattedName != null)
+ {
+ sb.append("FN:").append(formattedName).append("\r\n");
+ }
+ if (name != null)
+ sb.append("N:").append(name).append("\r\n");
+ for(String phoneNumber : phoneNumbers)
+ {
+ sb.append("TEL:").append(phoneNumber).append("\r\n");
+ }
+ for(String emailAddress : emailAddresses)
+ {
+ sb.append("EMAIL:").append(emailAddress).append("\r\n");
+ }
+ sb.append("END:VCARD").append("\r\n");
+ }
+
+ /**
+ * Parse a vCard from a BMgsReader, where a line containing "BEGIN:VCARD" have just been read.
+ * @param reader
+ * @param originator
+ * @return
+ */
+ public static vCard parseVcard(BMsgReader reader, int envLevel) {
+ String formattedName = null;
+ String name = null;
+ ArrayList<String> phoneNumbers = null;
+ ArrayList<String> emailAddresses = null;
+ String[] parts;
+ String line = reader.getLineEnforce();
+
+ while(!line.contains("END:VCARD")) {
+ line = line.trim();
+ if(line.startsWith("N:")){
+ parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':'
+ if(parts.length == 2) {
+ name = parts[1];
+ } else
+ name = "";
+ }
+ else if(line.startsWith("FN:")){
+ parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':'
+ if(parts.length == 2) {
+ formattedName = parts[1];
+ } else
+ formattedName = "";
+ }
+ else if(line.startsWith("TEL:")){
+ parts = line.split("[^\\\\]:"); // Split on "un-escaped" ':'
+ if(parts.length == 2) {
+ String[] subParts = parts[1].split("[^\\\\];");
+ if(phoneNumbers == null)
+ phoneNumbers = new ArrayList<String>(1);
+ phoneNumbers.add(subParts[subParts.length-1]); // only keep actual phone number
+ } else {}
+ // Empty phone number - ignore
+ }
+ else if(line.startsWith("EMAIL:")){
+ parts = line.split("[^\\\\]:"); // Split on "un-escaped" :
+ if(parts.length == 2) {
+ String[] subParts = parts[1].split("[^\\\\];");
+ if(emailAddresses == null)
+ emailAddresses = new ArrayList<String>(1);
+ emailAddresses.add(subParts[subParts.length-1]); // only keep actual email address
+ } else {}
+ // Empty email address entry - ignore
+ }
+ line = reader.getLineEnforce();
+ }
+ return new vCard(name, formattedName,
+ phoneNumbers == null? null : phoneNumbers.toArray(new String[phoneNumbers.size()]),
+ emailAddresses == null ? null : emailAddresses.toArray(new String[emailAddresses.size()]),
+ envLevel);
+ }
+ };
+
+ private static class BMsgReader {
+ InputStream mInStream;
+ public BMsgReader(InputStream is)
+ {
+ this.mInStream = is;
+ }
+
+ private byte[] getLineAsBytes() {
+ int readByte;
+
+ /* TODO: Actually the vCard spec. allows to break lines by using a newLine
+ * followed by a white space character(space or tab). Not sure this is a good idea to implement
+ * as the Bluetooth MAP spec. illustrates vCards using tab alignment, hence actually
+ * showing an invalid vCard format...
+ * If we read such a folded line, the folded part will be skipped in the parser
+ */
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ try {
+ while ((readByte = mInStream.read()) != -1) {
+ if (readByte == '\r') {
+ if ((readByte = mInStream.read()) != -1 && readByte == '\n') {
+ if(output.size() == 0)
+ continue; /* Skip empty lines */
+ else
+ break;
+ } else {
+ output.write('\r');
+ }
+ } else if (readByte == '\n' && output.size() == 0) {
+ /* Empty line - skip */
+ continue;
+ }
+
+ output.write(readByte);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ return null;
+ }
+ return output.toByteArray();
+ }
+
+ /**
+ * Read a line of text from the BMessage.
+ * @return the next line of text, or null at end of file, or if UTF-8 is not supported.
+ */
+ public String getLine() {
+ try {
+ byte[] line = getLineAsBytes();
+ if (line.length == 0)
+ return null;
+ else
+ return new String(line, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, e);
+ return null;
+ }
+ }
+
+ /**
+ * same as getLine(), but throws an exception, if we run out of lines.
+ * Use this function when ever more lines are needed for the bMessage to be complete.
+ * @return the next line
+ */
+ public String getLineEnforce() {
+ String line = getLine();
+ if (line == null)
+ throw new IllegalArgumentException("Bmessage too short");
+
+ return line;
+ }
+
+
+ /**
+ * Reads a line from the InputStream, and examines if the subString
+ * matches the line read.
+ * @param subString
+ * The string to match against the line.
+ * @throws IllegalArgumentException
+ * If the expected substring is not found.
+ *
+ */
+ public void expect(String subString) throws IllegalArgumentException{
+ String line = getLine();
+ if(line == null || subString == null){
+ throw new IllegalArgumentException("Line or substring is null");
+ }else if(!line.toUpperCase().contains(subString.toUpperCase()))
+ throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\"");
+ }
+
+ /**
+ * Same as expect(String), but with two strings.
+ * @param subString
+ * @param subString2
+ * @throws IllegalArgumentException
+ * If one or all of the strings are not found.
+ */
+ public void expect(String subString, String subString2) throws IllegalArgumentException{
+ String line = getLine();
+ if(!line.toUpperCase().contains(subString.toUpperCase()))
+ throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\"");
+ if(!line.toUpperCase().contains(subString2.toUpperCase()))
+ throw new IllegalArgumentException("Expected \"" + subString + "\" in: \"" + line + "\"");
+ }
+
+ /**
+ * Read a part of the bMessage as raw data.
+ * @param length the number of bytes to read
+ * @return the byte[] containing the number of bytes or null if an error occurs or EOF is reached
+ * before length bytes have been read.
+ */
+ public byte[] getDataBytes(int length) {
+ byte[] data = new byte[length];
+ try {
+ int bytesRead;
+ int offset=0;
+ while ((bytesRead = mInStream.read(data, offset, length-offset)) != (length - offset)) {
+ if(bytesRead == -1)
+ return null;
+ offset += bytesRead;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ return null;
+ }
+ return data;
+ }
+ };
+
+ public BluetoothMapbMessage(){
+
+ }
+
+ public static BluetoothMapbMessage parse(InputStream bMsgStream, int appParamCharset) throws IllegalArgumentException{
+ BMsgReader reader;
+ String line = "";
+ BluetoothMapbMessage newBMsg = null;
+ boolean status = false;
+ boolean statusFound = false;
+ TYPE type = null;
+ String folder = null;
+
+ /* This section is used for debug. It will write the incoming message to a file on the SD-card,
+ * hence should only be used for test/debug.
+ * If an error occurs, it will result in a OBEX_HTTP_PRECON_FAILED to be send to the client,
+ * even though the message might be formatted correctly, hence only enable this code for test. */
+ if(V) {
+ /* Read the entire stream into a file on the SD card*/
+ File sdCard = Environment.getExternalStorageDirectory();
+ File dir = new File (sdCard.getAbsolutePath() + "/bluetooth/log/");
+ dir.mkdirs();
+ File file = new File(dir, "receivedBMessage.txt");
+ FileOutputStream outStream = null;
+ boolean failed = false;
+ int writtenLen = 0;
+
+ try {
+ outStream = new FileOutputStream(file, false); /* overwrite if it does already exist */
+
+ byte[] buffer = new byte[4*1024];
+ int len = 0;
+ while ((len = bMsgStream.read(buffer)) > 0) {
+ outStream.write(buffer, 0, len);
+ writtenLen += len;
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG,"Unable to create output stream",e);
+ } catch (IOException e) {
+ Log.e(TAG,"Failed to copy the received message",e);
+ if(writtenLen != 0)
+ failed = true; /* We failed to write the complete file, hence the received message is lost... */
+ } finally {
+ if(outStream != null)
+ try {
+ outStream.close();
+ } catch (IOException e) {
+ }
+ }
+
+ /* Return if we corrupted the incoming bMessage. */
+ if(failed) {
+ throw new IllegalArgumentException(); /* terminate this function with an error. */
+ }
+
+ if (outStream == null) {
+ /* We failed to create the the log-file, just continue using the original bMsgStream. */
+ } else {
+ /* overwrite the bMsgStream using the file written to the SD-Card */
+ try {
+ bMsgStream.close();
+ } catch (IOException e) {
+ /* Ignore if we cannot close the stream. */
+ }
+ /* Open the file and overwrite bMsgStream to read from the file */
+ try {
+ bMsgStream = new FileInputStream(file);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG,"Failed to open the bMessage file", e);
+ throw new IllegalArgumentException(); /* terminate this function with an error. */
+ }
+ }
+ Log.i(TAG, "The incoming bMessage have been dumped to " + file.getAbsolutePath());
+ } /* End of if(V) log-section */
+
+ reader = new BMsgReader(bMsgStream);
+ reader.expect("BEGIN:BMSG");
+ reader.expect("VERSION","1.0");
+
+ line = reader.getLineEnforce();
+ // Parse the properties - which end with either a VCARD or a BENV
+ while(!line.contains("BEGIN:VCARD") && !line.contains("BEGIN:BENV")) {
+ if(line.contains("STATUS")){
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ if (arg[1].trim().equals("READ")) {
+ status = true;
+ } else if (arg[1].trim().equals("UNREAD")) {
+ status =false;
+ } else {
+ throw new IllegalArgumentException("Wrong value in 'STATUS': " + arg[1]);
+ }
+ } else {
+ throw new IllegalArgumentException("Missing value for 'STATUS': " + line);
+ }
+ }
+ if(line.contains("TYPE")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ String value = arg[1].trim();
+ type = TYPE.valueOf(value); // Will throw IllegalArgumentException if value is wrong
+ if(appParamCharset == BluetoothMapAppParams.CHARSET_NATIVE
+ && type != TYPE.SMS_CDMA && type != TYPE.SMS_GSM) {
+ throw new IllegalArgumentException("Native appParamsCharset only supported for SMS");
+ }
+ switch(type) {
+ case SMS_CDMA:
+ case SMS_GSM:
+ newBMsg = new BluetoothMapbMessageSms();
+ break;
+ case MMS:
+ case EMAIL:
+ newBMsg = new BluetoothMapbMessageMmsEmail();
+ break;
+ default:
+ break;
+ }
+ } else {
+ throw new IllegalArgumentException("Missing value for 'TYPE':" + line);
+ }
+ }
+ if(line.contains("FOLDER")) {
+ String[] arg = line.split(":");
+ if (arg != null && arg.length == 2) {
+ folder = arg[1].trim();
+ }
+ // This can be empty for push message - hence ignore if there is no value
+ }
+ line = reader.getLineEnforce();
+ }
+ if(newBMsg == null)
+ throw new IllegalArgumentException("Missing bMessage TYPE: - unable to parse body-content");
+ newBMsg.setType(type);
+ newBMsg.appParamCharset = appParamCharset;
+ if(folder != null)
+ newBMsg.setCompleteFolder(folder);
+ if(statusFound)
+ newBMsg.setStatus(status);
+
+ // Now check for originator VCARDs
+ while(line.contains("BEGIN:VCARD")){
+ if(D) Log.d(TAG,"Decoding vCard");
+ newBMsg.addOriginator(vCard.parseVcard(reader,0));
+ line = reader.getLineEnforce();
+ }
+ if(line.contains("BEGIN:BENV")) {
+ newBMsg.parseEnvelope(reader, 0);
+ } else
+ throw new IllegalArgumentException("Bmessage has no BEGIN:BENV - line:" + line);
+
+ /* TODO: Do we need to validate the END:* tags? They are only needed if someone puts additional info
+ * below the END:MSG - in which case we don't handle it.
+ */
+
+ try {
+ bMsgStream.close();
+ } catch (IOException e) {
+ /* Ignore if we cannot close the stream. */
+ }
+
+ return newBMsg;
+ }
+
+ private void parseEnvelope(BMsgReader reader, int level) {
+ String line;
+ line = reader.getLineEnforce();
+ if(D) Log.d(TAG,"Decoding envelope level " + level);
+
+ while(line.contains("BEGIN:VCARD")){
+ if(D) Log.d(TAG,"Decoding recipient vCard level " + level);
+ if(recipient == null)
+ recipient = new ArrayList<vCard>(1);
+ recipient.add(vCard.parseVcard(reader, level));
+ line = reader.getLineEnforce();
+ }
+ if(line.contains("BEGIN:BENV")) {
+ if(D) Log.d(TAG,"Decoding nested envelope");
+ parseEnvelope(reader, ++level); // Nested BENV
+ }
+ if(line.contains("BEGIN:BBODY")){
+ if(D) Log.d(TAG,"Decoding bbody");
+ parseBody(reader);
+ }
+ }
+
+ private void parseBody(BMsgReader reader) {
+ String line;
+ line = reader.getLineEnforce();
+ while(!line.contains("END:")) {
+ if(line.contains("PARTID:")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ try {
+ partId = Long.parseLong(arg[1].trim());
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Wrong value in 'PARTID': " + arg[1]);
+ }
+ } else {
+ throw new IllegalArgumentException("Missing value for 'PARTID': " + line);
+ }
+ }
+ else if(line.contains("ENCODING:")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ encoding = arg[1].trim(); // TODO: Validate ?
+ } else {
+ throw new IllegalArgumentException("Missing value for 'ENCODING': " + line);
+ }
+ }
+ else if(line.contains("CHARSET:")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ charset = arg[1].trim(); // TODO: Validate ?
+ } else {
+ throw new IllegalArgumentException("Missing value for 'CHARSET': " + line);
+ }
+ }
+ else if(line.contains("LANGUAGE:")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ language = arg[1].trim(); // TODO: Validate ?
+ } else {
+ throw new IllegalArgumentException("Missing value for 'LANGUAGE': " + line);
+ }
+ }
+ else if(line.contains("LENGTH:")) {
+ String arg[] = line.split(":");
+ if (arg != null && arg.length == 2) {
+ try {
+ bMsgLength = Integer.parseInt(arg[1].trim());
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Wrong value in 'LENGTH': " + arg[1]);
+ }
+ } else {
+ throw new IllegalArgumentException("Missing value for 'LENGTH': " + line);
+ }
+ }
+ else if(line.contains("BEGIN:MSG")) {
+ if(bMsgLength == INVALID_VALUE)
+ throw new IllegalArgumentException("Missing value for 'LENGTH'. Unable to read remaining part of the message");
+ // For SMS: Encoding of MSG is always UTF-8 compliant, regardless of any properties, since PDUs are encodes as hex-strings
+ /* PTS has a bug regarding the message length, and sets it 2 bytes too short, hence
+ * using the length field to determine the amount of data to read, might not be the
+ * best solution.
+ * Since errata ???(bluetooth.org is down at the moment) introduced escaping of END:MSG
+ * in the actual message content, it is now safe to use the END:MSG tag as terminator,
+ * and simply ignore the length field.*/
+ byte[] rawData = reader.getDataBytes(bMsgLength - (line.getBytes().length + 2)); // 2 added to compensate for the removed \r\n
+ String data;
+ try {
+ data = new String(rawData, "UTF-8");
+ if(V) {
+ Log.v(TAG,"MsgLength: " + bMsgLength);
+ Log.v(TAG,"line.getBytes().length: " + line.getBytes().length);
+ String debug = line.replaceAll("\\n", "<LF>\n");
+ debug = debug.replaceAll("\\r", "<CR>");
+ Log.v(TAG,"The line: \"" + debug + "\"");
+ debug = data.replaceAll("\\n", "<LF>\n");
+ debug = debug.replaceAll("\\r", "<CR>");
+ Log.v(TAG,"The msgString: \"" + debug + "\"");
+ }
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG,e);
+ throw new IllegalArgumentException("Unable to convert to UTF-8");
+ }
+ /* Decoding of MSG:
+ * 1) split on "\r\nEND:MSG\r\n"
+ * 2) delete "BEGIN:MSG\r\n" for each msg
+ * 3) replace any occurrence of "\END:MSG" with "END:MSG"
+ * 4) based on charset from application properties either store as String[] or decode to raw PDUs
+ * */
+ String messages[] = data.split("\r\nEND:MSG\r\n");
+ parseMsgInit();
+ for(int i = 0; i < messages.length; i++) {
+ messages[i] = messages[i].replaceFirst("^BEGIN:MSG\r\n", "");
+ messages[i] = messages[i].replaceAll("\r\n([/]*)/END\\:MSG", "\r\n$1END:MSG");
+ messages[i] = messages[i].trim();
+ parseMsgPart(messages[i]);
+ }
+ }
+ line = reader.getLineEnforce();
+ }
+ }
+
+ /**
+ * Parse the 'message' part of <bmessage-body-content>"
+ * @param msgPart
+ */
+ public abstract void parseMsgPart(String msgPart);
+ /**
+ * Set initial values before parsing - will be called is a message body is found
+ * during parsing.
+ */
+ public abstract void parseMsgInit();
+
+ public abstract byte[] encode() throws UnsupportedEncodingException;
+
+ public void setStatus(boolean read) {
+ if(read)
+ this.status = "READ";
+ else
+ this.status = "UNREAD";
+ }
+
+ public void setType(TYPE type) {
+ this.type = type;
+ }
+
+ /**
+ * @return the type
+ */
+ public TYPE getType() {
+ return type;
+ }
+
+ public void setCompleteFolder(String folder) {
+ this.folder = folder;
+ }
+
+ public void setFolder(String folder) {
+ this.folder = "telecom/msg/" + folder;
+ }
+
+ public String getFolder() {
+ return folder;
+ }
+
+
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ public ArrayList<vCard> getOriginators() {
+ return originator;
+ }
+
+ public void addOriginator(vCard originator) {
+ if(this.originator == null)
+ this.originator = new ArrayList<vCard>();
+ this.originator.add(originator);
+ }
+
+ /**
+ * Add a version 3.0 vCard with a formatted name
+ * @param name e.g. Bonde;Casper
+ * @param formattedName e.g. "Casper Bonde"
+ * @param phoneNumbers
+ * @param emailAddresses
+ */
+ public void addOriginator(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) {
+ if(originator == null)
+ originator = new ArrayList<vCard>();
+ originator.add(new vCard(name, formattedName, phoneNumbers, emailAddresses));
+ }
+
+ /** Add a version 2.1 vCard with only a name.
+ *
+ * @param name e.g. Bonde;Casper
+ * @param phoneNumbers
+ * @param emailAddresses
+ */
+ public void addOriginator(String name, String[] phoneNumbers, String[] emailAddresses) {
+ if(originator == null)
+ originator = new ArrayList<vCard>();
+ originator.add(new vCard(name, phoneNumbers, emailAddresses));
+ }
+
+ public ArrayList<vCard> getRecipients() {
+ return recipient;
+ }
+
+ public void setRecipient(vCard recipient) {
+ if(this.recipient == null)
+ this.recipient = new ArrayList<vCard>();
+ this.recipient.add(recipient);
+ }
+
+ public void addRecipient(String name, String formattedName, String[] phoneNumbers, String[] emailAddresses) {
+ if(recipient == null)
+ recipient = new ArrayList<vCard>();
+ recipient.add(new vCard(name, formattedName, phoneNumbers, emailAddresses));
+ }
+
+ public void addRecipient(String name, String[] phoneNumbers, String[] emailAddresses) {
+ if(recipient == null)
+ recipient = new ArrayList<vCard>();
+ recipient.add(new vCard(name, phoneNumbers, emailAddresses));
+ }
+
+ /**
+ * Convert a byte[] of data to a hex string representation, converting each nibble to the corresponding
+ * hex char.
+ * NOTE: There is not need to escape instances of "\r\nEND:MSG" in the binary data represented as a string
+ * as only the characters [0-9] and [a-f] is used.
+ * @param pduData the byte-array of data.
+ * @param scAddressData the byte-array of the encoded sc-Address.
+ * @return the resulting string.
+ */
+ protected String encodeBinary(byte[] pduData, byte[] scAddressData) {
+ StringBuilder out = new StringBuilder((pduData.length + scAddressData.length)*2);
+ for(int i = 0; i < scAddressData.length; i++) {
+ out.append(Integer.toString((scAddressData[i] >> 4) & 0x0f,16)); // MS-nibble first
+ out.append(Integer.toString( scAddressData[i] & 0x0f,16));
+ }
+ for(int i = 0; i < pduData.length; i++) {
+ out.append(Integer.toString((pduData[i] >> 4) & 0x0f,16)); // MS-nibble first
+ out.append(Integer.toString( pduData[i] & 0x0f,16));
+ /*out.append(Integer.toHexString(data[i]));*/ /* This is the same as above, but does not include the needed 0's
+ e.g. it converts the value 3 to "3" and not "03" */
+ }
+ return out.toString();
+ }
+
+ /**
+ * Decodes a binary hex-string encoded UTF-8 string to the represented binary data set.
+ * @param data The string representation of the data - must have an even number of characters.
+ * @return the byte[] represented in the data.
+ */
+ protected byte[] decodeBinary(String data) {
+ byte[] out = new byte[data.length()/2];
+ String value;
+ if(D) Log.d(TAG,"Decoding binary data: START:" + data + ":END");
+ for(int i = 0, j = 0, n = out.length; i < n; i++)
+ {
+ value = data.substring(j++, ++j); // same as data.substring(2*i, 2*i+1+1) - substring() uses end-1 for last index
+ out[i] = (byte)(Integer.valueOf(value, 16) & 0xff);
+ }
+ if(D) {
+ StringBuilder sb = new StringBuilder(out.length);
+ for(int i = 0, n = out.length; i < n; i++)
+ {
+ sb.append(String.format("%02X",out[i] & 0xff));
+ }
+ Log.d(TAG,"Decoded binary data: START:" + sb.toString() + ":END");
+ }
+ return out;
+ }
+
+ public byte[] encodeGeneric(ArrayList<byte[]> bodyFragments) throws UnsupportedEncodingException
+ {
+ StringBuilder sb = new StringBuilder(256);
+ byte[] msgStart, msgEnd;
+ sb.append("BEGIN:BMSG").append("\r\n");
+ sb.append(VERSION).append("\r\n");
+ sb.append("STATUS:").append(status).append("\r\n");
+ sb.append("TYPE:").append(type.name()).append("\r\n");
+ if(folder.length() > 512)
+ sb.append("FOLDER:").append(folder.substring(folder.length()-512, folder.length())).append("\r\n");
+ else
+ sb.append("FOLDER:").append(folder).append("\r\n");
+ if(originator != null){
+ for(vCard element : originator)
+ element.encode(sb);
+ }
+ /* TODO: Do we need the three levels of env? - e.g. for e-mail. - we do have a level in the
+ * vCards that could be used to determine the the levels of the envelope.
+ */
+
+ sb.append("BEGIN:BENV").append("\r\n");
+ if(recipient != null){
+ for(vCard element : recipient)
+ element.encode(sb);
+ }
+ sb.append("BEGIN:BBODY").append("\r\n");
+ if(encoding != null && encoding != "")
+ sb.append("ENCODING:").append(encoding).append("\r\n");
+ if(charset != null && charset != "")
+ sb.append("CHARSET:").append(charset).append("\r\n");
+
+
+ int length = 0;
+ /* 22 is the length of the 'BEGIN:MSG' and 'END:MSG' + 3*CRLF */
+ for (byte[] fragment : bodyFragments) {
+ length += fragment.length + 22;
+ }
+ sb.append("LENGTH:").append(length).append("\r\n");
+
+ // Extract the initial part of the bMessage string
+ msgStart = sb.toString().getBytes("UTF-8");
+
+ sb = new StringBuilder(31);
+ sb.append("END:BBODY").append("\r\n");
+ sb.append("END:BENV").append("\r\n");
+ sb.append("END:BMSG").append("\r\n");
+
+ msgEnd = sb.toString().getBytes("UTF-8");
+
+ try {
+
+ ByteArrayOutputStream stream = new ByteArrayOutputStream(msgStart.length + msgEnd.length + length);
+ stream.write(msgStart);
+
+ for (byte[] fragment : bodyFragments) {
+ stream.write("BEGIN:MSG\r\n".getBytes("UTF-8"));
+ stream.write(fragment);
+ stream.write("\r\nEND:MSG\r\n".getBytes("UTF-8"));
+ }
+ stream.write(msgEnd);
+
+ if(V) Log.v(TAG,stream.toString("UTF-8"));
+ return stream.toByteArray();
+ } catch (IOException e) {
+ Log.w(TAG,e);
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java b/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java
new file mode 100644
index 0000000..0f1feac
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java
@@ -0,0 +1,638 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Locale;
+import java.util.UUID;
+
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
+import android.util.Base64;
+import android.util.Log;
+
+public class BluetoothMapbMessageMmsEmail extends BluetoothMapbMessage {
+
+ public static class MimePart {
+ public long _id = INVALID_VALUE; /* The _id from the content provider, can be used to sort the parts if needed */
+ public String contentType = null; /* The mime type, e.g. text/plain */
+ public String contentId = null;
+ public String contentLocation = null;
+ public String contentDisposition = null;
+ public String partName = null; /* e.g. text_1.txt*/
+ public String charsetName = null; /* This seems to be a number e.g. 106 for UTF-8 CharacterSets
+ holds a method for the mapping. */
+ public String fileName = null; /* Do not seem to be used */
+ public byte[] data = null; /* The raw un-encoded data e.g. the raw jpeg data or the text.getBytes("utf-8") */
+
+
+
+ public void encode(StringBuilder sb, String boundaryTag, boolean last) throws UnsupportedEncodingException {
+ sb.append("--").append(boundaryTag).append("\r\n");
+ if(contentType != null)
+ sb.append("Content-Type: ").append(contentType);
+ if(charsetName != null)
+ sb.append("; ").append("charset=\"").append(charsetName).append("\"");
+ sb.append("\r\n");
+ if(contentLocation != null)
+ sb.append("Content-Location: ").append(contentLocation).append("\r\n");
+ if(contentId != null)
+ sb.append("Content-ID: ").append(contentId).append("\r\n");
+ if(contentDisposition != null)
+ sb.append("Content-Disposition: ").append(contentDisposition).append("\r\n");
+ if(data != null) {
+ /* TODO: If errata 4176 is adopted in the current form (it is not in either 1.1 or 1.2),
+ the below is not allowed, Base64 should be used for text. */
+
+ if(contentType != null &&
+ (contentType.toUpperCase().contains("TEXT") ||
+ contentType.toUpperCase().contains("SMIL") )) {
+ sb.append("Content-Transfer-Encoding: 8BIT\r\n\r\n"); // Add the header split empty line
+ sb.append(new String(data,"UTF-8")).append("\r\n");
+ }
+ else {
+ sb.append("Content-Transfer-Encoding: Base64\r\n\r\n"); // Add the header split empty line
+ sb.append(Base64.encodeToString(data, Base64.DEFAULT)).append("\r\n");
+ }
+ }
+ if(last) {
+ sb.append("--").append(boundaryTag).append("--").append("\r\n");
+ }
+ }
+
+ public void encodePlainText(StringBuilder sb) throws UnsupportedEncodingException {
+ if(contentType != null && contentType.toUpperCase().contains("TEXT")) {
+ sb.append(new String(data,"UTF-8")).append("\r\n");
+ } else if(contentType != null && contentType.toUpperCase().contains("/SMIL")) {
+ /* Skip the smil.xml, as no-one knows what it is. */
+ } else {
+ /* Not a text part, just print the filename or part name if they exist. */
+ if(partName != null)
+ sb.append("<").append(partName).append(">\r\n");
+ else
+ sb.append("<").append("attachment").append(">\r\n");
+ }
+ }
+ }
+
+ private long date = INVALID_VALUE;
+ private String subject = null;
+ private ArrayList<Rfc822Token> from = null; // Shall not be empty
+ private ArrayList<Rfc822Token> sender = null; // Shall not be empty
+ private ArrayList<Rfc822Token> to = null; // Shall not be empty
+ private ArrayList<Rfc822Token> cc = null; // Can be empty
+ private ArrayList<Rfc822Token> bcc = null; // Can be empty
+ private ArrayList<Rfc822Token> replyTo = null;// Can be empty
+ private String messageId = null;
+ private ArrayList<MimePart> parts = null;
+ private String contentType = null;
+ private String boundary = null;
+ private boolean textOnly = false;
+ private boolean includeAttachments;
+ private boolean hasHeaders = false;
+ private String encoding = null;
+
+ private String getBoundary() {
+ if(boundary == null)
+ boundary = "----" + UUID.randomUUID();
+ return boundary;
+ }
+
+ /**
+ * @return the parts
+ */
+ public ArrayList<MimePart> getMimeParts() {
+ return parts;
+ }
+
+ public MimePart addMimePart() {
+ if(parts == null)
+ parts = new ArrayList<BluetoothMapbMessageMmsEmail.MimePart>();
+ MimePart newPart = new MimePart();
+ parts.add(newPart);
+ return newPart;
+ }
+ public String getDateString() {
+ SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
+ Date dateObj = new Date(date);
+ return format.format(dateObj); // Format according to RFC 2822 page 14
+ }
+ public long getDate() {
+ return date;
+ }
+ public void setDate(long date) {
+ this.date = date;
+ }
+ public String getSubject() {
+ return subject;
+ }
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+ public ArrayList<Rfc822Token> getFrom() {
+ return from;
+ }
+ public void setFrom(ArrayList<Rfc822Token> from) {
+ this.from = from;
+ }
+ public void addFrom(String name, String address) {
+ if(this.from == null)
+ this.from = new ArrayList<Rfc822Token>(1);
+ this.from.add(new Rfc822Token(name, address, null));
+ }
+ public ArrayList<Rfc822Token> getSender() {
+ return sender;
+ }
+ public void setSender(ArrayList<Rfc822Token> sender) {
+ this.sender = sender;
+ }
+ public void addSender(String name, String address) {
+ if(this.sender == null)
+ this.sender = new ArrayList<Rfc822Token>(1);
+ this.sender.add(new Rfc822Token(name,address,null));
+ }
+ public ArrayList<Rfc822Token> getTo() {
+ return to;
+ }
+ public void setTo(ArrayList<Rfc822Token> to) {
+ this.to = to;
+ }
+ public void addTo(String name, String address) {
+ if(this.to == null)
+ this.to = new ArrayList<Rfc822Token>(1);
+ this.to.add(new Rfc822Token(name, address, null));
+ }
+ public ArrayList<Rfc822Token> getCc() {
+ return cc;
+ }
+ public void setCc(ArrayList<Rfc822Token> cc) {
+ this.cc = cc;
+ }
+ public void addCc(String name, String address) {
+ if(this.cc == null)
+ this.cc = new ArrayList<Rfc822Token>(1);
+ this.cc.add(new Rfc822Token(name, address, null));
+ }
+ public ArrayList<Rfc822Token> getBcc() {
+ return bcc;
+ }
+ public void setBcc(ArrayList<Rfc822Token> bcc) {
+ this.bcc = bcc;
+ }
+ public void addBcc(String name, String address) {
+ if(this.bcc == null)
+ this.bcc = new ArrayList<Rfc822Token>(1);
+ this.bcc.add(new Rfc822Token(name, address, null));
+ }
+ public ArrayList<Rfc822Token> getReplyTo() {
+ return replyTo;
+ }
+ public void setReplyTo(ArrayList<Rfc822Token> replyTo) {
+ this.replyTo = replyTo;
+ }
+ public void addReplyTo(String name, String address) {
+ if(this.replyTo == null)
+ this.replyTo = new ArrayList<Rfc822Token>(1);
+ this.replyTo.add(new Rfc822Token(name, address, null));
+ }
+ public void setMessageId(String messageId) {
+ this.messageId = messageId;
+ }
+ public String getMessageId() {
+ return messageId;
+ }
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+ public String getContentType() {
+ return contentType;
+ }
+ public void setTextOnly(boolean textOnly) {
+ this.textOnly = textOnly;
+ }
+ public boolean getTextOnly() {
+ return textOnly;
+ }
+ public void setIncludeAttachments(boolean includeAttachments) {
+ this.includeAttachments = includeAttachments;
+ }
+ public boolean getIncludeAttachments() {
+ return includeAttachments;
+ }
+ public void updateCharset() {
+ charset = null;
+ for(MimePart part : parts) {
+ if(part.contentType != null &&
+ part.contentType.toUpperCase().contains("TEXT")) {
+ charset = "UTF-8";
+ break;
+ }
+ }
+ }
+ public int getSize() {
+ int message_size = 0;
+ for(MimePart part : parts) {
+ message_size += part.data.length;
+ }
+ return message_size;
+ }
+
+ /**
+ * Encode an address header, and perform folding if needed.
+ * @param sb The stringBuilder to write to
+ * @param headerName The RFC 2822 header name
+ * @param addresses the reformatted address substrings to encode.
+ */
+ public void encodeHeaderAddresses(StringBuilder sb, String headerName,
+ ArrayList<Rfc822Token> addresses) {
+ /* TODO: Do we need to encode the addresses if they contain illegal characters?
+ * This depends of the outcome of errata 4176. The current spec. states to use UTF-8
+ * where possible, but the RFCs states to use US-ASCII for the headers - hence encoding
+ * would be needed to support non US-ASCII characters. But the MAP spec states not to
+ * use any encoding... */
+ int partLength, lineLength = 0;
+ lineLength += headerName.getBytes().length;
+ sb.append(headerName);
+ for(Rfc822Token address : addresses) {
+ partLength = address.toString().getBytes().length+1;
+ // Add folding if needed
+ if(lineLength + partLength >= 998) // max line length in RFC2822
+ {
+ sb.append("\r\n "); // Append a FWS (folding whitespace)
+ lineLength = 0;
+ }
+ sb.append(address.toString()).append(";");
+ lineLength += partLength;
+ }
+ sb.append("\r\n");
+ }
+
+ public void encodeHeaders(StringBuilder sb) throws UnsupportedEncodingException
+ {
+ /* TODO: From RFC-4356 - about the RFC-(2)822 headers:
+ * "Current Internet Message format requires that only 7-bit US-ASCII
+ * characters be present in headers. Non-7-bit characters in an address
+ * domain must be encoded with [IDN]. If there are any non-7-bit
+ * characters in the local part of an address, the message MUST be
+ * rejected. Non-7-bit characters elsewhere in a header MUST be encoded
+ * according to [Hdr-Enc]."
+ * We need to add the address encoding in encodeHeaderAddresses, but it is not
+ * straight forward, as it is unclear how to do this. */
+ if (date != INVALID_VALUE)
+ sb.append("Date: ").append(getDateString()).append("\r\n");
+ /* According to RFC-2822 headers must use US-ASCII, where the MAP specification states
+ * UTF-8 should be used for the entire <bmessage-body-content>. We let the MAP specification
+ * take precedence above the RFC-2822. The code to
+ */
+ /* If we are to use US-ASCII anyway, here are the code for it.
+ if (subject != null){
+ // Use base64 encoding for the subject, as it may contain non US-ASCII characters or other
+ // illegal (RFC822 header), and android do not seem to have encoders/decoders for quoted-printables
+ sb.append("Subject:").append("=?utf-8?B?");
+ sb.append(Base64.encodeToString(subject.getBytes("utf-8"), Base64.DEFAULT));
+ sb.append("?=\r\n");
+ }*/
+ if (subject != null)
+ sb.append("Subject: ").append(subject).append("\r\n");
+ if(from != null)
+ encodeHeaderAddresses(sb, "From: ", from); // This includes folding if needed.
+ if(sender != null)
+ encodeHeaderAddresses(sb, "Sender: ", sender); // This includes folding if needed.
+ /* For MMS one recipient(to, cc or bcc) must exists, if none: 'To: undisclosed-
+ * recipients:;' could be used.
+ * TODO: Is this a valid solution for E-Mail?
+ */
+ if(to == null && cc == null && bcc == null)
+ sb.append("To: undisclosed-recipients:;\r\n");
+ if(to != null)
+ encodeHeaderAddresses(sb, "To: ", to); // This includes folding if needed.
+ if(cc != null)
+ encodeHeaderAddresses(sb, "Cc: ", cc); // This includes folding if needed.
+ if(bcc != null)
+ encodeHeaderAddresses(sb, "Bcc: ", bcc); // This includes folding if needed.
+ if(replyTo != null)
+ encodeHeaderAddresses(sb, "Reply-To: ", replyTo); // This includes folding if needed.
+ if(includeAttachments == true)
+ {
+ if(messageId != null)
+ sb.append("Message-Id: ").append(messageId).append("\r\n");
+ if(contentType != null)
+ sb.append("Content-Type: ").append(contentType).append("; boundary=").append(getBoundary()).append("\r\n");
+ }
+ sb.append("\r\n"); // If no headers exists, we still need two CRLF, hence keep it out of the if above.
+ }
+
+ /* Notes on MMS
+ * ------------
+ * According to rfc4356 all headers of a MMS converted to an E-mail must use
+ * 7-bit encoding. According the the MAP specification only 8-bit encoding is
+ * allowed - hence the bMessage-body should contain no SMTP headers. (Which makes
+ * sense, since the info is already present in the bMessage properties.)
+ * The result is that no information from RFC4356 is needed, since it does not
+ * describe any mapping between MMS content and E-mail content.
+ * Suggestion:
+ * Clearly state in the MAP specification that
+ * only the actual message content should be included in the <bmessage-body-content>.
+ * Correct the Example to not include the E-mail headers, and in stead show how to
+ * include a picture or another binary attachment.
+ *
+ * If the headers should be included, clearly state which, as the example clearly shows
+ * that some of the headers should be excluded.
+ * Additionally it is not clear how to handle attachments. There is a parameter in the
+ * get message to include attachments, but since only 8-bit encoding is allowed,
+ * (hence neither base64 nor binary) there is no mechanism to embed the attachment in
+ * the <bmessage-body-content>.
+ *
+ * UPDATE: Errata 4176 allows the needed encoding typed inside the <bmessage-body-content>
+ * including Base64 and Quoted Printables - hence it is possible to encode non-us-ascii
+ * messages - e.g. pictures and utf-8 strings with non-us-ascii content.
+ * It have not yet been adopted, but since the comments clearly suggest that it is allowed
+ * to use encoding schemes for non-text parts, it is still not clear what to do about non
+ * US-ASCII text in the headers.
+ * */
+
+ /**
+ * Encode the bMessage as a MMS
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public byte[] encodeMms() throws UnsupportedEncodingException
+ {
+ ArrayList<byte[]> bodyFragments = new ArrayList<byte[]>();
+ StringBuilder sb = new StringBuilder();
+ int count = 0;
+ String mmsBody;
+
+ encoding = "8BIT"; // The encoding used
+
+ encodeHeaders(sb);
+ if(getIncludeAttachments() == false) {
+ for(MimePart part : parts) {
+ part.encodePlainText(sb); /* We call encode on all parts, to include a tag, where an attachment is missing. */
+ }
+ } else {
+ for(MimePart part : parts) {
+ count++;
+ part.encode(sb, getBoundary(), (count == parts.size()));
+ }
+ }
+
+ mmsBody = sb.toString();
+
+ if(mmsBody != null) {
+ String tmpBody = mmsBody.replaceAll("END:MSG", "/END\\:MSG"); // Replace any occurrences of END:MSG with \END:MSG
+ bodyFragments.add(tmpBody.getBytes("UTF-8"));
+ } else {
+ bodyFragments.add(new byte[0]);
+ }
+
+ return encodeGeneric(bodyFragments);
+ }
+
+
+ /**
+ * Try to parse the hdrPart string as e-mail headers.
+ * @param hdrPart The string to parse.
+ * @return Null if the entire string were e-mail headers. The part of the string in which
+ * no headers were found.
+ */
+ private String parseMmsHeaders(String hdrPart) {
+ String[] headers = hdrPart.split("\r\n");
+ String header;
+ hasHeaders = false;
+
+ for(int i = 0, c = headers.length; i < c; i++) {
+ header = headers[i];
+
+ /* We need to figure out if any headers are present, in cases where devices do not follow the e-mail RFCs.
+ * Skip empty lines, and then parse headers until a non-header line is found, at which point we treat the
+ * remaining as plain text.
+ */
+ if(header.trim() == "")
+ continue;
+ String[] headerParts = header.split(":",2);
+ if(headerParts.length != 2) {
+ // We treat the remaining content as plain text.
+ StringBuilder remaining = new StringBuilder();
+ for(; i < c; i++)
+ remaining.append(headers[i]);
+
+ return remaining.toString();
+ }
+
+ String headerType = headerParts[0].toUpperCase();
+ String headerValue = headerParts[1].trim();
+
+ // Address headers
+ /* TODO: If this is empty, the MSE needs to fill it in before sending the message.
+ * This happens when sending the MMS, not sure what happens for e-mail.
+ */
+ if(headerType.contains("FROM")) {
+ Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(headerValue);
+ from = new ArrayList<Rfc822Token>(Arrays.asList(tokens));
+ }
+ else if(headerType.contains("TO")) {
+ Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(headerValue);
+ to = new ArrayList<Rfc822Token>(Arrays.asList(tokens));
+ }
+ else if(headerType.contains("CC")) {
+ Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(headerValue);
+ cc = new ArrayList<Rfc822Token>(Arrays.asList(tokens));
+ }
+ else if(headerType.contains("BCC")) {
+ Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(headerValue);
+ bcc = new ArrayList<Rfc822Token>(Arrays.asList(tokens));
+ }
+ else if(headerType.contains("REPLY-TO")) {
+ Rfc822Token tokens[] = Rfc822Tokenizer.tokenize(headerValue);
+ replyTo = new ArrayList<Rfc822Token>(Arrays.asList(tokens));
+ }// Other headers
+ else if(headerType.contains("SUBJECT")) {
+ subject = headerValue;
+ }
+ else if(headerType.contains("MESSAGE-ID")) {
+ messageId = headerValue;
+ }
+ else if(headerType.contains("DATE")) {
+ /* TODO: Do we need the date? */
+ }
+ else if(headerType.contains("CONTENT-TYPE")) {
+ String[] contentTypeParts = headerValue.split(";");
+ contentType = contentTypeParts[0];
+ // Extract the boundary if it exists
+ for(int j=1, n=contentTypeParts.length; j<n; j++)
+ {
+ if(contentTypeParts[j].contains("boundary")) {
+ boundary = contentTypeParts[j].split("boundary[\\s]*=", 2)[1].trim();
+ }
+ }
+ }
+ else if(headerType.contains("CONTENT-TRANSFER-ENCODING")) {
+ encoding = headerValue;
+ }
+ else {
+ if(D) Log.w(TAG,"Skipping unknown header: " + headerType + " (" + header + ")");
+ }
+ }
+ return null;
+ }
+
+ private void parseMmsMimePart(String partStr) {
+ String[] parts = partStr.split("\r\n\r\n", 2); // Split the header from the body
+ String body;
+ if(parts.length != 2) {
+ body = partStr;
+ } else {
+ body = parts[1];
+ }
+ String[] headers = parts[0].split("\r\n");
+ MimePart newPart = addMimePart();
+ String partEncoding = encoding; /* Use the overall encoding as default */
+
+ for(String header : headers) {
+ if(header.length() == 0)
+ continue;
+
+ if(header.trim() == "" || header.trim().equals("--")) // Skip empty lines(the \r\n after the boundary tag) and endBoundary tags
+ continue;
+ String[] headerParts = header.split(":",2);
+ if(headerParts.length != 2)
+ throw new IllegalArgumentException("part-Header not formatted correctly: " + header);
+ String headerType = headerParts[0].toUpperCase();
+ String headerValue = headerParts[1].trim();
+ if(headerType.contains("CONTENT-TYPE")) {
+ // TODO: extract charset? Only UTF-8 is allowed for TEXT typed parts
+ newPart.contentType = headerValue;
+ Log.d(TAG, "*** CONTENT-TYPE: " + newPart.contentType);
+ }
+ else if(headerType.contains("CONTENT-LOCATION")) {
+ // This is used if the smil refers to a file name in its src=
+ newPart.contentLocation = headerValue;
+ newPart.partName = headerValue;
+ }
+ else if(headerType.contains("CONTENT-TRANSFER-ENCODING")) {
+ partEncoding = headerValue;
+ }
+ else if(headerType.contains("CONTENT-ID")) {
+ // This is used if the smil refers to a cid:<xxx> in it's src=
+ newPart.contentId = headerValue;
+ }
+ else if(headerType.contains("CONTENT-DISPOSITION")) {
+ // This is used if the smil refers to a cid:<xxx> in it's src=
+ newPart.contentDisposition = headerValue;
+ }
+ else {
+ if(D) Log.w(TAG,"Skipping unknown part-header: " + headerType + " (" + header + ")");
+ }
+ }
+ // Now for the body
+ newPart.data = decodeBody(body, partEncoding);
+ }
+
+ private void parseMmsMimeBody(String body) {
+ MimePart newPart = addMimePart();
+ newPart.data = decodeBody(body, encoding);
+ }
+
+ private byte[] decodeBody(String body, String encoding) {
+ if(encoding != null && encoding.toUpperCase().contains("BASE64")) {
+ return Base64.decode(body, Base64.DEFAULT);
+ } else {
+ // TODO: handle other encoding types? - here we simply store the string data as bytes
+ try {
+ return body.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // This will never happen, as UTF-8 is mandatory on Android platforms
+ }
+ }
+ return null;
+ }
+
+ private void parseMms(String message) {
+ /* Overall strategy for decoding:
+ * 1) split on first empty line to extract the header
+ * 2) unfold and parse headers
+ * 3) split on boundary to split into parts (or use the remaining as a part,
+ * if part is not found)
+ * 4) parse each part
+ * */
+ String[] messageParts;
+ String[] mimeParts;
+ String remaining = null;
+ String messageBody = null;
+ message = message.replaceAll("\\r\\n[ \\\t]+", ""); // Unfold
+ messageParts = message.split("\r\n\r\n", 2); // Split the header from the body
+ if(messageParts.length != 2) {
+ // Handle entire message as plain text
+ messageBody = message;
+ }
+ else
+ {
+ remaining = parseMmsHeaders(messageParts[0]);
+ // If we have some text not being a header, add it to the message body.
+ if(remaining != null) {
+ messageBody = remaining + messageParts[1];
+ }
+ else {
+ messageBody = messageParts[1];
+ }
+ }
+
+ if(boundary == null)
+ {
+ // If the boundary is not set, handle as non-multi-part
+ parseMmsMimeBody(messageBody);
+ setTextOnly(true);
+ if(contentType == null)
+ contentType = "text/plain";
+ parts.get(0).contentType = contentType;
+ }
+ else
+ {
+ mimeParts = messageBody.split("--" + boundary);
+ for(int i = 0; i < mimeParts.length - 1; i++) {
+ String part = mimeParts[i];
+ if (part != null && (part.length() > 0))
+ parseMmsMimePart(part);
+ }
+ }
+ }
+
+ /* Notes on SMIL decoding (from http://tools.ietf.org/html/rfc2557):
+ * src="filename.jpg" refers to a part with Content-Location: filename.jpg
+ * src="cid:1234@hest.net" refers to a part with Content-ID:<1234@hest.net>*/
+ @Override
+ public void parseMsgPart(String msgPart) {
+ parseMms(msgPart);
+
+ }
+
+ @Override
+ public void parseMsgInit() {
+ // Not used for e-mail
+
+ }
+
+ @Override
+ public byte[] encode() throws UnsupportedEncodingException {
+ return encodeMms();
+ }
+
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMapbMessageSms.java b/src/com/android/bluetooth/map/BluetoothMapbMessageSms.java
new file mode 100644
index 0000000..8107bd8
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMapbMessageSms.java
@@ -0,0 +1,93 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapSmsPdu.SmsPdu;
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+
+public class BluetoothMapbMessageSms extends BluetoothMapbMessage {
+
+ private ArrayList<SmsPdu> smsBodyPdus = null;
+ private String smsBody = null;
+
+ public void setSmsBodyPdus(ArrayList<SmsPdu> smsBodyPdus) {
+ this.smsBodyPdus = smsBodyPdus;
+ this.charset = null;
+ if(smsBodyPdus.size() > 0)
+ this.encoding = smsBodyPdus.get(0).getEncodingString();
+ }
+
+ public String getSmsBody() {
+ return smsBody;
+ }
+
+ public void setSmsBody(String smsBody) {
+ this.smsBody = smsBody;
+ this.charset = "UTF-8";
+ this.encoding = null;
+ }
+
+ @Override
+ public void parseMsgPart(String msgPart) {
+ if(appParamCharset == BluetoothMapAppParams.CHARSET_NATIVE) {
+ if(D) Log.d(TAG, "Decoding \"" + msgPart + "\" as native PDU");
+ byte[] msgBytes = decodeBinary(msgPart);
+ if(msgBytes.length > 0 &&
+ msgBytes[0] < msgBytes.length-1 &&
+ (msgBytes[msgBytes[0]+1] & 0x03) != 0x01) {
+ if(D) Log.d(TAG, "Only submit PDUs are supported");
+ throw new IllegalArgumentException("Only submit PDUs are supported");
+ }
+
+ smsBody += BluetoothMapSmsPdu.decodePdu(msgBytes,
+ type == TYPE.SMS_CDMA ? BluetoothMapSmsPdu.SMS_TYPE_CDMA
+ : BluetoothMapSmsPdu.SMS_TYPE_GSM);
+ } else {
+ smsBody += msgPart;
+ }
+ }
+ @Override
+ public void parseMsgInit() {
+ smsBody = "";
+ }
+
+ public byte[] encode() throws UnsupportedEncodingException
+ {
+ ArrayList<byte[]> bodyFragments = new ArrayList<byte[]>();
+
+ /* Store the messages in an ArrayList to be able to handle the different message types in a generic way.
+ * We use byte[] since we need to extract the length in bytes.
+ */
+ if(smsBody != null) {
+ String tmpBody = smsBody.replaceAll("END:MSG", "/END\\:MSG"); // Replace any occurrences of END:MSG with \END:MSG
+ bodyFragments.add(tmpBody.getBytes("UTF-8"));
+ }else if (smsBodyPdus != null && smsBodyPdus.size() > 0) {
+ for (SmsPdu pdu : smsBodyPdus) {
+ // This cannot(must not) contain END:MSG
+ bodyFragments.add(encodeBinary(pdu.getData(),pdu.getScAddress()).getBytes("UTF-8"));
+ }
+ } else {
+ bodyFragments.add(new byte[0]); // TODO: Is this allowed? (An empty message)
+ }
+
+ return encodeGeneric(bodyFragments);
+ }
+
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMnsObexClient.java b/src/com/android/bluetooth/map/BluetoothMnsObexClient.java
new file mode 100644
index 0000000..544c621
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMnsObexClient.java
@@ -0,0 +1,371 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.obex.ApplicationParameter;
+import javax.obex.ClientOperation;
+import javax.obex.ClientSession;
+import javax.obex.HeaderSet;
+import javax.obex.ObexTransport;
+import javax.obex.ResponseCodes;
+
+/**
+ * The Message Notification Service class runs its own message handler thread,
+ * to avoid executing long operations on the MAP service Thread.
+ * This handler context is passed to the content observers,
+ * hence all call-backs (and thereby transmission of data) is executed
+ * from this thread.
+ */
+public class BluetoothMnsObexClient {
+
+ private static final String TAG = "BluetoothMnsObexClient";
+ private static final boolean D = false;
+ private static final boolean V = false;
+
+ private ObexTransport mTransport;
+ private Context mContext;
+ public Handler mHandler = null;
+ private volatile boolean mWaitingForRemote;
+ private static final String TYPE_EVENT = "x-bt/MAP-event-report";
+ private ClientSession mClientSession;
+ private boolean mConnected = false;
+ BluetoothDevice mRemoteDevice;
+ private BluetoothMapContentObserver mObserver;
+ private boolean mObserverRegistered = false;
+
+ // Used by the MAS to forward notification registrations
+ public static final int MSG_MNS_NOTIFICATION_REGISTRATION = 1;
+
+
+ public static final ParcelUuid BluetoothUuid_ObexMns =
+ ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+
+
+ public BluetoothMnsObexClient(Context context, BluetoothDevice remoteDevice) {
+ if (remoteDevice == null) {
+ throw new NullPointerException("Obex transport is null");
+ }
+ HandlerThread thread = new HandlerThread("BluetoothMnsObexClient");
+ thread.start();
+ Looper looper = thread.getLooper();
+ mHandler = new MnsObexClientHandler(looper);
+ mContext = context;
+ mRemoteDevice = remoteDevice;
+ mObserver = new BluetoothMapContentObserver(mContext);
+ mObserver.init();
+ }
+
+ public Handler getMessageHandler() {
+ return mHandler;
+ }
+
+ public BluetoothMapContentObserver getContentObserver() {
+ return mObserver;
+ }
+
+ private final class MnsObexClientHandler extends Handler {
+ private MnsObexClientHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_MNS_NOTIFICATION_REGISTRATION:
+ handleRegistration(msg.arg1 /*masId*/, msg.arg2 /*status*/);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ public boolean isConnected() {
+ return mConnected;
+ }
+
+ /**
+ * Disconnect the connection to MNS server.
+ * Call this when the MAS client requests a de-registration on events.
+ */
+ public void disconnect() {
+ try {
+ if (mClientSession != null) {
+ mClientSession.disconnect(null);
+ if (D) Log.d(TAG, "OBEX session disconnected");
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "OBEX session disconnect error " + e.getMessage());
+ }
+ try {
+ if (mClientSession != null) {
+ if (D) Log.d(TAG, "OBEX session close mClientSession");
+ mClientSession.close();
+ mClientSession = null;
+ if (D) Log.d(TAG, "OBEX session closed");
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "OBEX session close error:" + e.getMessage());
+ }
+ if (mTransport != null) {
+ try {
+ if (D) Log.d(TAG, "Close Obex Transport");
+ mTransport.close();
+ mTransport = null;
+ mConnected = false;
+ if (D) Log.d(TAG, "Obex Transport Closed");
+ } catch (IOException e) {
+ Log.e(TAG, "mTransport.close error: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Shutdown the MNS.
+ */
+ public void shutdown() {
+ /* should shutdown handler thread first to make sure
+ * handleRegistration won't be called when disconnet
+ */
+ if (mHandler != null) {
+ // Shut down the thread
+ mHandler.removeCallbacksAndMessages(null);
+ Looper looper = mHandler.getLooper();
+ if (looper != null) {
+ looper.quit();
+ }
+ mHandler = null;
+ }
+
+ /* Disconnect if connected */
+ disconnect();
+
+ if(mObserverRegistered) {
+ mObserver.unregisterObserver();
+ mObserverRegistered = false;
+ }
+ if (mObserver != null) {
+ mObserver.deinit();
+ mObserver = null;
+ }
+ }
+
+ private HeaderSet hsConnect = null;
+
+ public void handleRegistration(int masId, int notificationStatus){
+ Log.d(TAG, "handleRegistration( " + masId + ", " + notificationStatus + ")");
+
+ if((isConnected() == false) &&
+ (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES)) {
+ Log.d(TAG, "handleRegistration: connect");
+ connect();
+ }
+
+ if(notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_NO) {
+ // Unregister - should we disconnect, or keep the connection? - the spec. says nothing about this.
+ if(mObserverRegistered == true) {
+ mObserver.unregisterObserver();
+ mObserverRegistered = false;
+ disconnect();
+ }
+ } else if(notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
+ /* Connect if we do not have a connection, and start the content observers providing
+ * this thread as Handler.
+ */
+ if(mObserverRegistered == false) {
+ mObserver.registerObserver(this, masId);
+ mObserverRegistered = true;
+ }
+ }
+ }
+
+ public void connect() {
+ Log.d(TAG, "handleRegistration: connect 2");
+
+ BluetoothSocket btSocket = null;
+ try {
+ btSocket = mRemoteDevice.createInsecureRfcommSocketToServiceRecord(
+ BluetoothUuid_ObexMns.getUuid());
+ btSocket.connect();
+ } catch (IOException e) {
+ Log.e(TAG, "BtSocket Connect error " + e.getMessage(), e);
+ // TODO: do we need to report error somewhere?
+ return;
+ }
+
+ mTransport = new BluetoothMnsRfcommTransport(btSocket);
+
+ try {
+ mClientSession = new ClientSession(mTransport);
+ mConnected = true;
+ } catch (IOException e1) {
+ Log.e(TAG, "OBEX session create error " + e1.getMessage());
+ }
+ if (mConnected && mClientSession != null) {
+ mConnected = false;
+ HeaderSet hs = new HeaderSet();
+ // bb582b41-420c-11db-b0de-0800200c9a66
+ byte[] mnsTarget = { (byte) 0xbb, (byte) 0x58, (byte) 0x2b, (byte) 0x41,
+ (byte) 0x42, (byte) 0x0c, (byte) 0x11, (byte) 0xdb,
+ (byte) 0xb0, (byte) 0xde, (byte) 0x08, (byte) 0x00,
+ (byte) 0x20, (byte) 0x0c, (byte) 0x9a, (byte) 0x66 };
+ hs.setHeader(HeaderSet.TARGET, mnsTarget);
+
+ synchronized (this) {
+ mWaitingForRemote = true;
+ }
+ try {
+ hsConnect = mClientSession.connect(hs);
+ if (D) Log.d(TAG, "OBEX session created");
+ mConnected = true;
+ } catch (IOException e) {
+ Log.e(TAG, "OBEX session connect error " + e.getMessage());
+ }
+ }
+ synchronized (this) {
+ mWaitingForRemote = false;
+ }
+ }
+
+ public int sendEvent(byte[] eventBytes, int masInstanceId) {
+
+ boolean error = false;
+ int responseCode = -1;
+ HeaderSet request;
+ int maxChunkSize, bytesToWrite, bytesWritten = 0;
+ ClientSession clientSession = mClientSession;
+
+ if ((!mConnected) || (clientSession == null)) {
+ Log.w(TAG, "sendEvent after disconnect:" + mConnected);
+ return responseCode;
+ }
+
+ request = new HeaderSet();
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ appParams.setMasInstanceId(masInstanceId);
+
+ ClientOperation putOperation = null;
+ OutputStream outputStream = null;
+
+ try {
+ request.setHeader(HeaderSet.TYPE, TYPE_EVENT);
+ request.setHeader(HeaderSet.APPLICATION_PARAMETER, appParams.EncodeParams());
+
+ if (hsConnect.mConnectionID != null) {
+ request.mConnectionID = new byte[4];
+ System.arraycopy(hsConnect.mConnectionID, 0, request.mConnectionID, 0, 4);
+ } else {
+ Log.w(TAG, "sendEvent: no connection ID");
+ }
+
+ synchronized (this) {
+ mWaitingForRemote = true;
+ }
+ // Send the header first and then the body
+ try {
+ if (V) Log.v(TAG, "Send headerset Event ");
+ putOperation = (ClientOperation)clientSession.put(request);
+ // TODO - Should this be kept or Removed
+
+ } catch (IOException e) {
+ Log.e(TAG, "Error when put HeaderSet " + e.getMessage());
+ error = true;
+ }
+ synchronized (this) {
+ mWaitingForRemote = false;
+ }
+ if (!error) {
+ try {
+ if (V) Log.v(TAG, "Send headerset Event ");
+ outputStream = putOperation.openOutputStream();
+ } catch (IOException e) {
+ Log.e(TAG, "Error when opening OutputStream " + e.getMessage());
+ error = true;
+ }
+ }
+
+ if (!error) {
+
+ maxChunkSize = putOperation.getMaxPacketSize();
+
+ while (bytesWritten < eventBytes.length) {
+ bytesToWrite = Math.min(maxChunkSize, eventBytes.length - bytesWritten);
+ outputStream.write(eventBytes, bytesWritten, bytesToWrite);
+ bytesWritten += bytesToWrite;
+ }
+
+ if (bytesWritten == eventBytes.length) {
+ Log.i(TAG, "SendEvent finished send length" + eventBytes.length);
+ } else {
+ error = true;
+ putOperation.abort();
+ Log.i(TAG, "SendEvent interrupted");
+ }
+ }
+ } catch (IOException e) {
+ handleSendException(e.toString());
+ error = true;
+ } catch (IndexOutOfBoundsException e) {
+ handleSendException(e.toString());
+ error = true;
+ } finally {
+ try {
+ if (outputStream != null) {
+ outputStream.close();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error when closing stream after send " + e.getMessage());
+ }
+ try {
+ if ((!error) && (putOperation != null)) {
+ responseCode = putOperation.getResponseCode();
+ if (responseCode != -1) {
+ if (V) Log.v(TAG, "Put response code " + responseCode);
+ if (responseCode != ResponseCodes.OBEX_HTTP_OK) {
+ Log.i(TAG, "Response error code is " + responseCode);
+ }
+ }
+ }
+ if (putOperation != null) {
+ putOperation.close();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error when closing stream after send " + e.getMessage());
+ }
+ }
+
+ return responseCode;
+ }
+
+ private void handleSendException(String exception) {
+ Log.e(TAG, "Error when sending event: " + exception);
+ }
+}
diff --git a/src/com/android/bluetooth/map/BluetoothMnsRfcommTransport.java b/src/com/android/bluetooth/map/BluetoothMnsRfcommTransport.java
new file mode 100644
index 0000000..fc5d54a
--- /dev/null
+++ b/src/com/android/bluetooth/map/BluetoothMnsRfcommTransport.java
@@ -0,0 +1,79 @@
+/*
+* Copyright (C) 2013 Samsung System LSI
+* 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.bluetooth.map;
+
+import android.bluetooth.BluetoothSocket;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.obex.ObexTransport;
+
+public class BluetoothMnsRfcommTransport implements ObexTransport {
+
+ private final BluetoothSocket mSocket;
+
+ public BluetoothMnsRfcommTransport(BluetoothSocket socket) {
+ super();
+ this.mSocket = socket;
+ }
+
+ public void close() throws IOException {
+ mSocket.close();
+ }
+
+ public DataInputStream openDataInputStream() throws IOException {
+ return new DataInputStream(openInputStream());
+ }
+
+ public DataOutputStream openDataOutputStream() throws IOException {
+ return new DataOutputStream(openOutputStream());
+ }
+
+ public InputStream openInputStream() throws IOException {
+ return mSocket.getInputStream();
+ }
+
+ public OutputStream openOutputStream() throws IOException {
+ return mSocket.getOutputStream();
+ }
+
+ public void connect() throws IOException {
+ }
+
+ public void create() throws IOException {
+ }
+
+ public void disconnect() throws IOException {
+ }
+
+ public void listen() throws IOException {
+ }
+
+ public boolean isConnected() throws IOException {
+ // TODO: add implementation
+ return true;
+ }
+
+ public String getRemoteAddress() {
+ if (mSocket == null)
+ return null;
+ return mSocket.getRemoteDevice().getAddress();
+ }
+
+}
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java b/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
index fa0c8b2..d91d9a2 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapCallLogComposer.java
@@ -16,7 +16,6 @@
package com.android.bluetooth.pbap;
import com.android.bluetooth.R;
-import com.android.internal.telephony.CallerInfo;
import android.content.ContentResolver;
import android.content.Context;
@@ -60,7 +59,7 @@
/** The projection to use when querying the call log table */
private static final String[] sCallLogProjection = new String[] {
Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE,
- Calls.CACHED_NUMBER_LABEL
+ Calls.CACHED_NUMBER_LABEL, Calls.NUMBER_PRESENTATION
};
private static final int NUMBER_COLUMN_INDEX = 0;
private static final int DATE_COLUMN_INDEX = 1;
@@ -68,6 +67,7 @@
private static final int CALLER_NAME_COLUMN_INDEX = 3;
private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4;
private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5;
+ private static final int NUMBER_PRESENTATION_COLUMN_INDEX = 6;
// Property for call log entry
private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME";
@@ -139,24 +139,22 @@
VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING;
final VCardBuilder builder = new VCardBuilder(vcardType);
String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX);
+ String number = mCursor.getString(NUMBER_COLUMN_INDEX);
+ final int numberPresentation = mCursor.getInt(NUMBER_PRESENTATION_COLUMN_INDEX);
if (TextUtils.isEmpty(name)) {
name = "";
}
- if (CallerInfo.UNKNOWN_NUMBER.equals(name) || CallerInfo.PRIVATE_NUMBER.equals(name) ||
- CallerInfo.PAYPHONE_NUMBER.equals(name)) {
+ if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
// setting name to "" as FN/N must be empty fields in this case.
name = "";
+ // TODO: there are really 3 possible strings that could be set here:
+ // "unknown", "private", and "payphone".
+ number = mContext.getString(R.string.unknownNumber);
}
final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name));
builder.appendLine(VCardConstants.PROPERTY_FN, name, needCharset, false);
builder.appendLine(VCardConstants.PROPERTY_N, name, needCharset, false);
- String number = mCursor.getString(NUMBER_COLUMN_INDEX);
- if (CallerInfo.UNKNOWN_NUMBER.equals(number) ||
- CallerInfo.PRIVATE_NUMBER.equals(number) ||
- CallerInfo.PAYPHONE_NUMBER.equals(number)) {
- number = mContext.getString(R.string.unknownNumber);
- }
final int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX);
String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX);
if (TextUtils.isEmpty(label)) {
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapService.java b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
index a45bc9a..2f577d5 100755
--- a/src/com/android/bluetooth/pbap/BluetoothPbapService.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapService.java
@@ -242,6 +242,8 @@
Intent timeoutIntent =
new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL);
timeoutIntent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
+ timeoutIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
sendBroadcast(timeoutIntent, BLUETOOTH_ADMIN_PERM);
}
// Release all resources
@@ -250,7 +252,11 @@
removeTimeoutMsg = false;
}
} else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
- if (!isWaitingAuthorization) {
+ int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
+
+ if ((!isWaitingAuthorization) ||
+ (requestType != BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS)) {
// this reply is not for us
return;
}
@@ -580,8 +586,9 @@
intent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, getPackageName());
intent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME,
BluetoothPbapReceiver.class.getName());
- sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+
isWaitingAuthorization = true;
+ sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
if (VERBOSE) Log.v(TAG, "waiting for authorization for connection from: "
+ sRemoteDeviceName);
@@ -628,6 +635,8 @@
case USER_TIMEOUT:
Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL);
intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
+ intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
+ BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
sendBroadcast(intent);
isWaitingAuthorization = false;
stopObexServerSession();
diff --git a/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java b/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java
index 001d4c2..3568299 100644
--- a/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java
+++ b/src/com/android/bluetooth/pbap/BluetoothPbapVcardManager.java
@@ -51,7 +51,6 @@
import com.android.bluetooth.R;
import com.android.vcard.VCardComposer;
import com.android.vcard.VCardConfig;
-import com.android.internal.telephony.CallerInfo;
import com.android.vcard.VCardPhoneNumberTranslationCallback;
import java.io.IOException;
@@ -200,10 +199,11 @@
final Uri myUri = CallLog.Calls.CONTENT_URI;
String selection = BluetoothPbapObexServer.createSelectionPara(type);
String[] projection = new String[] {
- Calls.NUMBER, Calls.CACHED_NAME
+ Calls.NUMBER, Calls.CACHED_NAME, Calls.NUMBER_PRESENTATION
};
final int CALLS_NUMBER_COLUMN_INDEX = 0;
final int CALLS_NAME_COLUMN_INDEX = 1;
+ final int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 2;
Cursor callCursor = null;
ArrayList<String> list = new ArrayList<String>();
@@ -216,11 +216,12 @@
String name = callCursor.getString(CALLS_NAME_COLUMN_INDEX);
if (TextUtils.isEmpty(name)) {
// name not found, use number instead
- name = callCursor.getString(CALLS_NUMBER_COLUMN_INDEX);
- if (CallerInfo.UNKNOWN_NUMBER.equals(name) ||
- CallerInfo.PRIVATE_NUMBER.equals(name) ||
- CallerInfo.PAYPHONE_NUMBER.equals(name)) {
+ final int numberPresentation = callCursor.getInt(
+ CALLS_NUMBER_PRESENTATION_COLUMN_INDEX);
+ if (numberPresentation != Calls.PRESENTATION_ALLOWED) {
name = mContext.getString(R.string.unknownNumber);
+ } else {
+ name = callCursor.getString(CALLS_NUMBER_COLUMN_INDEX);
}
}
list.add(name);
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100755
index 0000000..ce9be11
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := optional
+LOCAL_CERTIFICATE := platform
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := com.android.emailcommon
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BluetoothProfileTests
+
+LOCAL_INSTRUMENTATION_FOR := Bluetooth
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
new file mode 100755
index 0000000..c022b22
--- /dev/null
+++ b/tests/AndroidManifest.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.bluetooth.tests">
+
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="com.android.permission.HANDOVER_STATUS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.NET_ADMIN" />
+ <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.NET_TUNNELING" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+ <uses-permission android:name="com.google.android.gallery3d.permission.GALLERY_PROVIDER"/>
+ <uses-permission android:name="com.android.gallery3d.permission.GALLERY_PROVIDER"/>
+
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS" />
+ <uses-permission android:name="android.permission.WRITE_SMS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <uses-permission android:name="com.android.email.permission.ACCESS_PROVIDER"/>
+
+ <!-- For PBAP Owner Vcard Info -->
+ <uses-permission android:name="android.permission.READ_PROFILE"/>
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <uses-permission android:name="android.permission.ACCESS_BLUETOOTH_SHARE" />
+ <uses-permission android:name="com.android.permission.WHITELIST_BLUETOOTH_DEVICE" />
+ <path-permission
+ android:path="/btopp"
+ android:permission="android.permission.ACCESS_BLUETOOTH_SHARE" />
+ </application>
+ <!--
+ This declares that this application uses the instrumentation test runner targeting
+ the package of com.android.bluetooth. To run the tests use the command:
+ "adb shell am instrument -w com.android.bluetooth.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.bluetooth"
+ android:label="Tests for com.android.bluetooth"/>
+</manifest>
+
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java
new file mode 100644
index 0000000..9e318c6
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java
@@ -0,0 +1,102 @@
+package com.android.bluetooth.tests;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.database.Cursor;
+import android.content.Context;
+import android.content.ContentResolver;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.android.bluetooth.map.BluetoothMapContent;
+import com.android.bluetooth.map.BluetoothMapContentObserver;
+
+import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.EmailContent.Message;
+import com.android.emailcommon.provider.EmailContent.MessageColumns;
+import com.android.emailcommon.provider.EmailContent.SyncColumns;
+
+public class BluetoothMapContentTest extends AndroidTestCase {
+ private static final String TAG = "BluetoothMapContentTest";
+
+ private static final boolean D = true;
+ private static final boolean V = true;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+
+ static final String[] EMAIL_PROJECTION = new String[] {
+ EmailContent.RECORD_ID,
+ MessageColumns.DISPLAY_NAME, MessageColumns.TIMESTAMP,
+ MessageColumns.SUBJECT, MessageColumns.FLAG_READ,
+ MessageColumns.FLAG_ATTACHMENT, MessageColumns.FLAGS,
+ SyncColumns.SERVER_ID, MessageColumns.DRAFT_INFO,
+ MessageColumns.MESSAGE_ID, MessageColumns.MAILBOX_KEY,
+ MessageColumns.ACCOUNT_KEY, MessageColumns.FROM_LIST,
+ MessageColumns.TO_LIST, MessageColumns.CC_LIST,
+ MessageColumns.BCC_LIST, MessageColumns.REPLY_TO_LIST,
+ SyncColumns.SERVER_TIMESTAMP, MessageColumns.MEETING_INFO,
+ MessageColumns.SNIPPET, MessageColumns.PROTOCOL_SEARCH_INFO,
+ MessageColumns.THREAD_TOPIC
+ };
+
+ private String getDateTimeString(long timestamp) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = new Date(timestamp);
+ return format.format(date); // Format to YYYYMMDDTHHMMSS local time
+ }
+
+ private void printEmail(Cursor c) {
+ if (D) Log.d(TAG, "printEmail " +
+ c.getLong(c.getColumnIndex(EmailContent.RECORD_ID)) +
+ "\n " + MessageColumns.DISPLAY_NAME + " : " + c.getString(c.getColumnIndex(MessageColumns.DISPLAY_NAME)) +
+ "\n " + MessageColumns.TIMESTAMP + " : " + getDateTimeString(c.getLong(c.getColumnIndex(MessageColumns.TIMESTAMP))) +
+ "\n " + MessageColumns.SUBJECT + " : " + c.getString(c.getColumnIndex(MessageColumns.SUBJECT)) +
+ "\n " + MessageColumns.FLAG_READ + " : " + c.getString(c.getColumnIndex(MessageColumns.FLAG_READ)) +
+ "\n " + MessageColumns.FLAG_ATTACHMENT + " : " + c.getInt(c.getColumnIndex(MessageColumns.FLAG_ATTACHMENT)) +
+ "\n " + MessageColumns.FLAGS + " : " + c.getInt(c.getColumnIndex(MessageColumns.FLAGS)) +
+ "\n " + SyncColumns.SERVER_ID + " : " + c.getInt(c.getColumnIndex(SyncColumns.SERVER_ID)) +
+ "\n " + MessageColumns.DRAFT_INFO + " : " + c.getInt(c.getColumnIndex(MessageColumns.DRAFT_INFO)) +
+ "\n " + MessageColumns.MESSAGE_ID + " : " + c.getInt(c.getColumnIndex(MessageColumns.MESSAGE_ID)) +
+ "\n " + MessageColumns.MAILBOX_KEY + " : " + c.getInt(c.getColumnIndex(MessageColumns.MAILBOX_KEY)) +
+ "\n " + MessageColumns.ACCOUNT_KEY + " : " + c.getInt(c.getColumnIndex(MessageColumns.ACCOUNT_KEY)) +
+ "\n " + MessageColumns.FROM_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.FROM_LIST)) +
+ "\n " + MessageColumns.TO_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.TO_LIST)) +
+ "\n " + MessageColumns.CC_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.CC_LIST)) +
+ "\n " + MessageColumns.BCC_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.BCC_LIST)) +
+ "\n " + MessageColumns.REPLY_TO_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.REPLY_TO_LIST)) +
+ "\n " + SyncColumns.SERVER_TIMESTAMP + " : " + getDateTimeString(c.getLong(c.getColumnIndex(SyncColumns.SERVER_TIMESTAMP))) +
+ "\n " + MessageColumns.MEETING_INFO + " : " + c.getString(c.getColumnIndex(MessageColumns.MEETING_INFO)) +
+ "\n " + MessageColumns.SNIPPET + " : " + c.getString(c.getColumnIndex(MessageColumns.SNIPPET)) +
+ "\n " + MessageColumns.PROTOCOL_SEARCH_INFO + " : " + c.getString(c.getColumnIndex(MessageColumns.PROTOCOL_SEARCH_INFO)) +
+ "\n " + MessageColumns.THREAD_TOPIC + " : " + c.getString(c.getColumnIndex(MessageColumns.THREAD_TOPIC)));
+ }
+
+ public void dumpEmailMessageTable() {
+ Log.d(TAG, "**** Dump of email message table ****");
+
+ Cursor c = mResolver.query(Message.CONTENT_URI,
+ EMAIL_PROJECTION, null, null, "_id DESC");
+ if (c != null) {
+ Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printEmail(c);
+ }
+ } else {
+ Log.d(TAG, "query failed");
+ c.close();
+ }
+ }
+
+ public BluetoothMapContentTest() {
+ super();
+ }
+
+ public void testDumpMessages() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ dumpEmailMessageTable();
+ }
+}
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java
new file mode 100755
index 0000000..14c41da
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java
@@ -0,0 +1,505 @@
+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.BluetoothMapbMessageMmsEmail;
+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() {
+ BluetoothMapbMessageMmsEmail msg = new BluetoothMapbMessageMmsEmail();
+ 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");
+ BluetoothMapbMessageMmsEmail.MimePart part = msg.addMimePart();
+ part.partName = "partNameText";
+ part.contentType ="dsfajfdlk/text/asdfafda";
+ try {
+ part.data = 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.partName = "partNameimage";
+ part.contentType = "dsfajfdlk/image/asdfafda";
+ part.data = 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 <joergen@hest.com>");
+ String headerStr = BasicHeaderValueFormatter.formatHeaderElement(header, true, BasicHeaderValueFormatter.DEFAULT);
+ if(D) Log.i(TAG, "The encoded header: " + headerStr);
+ }
+
+}
+