/*
|
* Copyright (C) 2014 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
package com.android.internal.telephony;
|
|
import android.content.res.Resources;
|
import android.content.res.XmlResourceParser;
|
import android.os.Build;
|
import android.telephony.Rlog;
|
import android.util.SparseIntArray;
|
|
import com.android.internal.telephony.cdma.sms.UserData;
|
import com.android.internal.util.XmlUtils;
|
|
public class Sms7BitEncodingTranslator {
|
private static final String TAG = "Sms7BitEncodingTranslator";
|
private static final boolean DBG = Build.IS_DEBUGGABLE ;
|
private static boolean mIs7BitTranslationTableLoaded = false;
|
private static SparseIntArray mTranslationTable = null;
|
private static SparseIntArray mTranslationTableCommon = null;
|
private static SparseIntArray mTranslationTableGSM = null;
|
private static SparseIntArray mTranslationTableCDMA = null;
|
|
// Parser variables
|
private static final String XML_START_TAG = "SmsEnforce7BitTranslationTable";
|
private static final String XML_TRANSLATION_TYPE_TAG = "TranslationType";
|
private static final String XML_CHARACTOR_TAG = "Character";
|
private static final String XML_FROM_TAG = "from";
|
private static final String XML_TO_TAG = "to";
|
|
/**
|
* Translates each message character that is not supported by GSM 7bit alphabet into a supported
|
* one.
|
*
|
* @param message message to be translated.
|
* @param isCdmaFormat true if cdma format should be used.
|
* @return translated message or null if some error occur.
|
*/
|
public static String translate(CharSequence message, boolean isCdmaFormat) {
|
if (message == null) {
|
Rlog.w(TAG, "Null message can not be translated");
|
return null;
|
}
|
|
int size = message.length();
|
if (size <= 0) {
|
return "";
|
}
|
|
if (!mIs7BitTranslationTableLoaded) {
|
mTranslationTableCommon = new SparseIntArray();
|
mTranslationTableGSM = new SparseIntArray();
|
mTranslationTableCDMA = new SparseIntArray();
|
load7BitTranslationTableFromXml();
|
mIs7BitTranslationTableLoaded = true;
|
}
|
|
if ((mTranslationTableCommon != null && mTranslationTableCommon.size() > 0) ||
|
(mTranslationTableGSM != null && mTranslationTableGSM.size() > 0) ||
|
(mTranslationTableCDMA != null && mTranslationTableCDMA.size() > 0)) {
|
char[] output = new char[size];
|
for (int i = 0; i < size; i++) {
|
output[i] = translateIfNeeded(message.charAt(i), isCdmaFormat);
|
}
|
|
return String.valueOf(output);
|
}
|
|
return null;
|
}
|
|
/**
|
* Translates a single character into its corresponding acceptable one, if
|
* needed, based on GSM 7-bit alphabet
|
*
|
* @param c
|
* character to be translated
|
* @return original character, if it's present on GSM 7-bit alphabet; a
|
* corresponding character, based on the translation table or white
|
* space, if no mapping is found in the translation table for such
|
* character
|
*/
|
private static char translateIfNeeded(char c, boolean isCdmaFormat) {
|
if (noTranslationNeeded(c, isCdmaFormat)) {
|
if (DBG) {
|
Rlog.v(TAG, "No translation needed for " + Integer.toHexString(c));
|
}
|
return c;
|
}
|
|
/*
|
* Trying to translate unicode to Gsm 7-bit alphabet; If c is not
|
* present on translation table, c does not belong to Unicode Latin-1
|
* (Basic + Supplement), so we don't know how to translate it to a Gsm
|
* 7-bit character! We replace c for an empty space and advises the user
|
* about it.
|
*/
|
int translation = -1;
|
|
if (mTranslationTableCommon != null) {
|
translation = mTranslationTableCommon.get(c, -1);
|
}
|
|
if (translation == -1) {
|
if (isCdmaFormat) {
|
if (mTranslationTableCDMA != null) {
|
translation = mTranslationTableCDMA.get(c, -1);
|
}
|
} else {
|
if (mTranslationTableGSM != null) {
|
translation = mTranslationTableGSM.get(c, -1);
|
}
|
}
|
}
|
|
if (translation != -1) {
|
if (DBG) {
|
Rlog.v(TAG, Integer.toHexString(c) + " (" + c + ")" + " translated to "
|
+ Integer.toHexString(translation) + " (" + (char) translation + ")");
|
}
|
return (char) translation;
|
} else {
|
if (DBG) {
|
Rlog.w(TAG, "No translation found for " + Integer.toHexString(c)
|
+ "! Replacing for empty space");
|
}
|
return ' ';
|
}
|
}
|
|
private static boolean noTranslationNeeded(char c, boolean isCdmaFormat) {
|
if (isCdmaFormat) {
|
return GsmAlphabet.isGsmSeptets(c) && UserData.charToAscii.get(c, -1) != -1;
|
}
|
else {
|
return GsmAlphabet.isGsmSeptets(c);
|
}
|
}
|
|
/**
|
* Load the whole translation table file from the framework resource
|
* encoded in XML.
|
*/
|
private static void load7BitTranslationTableFromXml() {
|
XmlResourceParser parser = null;
|
Resources r = Resources.getSystem();
|
|
if (parser == null) {
|
if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: open normal file");
|
parser = r.getXml(com.android.internal.R.xml.sms_7bit_translation_table);
|
}
|
|
try {
|
XmlUtils.beginDocument(parser, XML_START_TAG);
|
while (true) {
|
XmlUtils.nextElement(parser);
|
String tag = parser.getName();
|
if (DBG) {
|
Rlog.d(TAG, "tag: " + tag);
|
}
|
if (XML_TRANSLATION_TYPE_TAG.equals(tag)) {
|
String type = parser.getAttributeValue(null, "Type");
|
if (DBG) {
|
Rlog.d(TAG, "type: " + type);
|
}
|
if (type.equals("common")) {
|
mTranslationTable = mTranslationTableCommon;
|
} else if (type.equals("gsm")) {
|
mTranslationTable = mTranslationTableGSM;
|
} else if (type.equals("cdma")) {
|
mTranslationTable = mTranslationTableCDMA;
|
} else {
|
Rlog.e(TAG, "Error Parsing 7BitTranslationTable: found incorrect type" + type);
|
}
|
} else if (XML_CHARACTOR_TAG.equals(tag) && mTranslationTable != null) {
|
int from = parser.getAttributeUnsignedIntValue(null,
|
XML_FROM_TAG, -1);
|
int to = parser.getAttributeUnsignedIntValue(null,
|
XML_TO_TAG, -1);
|
if ((from != -1) && (to != -1)) {
|
if (DBG) {
|
Rlog.d(TAG, "Loading mapping " + Integer.toHexString(from)
|
.toUpperCase() + " -> " + Integer.toHexString(to)
|
.toUpperCase());
|
}
|
mTranslationTable.put (from, to);
|
} else {
|
Rlog.d(TAG, "Invalid translation table file format");
|
}
|
} else {
|
break;
|
}
|
}
|
if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: parsing successful, file loaded");
|
} catch (Exception e) {
|
Rlog.e(TAG, "Got exception while loading 7BitTranslationTable file.", e);
|
} finally {
|
if (parser instanceof XmlResourceParser) {
|
((XmlResourceParser)parser).close();
|
}
|
}
|
}
|
}
|