Disable shortcut key when network is not available

Bug: 3345931
Change-Id: I1deef774598b8e78da4404535b6d3814464a9d2d
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index de4ac61..e0eecfc 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -2,6 +2,7 @@
         package="com.android.inputmethod.latin">
 
     <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
     <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
diff --git a/java/res/drawable-hdpi/sym_bkeyboard_mic_disabled.png b/java/res/drawable-hdpi/sym_bkeyboard_mic_disabled.png
new file mode 100644
index 0000000..512f460
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_bkeyboard_mic_disabled.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_mic_disabled.png b/java/res/drawable-hdpi/sym_keyboard_mic_disabled.png
new file mode 100644
index 0000000..c8dca62
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_mic_disabled.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_bkeyboard_mic_disabled.png b/java/res/drawable-mdpi/sym_bkeyboard_mic_disabled.png
new file mode 100644
index 0000000..a6cb1cc
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_bkeyboard_mic_disabled.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_mic_disabled.png b/java/res/drawable-mdpi/sym_keyboard_mic_disabled.png
new file mode 100644
index 0000000..e926b3f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_mic_disabled.png
Binary files differ
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 3bff3fc..b1f7379 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -38,7 +38,7 @@
             android:label="@string/subtype_mode_en_voice"
             android:imeSubtypeLocale="en"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_en_GB_keyboard"
@@ -54,7 +54,7 @@
             android:label="@string/subtype_mode_cs_voice"
             android:imeSubtypeLocale="cs"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_da_keyboard"
@@ -70,7 +70,7 @@
             android:label="@string/subtype_mode_de_voice"
             android:imeSubtypeLocale="de"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_es_keyboard"
@@ -81,7 +81,7 @@
             android:label="@string/subtype_mode_es_voice"
             android:imeSubtypeLocale="es"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_fr_keyboard"
@@ -92,7 +92,7 @@
             android:label="@string/subtype_mode_fr_voice"
             android:imeSubtypeLocale="fr"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_fr_CA_keyboard"
@@ -113,7 +113,7 @@
             android:label="@string/subtype_mode_it_voice"
             android:imeSubtypeLocale="it"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_nb_keyboard"
@@ -129,7 +129,7 @@
             android:label="@string/subtype_mode_nl_voice"
             android:imeSubtypeLocale="nl"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_ru_keyboard"
@@ -150,60 +150,60 @@
             android:label="@string/subtype_mode_af_voice"
             android:imeSubtypeLocale="af"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_ja_voice"
             android:imeSubtypeLocale="ja"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_ko_voice"
             android:imeSubtypeLocale="ko"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_pl_voice"
             android:imeSubtypeLocale="pl"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_pt_voice"
             android:imeSubtypeLocale="pt"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_ru_voice"
             android:imeSubtypeLocale="ru"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_tr_voice"
             android:imeSubtypeLocale="tr"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_yue_voice"
             android:imeSubtypeLocale="yue"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_zh_voice"
             android:imeSubtypeLocale="zh"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
     <subtype android:icon="@drawable/ic_subtype_mic"
             android:label="@string/subtype_mode_zu_voice"
             android:imeSubtypeLocale="zu"
             android:imeSubtypeMode="voice"
-            android:imeSubtypeExtraValue="excludeFromLastInputMethod"
+            android:imeSubtypeExtraValue="excludeFromLastInputMethod,requireNetworkConnectivity"
     />
 </input-method>
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 35bafea..23886ad 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -95,6 +95,8 @@
     public boolean mPressed;
     /** If this is a sticky key, is it on? */
     public boolean mOn;
+    /** Key is enabled or not. */
+    public boolean mEnabled = true;
 
     private final static int[] KEY_STATE_NORMAL_ON = {
         android.R.attr.state_checkable,
@@ -385,8 +387,9 @@
      * @see android.graphics.drawable.StateListDrawable#setState(int[])
      */
     public int[] getCurrentDrawableState() {
+        final boolean pressed = mEnabled && mPressed;
         if (isFunctionalKey()) {
-            if (mPressed) {
+            if (pressed) {
                 return KEY_STATE_FUNCTIONAL_PRESSED;
             } else {
                 return KEY_STATE_FUNCTIONAL_NORMAL;
@@ -396,20 +399,20 @@
         int[] states = KEY_STATE_NORMAL;
 
         if (mOn) {
-            if (mPressed) {
+            if (pressed) {
                 states = KEY_STATE_PRESSED_ON;
             } else {
                 states = KEY_STATE_NORMAL_ON;
             }
         } else {
             if (mSticky) {
-                if (mPressed) {
+                if (pressed) {
                     states = KEY_STATE_PRESSED_OFF;
                 } else {
                     states = KEY_STATE_NORMAL_OFF;
                 }
             } else {
-                if (mPressed) {
+                if (pressed) {
                     states = KEY_STATE_PRESSED;
                 }
             }
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 863421f..3a0bf53 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -107,11 +107,6 @@
     private final HashSet<Key> mShiftLockEnabled = new HashSet<Key>();
     private final KeyboardShiftState mShiftState = new KeyboardShiftState();
 
-    /** Space key and its icons */
-    protected Key mSpaceKey;
-    protected Drawable mSpaceIcon;
-    protected Drawable mSpacePreviewIcon;
-
     /** Total height of the keyboard, including the padding and keys */
     private int mTotalHeight;
 
@@ -350,12 +345,6 @@
         return mId != null && mId.isNumberKeyboard();
     }
 
-    public void setSpaceKey(Key space) {
-        mSpaceKey = space;
-        mSpaceIcon = space.getIcon();
-        mSpacePreviewIcon = space.getPreviewIcon();
-    }
-
     private void computeNearestNeighbors() {
         // Round-up so we don't have any pixels outside the grid
         mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
index c41d570..e8324e5 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -286,8 +286,6 @@
             keys.add(key);
             if (key.mCode == Keyboard.CODE_SHIFT)
                 mKeyboard.getShiftKeys().add(key);
-            if (key.mCode == Keyboard.CODE_SPACE)
-                mKeyboard.setSpaceKey(key);
             endKey(key);
         }
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 558de66..2648ff3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -17,11 +17,11 @@
 package com.android.inputmethod.keyboard;
 
 import com.android.inputmethod.latin.LatinIME;
-import com.android.inputmethod.latin.Settings;
-import com.android.inputmethod.latin.Utils;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Settings;
 import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.Utils;
 
 import android.content.Context;
 import android.content.SharedPreferences;
@@ -222,8 +222,9 @@
         keyboard.setShifted(false);
         // If the cached keyboard had been switched to another keyboard while the language was
         // displayed on its spacebar, it might have had arbitrary text fade factor. In such case,
-        // we should reset the text fade factor.
+        // we should reset the text fade factor. It is also applicable to shortcut key.
         keyboard.setSpacebarTextFadeFactor(0.0f, null);
+        keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutAvailable(), null);
         return keyboard;
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index 1977f5f..dc134d6 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -45,18 +45,30 @@
     public static final int OPACITY_FULLY_OPAQUE = 255;
     private static final int SPACE_LED_LENGTH_PERCENT = 80;
 
+    private final Context mContext;
+
+    /* Space key and its icons, drawables and colors. */
+    private final Key mSpaceKey;
+    private final Drawable mSpaceIcon;
+    private final Drawable mSpacePreviewIcon;
+    private final int[] mSpaceKeyIndexArray;
     private final Drawable mSpaceAutoCorrectionIndicator;
     private final Drawable mButtonArrowLeftIcon;
     private final Drawable mButtonArrowRightIcon;
     private final int mSpacebarTextColor;
     private final int mSpacebarTextShadowColor;
+    private final int mSpacebarVerticalCorrection;
     private float mSpacebarTextFadeFactor = 0.0f;
-    private final int[] mSpaceKeyIndexArray;
     private int mSpaceDragStartX;
     private int mSpaceDragLastDiff;
-    private final Context mContext;
     private boolean mCurrentlyInSpace;
     private SlidingLocaleDrawable mSlidingLocaleIcon;
+
+    /* Shortcut key and its icons if available */
+    private final Key mShortcutKey;
+    private final Drawable mEnabledShortcutIcon;
+    private final Drawable mDisabledShortcutIcon;
+
     private int[] mPrefLetterFrequencies;
     private int mPrefLetter;
     private int mPrefLetterX;
@@ -74,8 +86,6 @@
     // its short language name will be used instead.
     private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
 
-    private static int sSpacebarVerticalCorrection;
-
     private static final String SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "small";
     private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium";
 
@@ -83,21 +93,47 @@
         super(context, id.getXmlId(), id);
         final Resources res = context.getResources();
         mContext = context;
+
+        final List<Key> keys = getKeys();
+        int spaceKeyIndex = -1;
+        int shortcutKeyIndex = -1;
+        final int keyCount = keys.size();
+        for (int index = 0; index < keyCount; index++) {
+            // For now, assuming there are up to one space key and one shortcut key respectively.
+            switch (keys.get(index).mCode) {
+            case CODE_SPACE:
+                spaceKeyIndex = index;
+                break;
+            case CODE_VOICE:
+                shortcutKeyIndex = index;
+                break;
+            }
+        }
+
+        // The index of space key is available only after Keyboard constructor has finished.
+        mSpaceKey = (spaceKeyIndex >= 0) ? keys.get(spaceKeyIndex) : null;
+        mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon() : null;
+        mSpacePreviewIcon = (mSpaceKey != null) ? mSpaceKey.getPreviewIcon() : null;
+        mSpaceKeyIndexArray = new int[] { spaceKeyIndex };
+
+        mShortcutKey = (shortcutKeyIndex >= 0) ? keys.get(shortcutKeyIndex) : null;
+        mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null;
+
         mSpacebarTextColor = res.getColor(R.color.latinkeyboard_bar_language_text);
         if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
             mSpacebarTextShadowColor = res.getColor(
                     R.color.latinkeyboard_bar_language_shadow_black);
+            mDisabledShortcutIcon = res.getDrawable(R.drawable.sym_keyboard_mic_disabled);
         } else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
             mSpacebarTextShadowColor = res.getColor(
                     R.color.latinkeyboard_bar_language_shadow_white);
+            mDisabledShortcutIcon = res.getDrawable(R.drawable.sym_bkeyboard_mic_disabled);
         }
         mSpaceAutoCorrectionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
         mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
         mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
-        sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
+        mSpacebarVerticalCorrection = res.getDimensionPixelOffset(
                 R.dimen.spacebar_vertical_correction);
-        // The index of space key is available only after Keyboard constructor has finished.
-        mSpaceKeyIndexArray = new int[] { indexOf(CODE_SPACE) };
     }
 
     public void setSpacebarTextFadeFactor(float fadeFactor, LatinKeyboardView view) {
@@ -113,6 +149,15 @@
         return newColor;
     }
 
+    public void updateShortcutKey(boolean available, LatinKeyboardView view) {
+        if (mShortcutKey == null)
+            return;
+        mShortcutKey.mEnabled = available;
+        mShortcutKey.setIcon(available ? mEnabledShortcutIcon : mDisabledShortcutIcon);
+        if (view != null)
+            view.invalidateKey(mShortcutKey);
+    }
+
     /**
      * @return a key which should be invalidated.
      */
@@ -316,7 +361,7 @@
         int y = pointY;
         final int code = key.mCode;
         if (code == CODE_SPACE) {
-            y += LatinKeyboard.sSpacebarVerticalCorrection;
+            y += mSpacebarVerticalCorrection;
             if (SubtypeSwitcher.getInstance().useSpacebarLanguageSwitcher()
                     && SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
                 if (mCurrentlyInSpace) {
@@ -442,15 +487,6 @@
         }
     }
 
-    private int indexOf(int code) {
-        List<Key> keys = getKeys();
-        int count = keys.size();
-        for (int i = 0; i < count; i++) {
-            if (keys.get(i).mCode == code) return i;
-        }
-        return -1;
-    }
-
     private int getTextSizeFromTheme(int style, int defValue) {
         TypedArray array = mContext.getTheme().obtainStyledAttributes(
                 style, new int[] { android.R.attr.textSize });
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 49f29f9..cf379f0 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -561,7 +561,8 @@
                 codes[1] = codes[0];
                 codes[0] = code;
             }
-            callListenerOnCodeInput(code, codes, x, y);
+            if (key.mEnabled)
+                callListenerOnCodeInput(code, codes, x, y);
             callListenerOnRelease(code);
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index c1e14ad..67ca9aa 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -17,16 +17,23 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.LatinKeyboard;
+import com.android.inputmethod.keyboard.LatinKeyboardView;
 import com.android.inputmethod.voice.SettingsUtil;
 import com.android.inputmethod.voice.VoiceIMEConnector;
 import com.android.inputmethod.voice.VoiceInput;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 import android.os.IBinder;
 import android.text.TextUtils;
 import android.util.Log;
@@ -47,6 +54,8 @@
     private static final char LOCALE_SEPARATER = '_';
     private static final String KEYBOARD_MODE = "keyboard";
     private static final String VOICE_MODE = "voice";
+    private static final String SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY =
+            "requireNetworkConnectivity";
     private final TextUtils.SimpleStringSplitter mLocaleSplitter =
             new TextUtils.SimpleStringSplitter(LOCALE_SEPARATER);
 
@@ -55,17 +64,17 @@
     private /* final */ SharedPreferences mPrefs;
     private /* final */ InputMethodManager mImm;
     private /* final */ Resources mResources;
+    private /* final */ ConnectivityManager mConnectivityManager;
+    private /* final */ boolean mConfigUseSpacebarLanguageSwitcher;
     private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod =
             new ArrayList<InputMethodSubtype>();
     private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
 
-    private boolean mConfigUseSpacebarLanguageSwitcher;
-
     /*-----------------------------------------------------------*/
     // Variants which should be changed only by reload functions.
     private boolean mNeedsToDisplayLanguage;
     private boolean mIsSystemLanguageSameAsInputLanguage;
-    private InputMethodInfo mShortcutInfo;
+    private InputMethodInfo mShortcutInputMethodInfo;
     private InputMethodSubtype mShortcutSubtype;
     private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
     private Locale mSystemLocale;
@@ -75,6 +84,8 @@
     private VoiceInput mVoiceInput;
     /*-----------------------------------------------------------*/
 
+    private boolean mIsNetworkConnected;
+
     public static SubtypeSwitcher getInstance() {
         return sInstance;
     }
@@ -95,6 +106,8 @@
         mService = service;
         mResources = service.getResources();
         mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mConnectivityManager = (ConnectivityManager) service.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
         mEnabledLanguagesOfCurrentInputMethod.clear();
         mSystemLocale = null;
@@ -109,6 +122,17 @@
                 R.bool.config_use_spacebar_language_switcher);
         if (mConfigUseSpacebarLanguageSwitcher)
             initLanguageSwitcher(service);
+
+        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
+        mIsNetworkConnected = (info != null && info.isConnected());
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onNetworkStateChanged(intent);
+            }
+        };
+        service.registerReceiver(receiver,
+                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
     }
 
     // Update all parameters stored in SubtypeSwitcher.
@@ -165,7 +189,8 @@
     private void updateShortcutIME() {
         if (DBG) {
             Log.d(TAG, "Update shortcut IME from : "
-                    + (mShortcutInfo == null ? "<null>" : mShortcutInfo.getId()) + ", "
+                    + (mShortcutInputMethodInfo == null
+                            ? "<null>" : mShortcutInputMethodInfo.getId()) + ", "
                     + (mShortcutSubtype == null ? "<null>" : (mShortcutSubtype.getLocale()
                             + ", " + mShortcutSubtype.getMode())));
         }
@@ -176,7 +201,7 @@
             List<InputMethodSubtype> subtypes = shortcuts.get(imi);
             // TODO: Returns the first found IMI for now. Should handle all shortcuts as
             // appropriate.
-            mShortcutInfo = imi;
+            mShortcutInputMethodInfo = imi;
             // TODO: Pick up the first found subtype for now. Should handle all subtypes
             // as appropriate.
             mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null;
@@ -184,7 +209,8 @@
         }
         if (DBG) {
             Log.d(TAG, "Update shortcut IME to : "
-                    + (mShortcutInfo == null ? "<null>" : mShortcutInfo.getId()) + ", "
+                    + (mShortcutInputMethodInfo == null
+                            ? "<null>" : mShortcutInputMethodInfo.getId()) + ", "
                     + (mShortcutSubtype == null ? "<null>" : (mShortcutSubtype.getLocale()
                             + ", " + mShortcutSubtype.getMode())));
         }
@@ -289,10 +315,10 @@
 
     public void switchToShortcutIME() {
         final IBinder token = mService.getWindow().getWindow().getAttributes().token;
-        if (token == null || mShortcutInfo == null) {
+        if (token == null || mShortcutInputMethodInfo == null) {
             return;
         }
-        final String imiId = mShortcutInfo.getId();
+        final String imiId = mShortcutInputMethodInfo.getId();
         final InputMethodSubtype subtype = mShortcutSubtype;
         new Thread("SwitchToShortcutIME") {
             @Override
@@ -303,7 +329,7 @@
     }
 
     public Drawable getShortcutIcon() {
-        return getSubtypeIcon(mShortcutInfo, mShortcutSubtype);
+        return getSubtypeIcon(mShortcutInputMethodInfo, mShortcutSubtype);
     }
 
     private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
@@ -332,6 +358,38 @@
         return null;
     }
 
+    private static boolean contains(String[] hay, String needle) {
+        for (String element : hay) {
+            if (element.equals(needle))
+                return true;
+        }
+        return false;
+    }
+
+    public boolean isShortcutAvailable() {
+        if (mShortcutInputMethodInfo == null)
+            return false;
+        if (mShortcutSubtype != null && contains(mShortcutSubtype.getExtraValue().split(","),
+                    SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) {
+            return mIsNetworkConnected;
+        }
+        return true;
+    }
+
+    private void onNetworkStateChanged(Intent intent) {
+        final boolean noConnection = intent.getBooleanExtra(
+                ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+        mIsNetworkConnected = !noConnection;
+
+        final LatinKeyboardView inputView = KeyboardSwitcher.getInstance().getInputView();
+        if (inputView != null) {
+            final LatinKeyboard keyboard = inputView.getLatinKeyboard();
+            if (keyboard != null) {
+                keyboard.updateShortcutKey(isShortcutAvailable(), inputView);
+            }
+        }
+    }
+
     //////////////////////////////////
     // Language Switching functions //
     //////////////////////////////////