merge in lmp-release history after reset to 7b54f44bafb4ef6e7d8f051970f2ab1ec5bb0d73
The Android Automerger [Tue, 7 Oct 2014 13:12:29 +0000 (06:12 -0700)]
src/java/android/telephony/SmsManager.java
src/java/android/telephony/SmsMessage.java
src/java/com/android/internal/telephony/SMSDispatcher.java
src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java [new file with mode: 0644]
src/java/com/android/internal/telephony/cdma/SmsMessage.java
src/java/com/android/internal/telephony/dataconnection/DataProfile.java
src/java/com/android/internal/telephony/dataconnection/DcTracker.java
src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
src/java/com/android/internal/telephony/gsm/GSMPhone.java
src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
src/java/com/android/internal/telephony/gsm/SmsMessage.java

index 8d9e734..ffc6329 100644 (file)
@@ -808,7 +808,7 @@ public final class SmsManager {
      *
      * @hide
      */
-    boolean isImsSmsSupported() {
+    public boolean isImsSmsSupported() {
         boolean boSupported = false;
         try {
             ISms iccISms = getISmsService();
@@ -833,7 +833,7 @@ public final class SmsManager {
      *
      * @hide
      */
-    String getImsSmsFormat() {
+    public String getImsSmsFormat() {
         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
         try {
             ISms iccISms = getISmsService();
index 81a4121..a154477 100644 (file)
@@ -26,6 +26,7 @@ import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
 
 import java.lang.Math;
 import java.util.ArrayList;
@@ -363,8 +364,16 @@ public class SmsMessage {
             }
         }
 
+        String newMsgBody = null;
+        Resources r = Resources.getSystem();
+        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
+            newMsgBody  = Sms7BitEncodingTranslator.translate(text);
+        }
+        if (TextUtils.isEmpty(newMsgBody)) {
+            newMsgBody = text;
+        }
         int pos = 0;  // Index in code units.
-        int textLen = text.length();
+        int textLen = newMsgBody.length();
         ArrayList<String> result = new ArrayList<String>(ted.msgCount);
         while (pos < textLen) {
             int nextPos = 0;  // Counts code units.
@@ -374,7 +383,7 @@ public class SmsMessage {
                     nextPos = pos + Math.min(limit, textLen - pos);
                 } else {
                     // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
-                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit,
+                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(newMsgBody, pos, limit,
                             ted.languageTable, ted.languageShiftTable);
                 }
             } else {  // Assume unicode.
@@ -385,7 +394,7 @@ public class SmsMessage {
                           nextPos + " >= " + textLen + ")");
                 break;
             }
-            result.add(text.substring(pos, nextPos));
+            result.add(newMsgBody.substring(pos, nextPos));
             pos = nextPos;
         }
         return result;
index d89c363..a4699e6 100644 (file)
@@ -302,6 +302,11 @@ public abstract class SMSDispatcher extends Handler {
             if (tracker.isMultipart()) {
                 sendMultipartSms(tracker);
             } else {
+                if (mPendingTrackerCount > 1) {
+                    tracker.mExpectMore = true;
+                } else {
+                    tracker.mExpectMore = false;
+                }
                 sendSms(tracker);
             }
             mPendingTrackerCount--;
diff --git a/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
new file mode 100644 (file)
index 0000000..6cb1f14
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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.telephony.Rlog;
+import android.os.Build;
+import android.util.SparseIntArray;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.telephony.SmsManager;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.XmlUtils;
+import com.android.internal.telephony.cdma.sms.UserData;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+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 throwsException
+     *            if true and some error occurs during translation, an exception
+     *            is thrown; otherwise a null String is returned
+     * @return translated message or null if some error occur
+     */
+    public static String translate(CharSequence message) {
+        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));
+            }
+
+            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) {
+        if (noTranslationNeeded(c)) {
+            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 (useCdmaFormatForMoSms()) {
+                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) {
+        if (useCdmaFormatForMoSms()) {
+            return GsmAlphabet.isGsmSeptets(c) && UserData.charToAscii.get(c, -1) != -1;
+        }
+        else {
+            return GsmAlphabet.isGsmSeptets(c);
+        }
+    }
+
+    private static boolean useCdmaFormatForMoSms() {
+        if (!SmsManager.getDefault().isImsSmsSupported()) {
+            // use Voice technology to determine SMS format.
+            return TelephonyManager.getDefault().getCurrentPhoneType()
+                    == PhoneConstants.PHONE_TYPE_CDMA;
+        }
+        // IMS is registered with SMS support, check the SMS format supported
+        return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
+    }
+
+    /**
+     * 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();
+            }
+        }
+    }
+}
index 5c99a43..a3af3a5 100644 (file)
@@ -24,6 +24,8 @@ import android.telephony.SmsCbMessage;
 import android.telephony.cdma.CdmaSmsCbProgramData;
 import android.telephony.Rlog;
 import android.util.Log;
+import android.text.TextUtils;
+import android.content.res.Resources;
 
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.SmsConstants;
@@ -38,6 +40,7 @@ import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.BitwiseInputStream;
 import com.android.internal.util.HexDump;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -458,7 +461,15 @@ public class SmsMessage extends SmsMessageBase {
      */
     public static TextEncodingDetails calculateLength(CharSequence messageBody,
             boolean use7bitOnly) {
-        return BearerData.calcTextEncodingDetails(messageBody, use7bitOnly);
+        CharSequence newMsgBody = null;
+        Resources r = Resources.getSystem();
+        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
+            newMsgBody  = Sms7BitEncodingTranslator.translate(messageBody);
+        }
+        if (TextUtils.isEmpty(newMsgBody)) {
+            newMsgBody = messageBody;
+        }
+        return BearerData.calcTextEncodingDetails(newMsgBody, use7bitOnly);
     }
 
     /**
index 3672e5d..45a6b6b 100644 (file)
@@ -107,4 +107,9 @@ public class DataProfile {
                 + "/" + maxConns + "/" + waitTime + "/" + enabled;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DataProfile == false) return false;
+        return (toString().equals(o.toString()));
+    }
 }
index 6d7bfb6..93f13c8 100644 (file)
@@ -79,8 +79,10 @@ import com.android.internal.util.ArrayUtils;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.HashMap;
+import java.util.Objects;
 
 import android.provider.Settings;
 
@@ -2258,6 +2260,8 @@ public final class DcTracker extends DcTrackerBase {
 
         addEmergencyApnSetting();
 
+        dedupeApnSettings();
+
         if (mAllApnSettings.isEmpty()) {
             if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
             mPreferredApn = null;
@@ -2276,6 +2280,76 @@ public final class DcTracker extends DcTrackerBase {
         setDataProfilesAsNeeded();
     }
 
+    private void dedupeApnSettings() {
+        ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>();
+
+        // coalesce APNs if they are similar enough to prevent
+        // us from bringing up two data calls with the same interface
+        int i = 0;
+        while (i < mAllApnSettings.size() - 1) {
+            ApnSetting first = mAllApnSettings.get(i);
+            ApnSetting second = null;
+            int j = i + 1;
+            while (j < mAllApnSettings.size()) {
+                second = mAllApnSettings.get(j);
+                if (apnsSimilar(first, second)) {
+                    ApnSetting newApn = mergeApns(first, second);
+                    mAllApnSettings.set(i, newApn);
+                    first = newApn;
+                    mAllApnSettings.remove(j);
+                } else {
+                    j++;
+                }
+            }
+            i++;
+        }
+    }
+
+    // Check if neither mention DUN and are substantially similar
+    private boolean apnsSimilar(ApnSetting first, ApnSetting second) {
+        return (first.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
+                second.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
+                Objects.equals(first.apn, second.apn) &&
+                Objects.equals(first.proxy, second.proxy) &&
+                Objects.equals(first.port, second.port) &&
+                Objects.equals(first.protocol, second.protocol) &&
+                Objects.equals(first.roamingProtocol, second.roamingProtocol) &&
+                first.carrierEnabled == second.carrierEnabled &&
+                first.bearer == second.bearer &&
+                first.profileId == second.profileId &&
+                Objects.equals(first.mvnoType, second.mvnoType) &&
+                Objects.equals(first.mvnoMatchData, second.mvnoMatchData) &&
+                xorEquals(first.mmsc, second.mmsc) &&
+                xorEquals(first.mmsProxy, second.mmsProxy) &&
+                xorEquals(first.mmsPort, second.mmsPort));
+    }
+
+    // equal or one is not specified
+    private boolean xorEquals(String first, String second) {
+        return (Objects.equals(first, second) ||
+                TextUtils.isEmpty(first) ||
+                TextUtils.isEmpty(second));
+    }
+
+    private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) {
+        ArrayList<String> resultTypes = new ArrayList<String>();
+        resultTypes.addAll(Arrays.asList(dest.types));
+        for (String srcType : src.types) {
+            if (resultTypes.contains(srcType) == false) resultTypes.add(srcType);
+        }
+        String mmsc = (TextUtils.isEmpty(dest.mmsc) ? src.mmsc : dest.mmsc);
+        String mmsProxy = (TextUtils.isEmpty(dest.mmsProxy) ? src.mmsProxy : dest.mmsProxy);
+        String mmsPort = (TextUtils.isEmpty(dest.mmsPort) ? src.mmsPort : dest.mmsPort);
+
+
+        return new ApnSetting(dest.id, dest.numeric, dest.carrier, dest.apn,
+                dest.proxy, dest.port, mmsc, mmsProxy, mmsPort, dest.user, dest.password,
+                dest.authType, resultTypes.toArray(new String[0]), dest.protocol,
+                dest.roamingProtocol, dest.carrierEnabled, dest.bearer, dest.profileId,
+                (dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime,
+                dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData);
+    }
+
     /** Return the DC AsyncChannel for the new data connection */
     private DcAsyncChannel createDataConnection() {
         if (DBG) log("createDataConnection E");
index ec045ff..0ba61c2 100644 (file)
@@ -1697,7 +1697,8 @@ public abstract class DcTrackerBase extends Handler {
             // Search for Initial APN setting and the first apn that can handle default
             for (ApnSetting apn : mAllApnSettings) {
                 // Can't use apn.canHandleType(), as that returns true for APNs that have no type.
-                if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA)) {
+                if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) &&
+                        apn.carrierEnabled) {
                     // The Initial Attach APN is highest priority so use it if there is one
                     log("setInitialApn: iaApnSetting=" + apn);
                     iaApnSetting = apn;
@@ -1751,7 +1752,16 @@ public abstract class DcTrackerBase extends Handler {
                 if (apn.modemCognitive) {
                     DataProfile dp = new DataProfile(apn,
                             mPhone.getServiceState().getRoaming());
-                    dps.add(dp);
+                    boolean isDup = false;
+                    for(DataProfile dpIn : dps) {
+                        if (dp.equals(dpIn)) {
+                            isDup = true;
+                            break;
+                        }
+                    }
+                    if (!isDup) {
+                        dps.add(dp);
+                    }
                 }
             }
             if(dps.size() > 0) {
index c833548..211d397 100644 (file)
@@ -448,8 +448,8 @@ public class GSMPhone extends PhoneBase {
         mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
     }
 
-    void notifyUnknownConnection() {
-        mUnknownConnectionRegistrants.notifyResult(this);
+    void notifyUnknownConnection(Connection cn) {
+        mUnknownConnectionRegistrants.notifyResult(cn);
     }
 
     void notifySuppServiceFailed(SuppService code) {
index 66a7768..d4088f2 100755 (executable)
@@ -434,6 +434,7 @@ public final class GsmCallTracker extends CallTracker {
         }
 
         Connection newRinging = null; //or waiting
+        Connection newUnknown = null;
         boolean hasNonHangupStateChanged = false;   // Any change besides
                                                     // a dropped connection
         boolean hasAnyCallDisconnected = false;
@@ -518,6 +519,8 @@ public final class GsmCallTracker extends CallTracker {
                             }
                         }
 
+                        newUnknown = mConnections[i];
+
                         unknownConnectionAppeared = true;
                     }
                 }
@@ -632,7 +635,7 @@ public final class GsmCallTracker extends CallTracker {
         updatePhoneState();
 
         if (unknownConnectionAppeared) {
-            mPhone.notifyUnknownConnection();
+            mPhone.notifyUnknownConnection(newUnknown);
         }
 
         if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
index 236c3b1..a1f029f 100644 (file)
@@ -20,6 +20,7 @@ import android.telephony.PhoneNumberUtils;
 import android.text.format.Time;
 import android.telephony.Rlog;
 import android.content.res.Resources;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.EncodeException;
 import com.android.internal.telephony.GsmAlphabet;
@@ -27,6 +28,7 @@ import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
 
 import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
@@ -783,11 +785,19 @@ public class SmsMessage extends SmsMessageBase {
      */
     public static TextEncodingDetails calculateLength(CharSequence msgBody,
             boolean use7bitOnly) {
-        TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly);
+        CharSequence newMsgBody = null;
+        Resources r = Resources.getSystem();
+        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
+            newMsgBody  = Sms7BitEncodingTranslator.translate(msgBody);
+        }
+        if (TextUtils.isEmpty(newMsgBody)) {
+            newMsgBody = msgBody;
+        }
+        TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(newMsgBody, use7bitOnly);
         if (ted == null) {
             ted = new TextEncodingDetails();
-            int octets = msgBody.length() * 2;
-            ted.codeUnitCount = msgBody.length();
+            int octets = newMsgBody.length() * 2;
+            ted.codeUnitCount = newMsgBody.length();
             if (octets > MAX_USER_DATA_BYTES) {
                 // If EMS is not supported, break down EMS into single segment SMS
                 // and add page info " x/y".