Merge "Handle LANGUAGE NOTIFICATION command"
diff --git a/src/java/com/android/internal/telephony/cat/AppInterface.java b/src/java/com/android/internal/telephony/cat/AppInterface.java
old mode 100644
new mode 100755
index c78b7f8..1f2d3a0
--- a/src/java/com/android/internal/telephony/cat/AppInterface.java
+++ b/src/java/com/android/internal/telephony/cat/AppInterface.java
@@ -84,6 +84,7 @@
         SET_UP_MENU(0x25),
         SET_UP_CALL(0x10),
         PROVIDE_LOCAL_INFORMATION(0x26),
+        LANGUAGE_NOTIFICATION(0x35),
         OPEN_CHANNEL(0x40),
         CLOSE_CHANNEL(0x41),
         RECEIVE_DATA(0x42),
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
old mode 100644
new mode 100755
index 7e70212..cd7a756
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -16,15 +16,21 @@
 
 package com.android.internal.telephony.cat;
 
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.backup.BackupManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources.NotFoundException;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.LocaleList;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -450,6 +456,18 @@
                     ((CallSetupParams) cmdParams).mConfirmMsg.text = message.toString();
                 }
                 break;
+            case LANGUAGE_NOTIFICATION:
+                String language = ((LanguageParams) cmdParams).mLanguage;
+                ResultCode result = ResultCode.OK;
+                if (language != null && language.length() > 0) {
+                    try {
+                        changeLanguage(language);
+                    } catch (RemoteException e) {
+                        result = ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS;
+                    }
+                }
+                sendTerminalResponse(cmdParams.mCmdDet, result, false, 0, null);
+                return;
             case OPEN_CHANNEL:
             case CLOSE_CHANNEL:
             case RECEIVE_DATA:
@@ -1129,4 +1147,13 @@
             mCmdIf.reportStkServiceIsRunning(null);
         }
     }
+
+    private void changeLanguage(String language) throws RemoteException {
+        IActivityManager am = ActivityManagerNative.getDefault();
+        Configuration config = am.getConfiguration();
+        config.setLocales(new LocaleList(new Locale(language), LocaleList.getDefault()));
+        config.userSetLocale = true;
+        am.updatePersistentConfiguration(config);
+        BackupManager.dataChanged("com.android.providers.settings");
+    }
 }
diff --git a/src/java/com/android/internal/telephony/cat/CommandParams.java b/src/java/com/android/internal/telephony/cat/CommandParams.java
old mode 100644
new mode 100755
index 7dfedab..59cd414
--- a/src/java/com/android/internal/telephony/cat/CommandParams.java
+++ b/src/java/com/android/internal/telephony/cat/CommandParams.java
@@ -150,6 +150,15 @@
     }
 }
 
+class LanguageParams extends CommandParams {
+    String mLanguage;
+
+    LanguageParams(CommandDetails cmdDet, String lang) {
+        super(cmdDet);
+        mLanguage = lang;
+    }
+}
+
 class SelectItemParams extends CommandParams {
     Menu mMenu = null;
     boolean mLoadTitleIcon = false;
diff --git a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index 3dd5337..eb92888 100644
--- a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -19,12 +19,15 @@
 import android.graphics.Bitmap;
 import android.os.Handler;
 import android.os.Message;
+import android.text.TextUtils;
 
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.uicc.IccFileHandler;
 
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
+
 import static com.android.internal.telephony.cat.CatCmdMessage.
                    SetupEventListConstants.USER_ACTIVITY_EVENT;
 import static com.android.internal.telephony.cat.CatCmdMessage.
@@ -47,6 +50,8 @@
     private int mIconLoadState = LOAD_NO_ICON;
     private RilMessageDecoder mCaller = null;
     private boolean mloadIcon = false;
+    private String mSavedLanguage;
+    private String mRequestedLanguage;
 
     // constants
     static final int MSG_ID_LOAD_ICON_DONE = 1;
@@ -66,6 +71,10 @@
     static final int DTTZ_SETTING                           = 0x03;
     static final int LANGUAGE_SETTING                       = 0x04;
 
+    // Command Qualifier value for language notification command
+    static final int NON_SPECIFIC_LANGUAGE                  = 0x00;
+    static final int SPECIFIC_LANGUAGE                      = 0x01;
+
     // As per TS 102.223 Annex C, Structure of CAT communications,
     // the APDU length can be max 255 bytes. This leaves only 239 bytes for user
     // input string. CMD details TLV + Device IDs TLV + Result TLV + Other
@@ -203,6 +212,9 @@
              case PROVIDE_LOCAL_INFORMATION:
                 cmdPending = processProvideLocalInfo(cmdDet, ctlvs);
                 break;
+             case LANGUAGE_NOTIFICATION:
+                 cmdPending = processLanguageNotification(cmdDet, ctlvs);
+                 break;
              case OPEN_CHANNEL:
              case CLOSE_CHANNEL:
              case RECEIVE_DATA:
@@ -1014,6 +1026,67 @@
         return false;
     }
 
+    /**
+     * Processes LANGUAGE_NOTIFICATION proactive command from the SIM card.
+     *
+     * The SPECIFIC_LANGUAGE notification sets the specified language.
+     * The NON_SPECIFIC_LANGUAGE notification restores the last specifically set language.
+     *
+     * @param cmdDet Command Details object retrieved from the proactive command object
+     * @param ctlvs List of ComprehensionTlv objects following Command Details
+     *        object and Device Identities object within the proactive command
+     * @return false. This function always returns false meaning that the command
+     *         processing is  not pending and additional asynchronous processing
+     *         is not required.
+     */
+    private boolean processLanguageNotification(CommandDetails cmdDet, List<ComprehensionTlv> ctlvs)
+            throws ResultException {
+        CatLog.d(this, "process Language Notification");
+
+        String desiredLanguage = null;
+        String currentLanguage = Locale.getDefault().getLanguage();
+        switch (cmdDet.commandQualifier) {
+            case NON_SPECIFIC_LANGUAGE:
+                if (!TextUtils.isEmpty(mSavedLanguage) && (!TextUtils.isEmpty(mRequestedLanguage)
+                        && mRequestedLanguage.equals(currentLanguage))) {
+                    CatLog.d(this, "Non-specific language notification changes the language "
+                            + "setting back to " + mSavedLanguage);
+                    desiredLanguage = mSavedLanguage;
+                }
+
+                mSavedLanguage = null;
+                mRequestedLanguage = null;
+                break;
+            case SPECIFIC_LANGUAGE:
+                ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.LANGUAGE, ctlvs);
+                if (ctlv != null) {
+                    int valueLen = ctlv.getLength();
+                    if (valueLen != 2) {
+                        throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+                    }
+
+                    byte[] rawValue = ctlv.getRawValue();
+                    int valueIndex = ctlv.getValueIndex();
+                    desiredLanguage = GsmAlphabet.gsm8BitUnpackedToString(rawValue, valueIndex, 2);
+
+                    if (TextUtils.isEmpty(mSavedLanguage) || (!TextUtils.isEmpty(mRequestedLanguage)
+                            && !mRequestedLanguage.equals(currentLanguage))) {
+                        mSavedLanguage = currentLanguage;
+                    }
+                    mRequestedLanguage = desiredLanguage;
+                    CatLog.d(this, "Specific language notification changes the language setting to "
+                            + mRequestedLanguage);
+                }
+                break;
+            default:
+                CatLog.d(this, "LN[" + cmdDet.commandQualifier + "] Command Not Supported");
+                break;
+        }
+
+        mCmdParams = new LanguageParams(cmdDet, desiredLanguage);
+        return false;
+    }
+
     private boolean processBIPClient(CommandDetails cmdDet,
                                      List<ComprehensionTlv> ctlvs) throws ResultException {
         AppInterface.CommandType commandType =