Add functions to enable / disable spell checker

Bug: 5057977

Change-Id: I2b27bd5f55feb305368034d7e95f83257ac4b3e6
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 15c57e6..be154e6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3785,6 +3785,13 @@
                 "selected_spell_checker_subtype";
 
         /**
+         * The {@link ComponentName} string whether spell checker is enabled or not.
+         *
+         * @hide
+         */
+        public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled";
+
+        /**
          * What happens when the user presses the Power button while in-call
          * and the screen is on.<br/>
          * <b>Values:</b><br/>
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index bb13052..5dca348 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -170,5 +170,26 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public void setSpellCheckerEnabled(boolean enabled) {
+        try {
+            sService.setSpellCheckerEnabled(enabled);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in setSpellCheckerSubtype:" + e);
+        }
+    }
 
+    /**
+     * @hide
+     */
+    public boolean isSpellCheckerEnabled() {
+        try {
+            return sService.isSpellCheckerEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in setSpellCheckerSubtype:" + e);
+            return false;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index cc30c176..b18af02 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -37,5 +37,7 @@
     oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
     oneway void setCurrentSpellChecker(String locale, String sciId);
     oneway void setCurrentSpellCheckerSubtype(String locale, int hashCode);
+    oneway void setSpellCheckerEnabled(boolean enabled);
+    boolean isSpellCheckerEnabled();
     SpellCheckerInfo[] getEnabledSpellCheckers();
 }
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 18ddabd..321274f 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -173,7 +173,7 @@
     @Override
     public SpellCheckerInfo getCurrentSpellChecker(String locale) {
         synchronized (mSpellCheckerMap) {
-            String curSpellCheckerId =
+            final String curSpellCheckerId =
                     Settings.Secure.getString(mContext.getContentResolver(),
                             Settings.Secure.SELECTED_SPELL_CHECKER);
             if (DBG) {
@@ -197,10 +197,16 @@
                 Slog.w(TAG, "getCurrentSpellChecker: " + subtypeHashCodeStr);
             }
             final SpellCheckerInfo sci = getCurrentSpellChecker(null);
-            if (sci.getSubtypeCount() == 0) {
+            if (sci == null || sci.getSubtypeCount() == 0) {
+                if (DBG) {
+                    Slog.w(TAG, "Subtype not found.");
+                }
                 return null;
             }
             if (TextUtils.isEmpty(subtypeHashCodeStr)) {
+                if (DBG) {
+                    Slog.w(TAG, "Return first subtype in " + sci.getId());
+                }
                 // Return the first Subtype if there is no settings for the current subtype.
                 return sci.getSubtypeAt(0);
             }
@@ -208,9 +214,15 @@
             for (int i = 0; i < sci.getSubtypeCount(); ++i) {
                 final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
                 if (scs.hashCode() == hashCode) {
+                    if (DBG) {
+                        Slog.w(TAG, "Return subtype " + scs.hashCode());
+                    }
                     return scs;
                 }
             }
+            if (DBG) {
+                Slog.w(TAG, "Return first subtype in " + sci.getId());
+            }
             return sci.getSubtypeAt(0);
         }
     }
@@ -283,6 +295,13 @@
         return;
     }
 
+    @Override
+    public boolean isSpellCheckerEnabled() {
+        synchronized(mSpellCheckerMap) {
+            return isSpellCheckerEnabledLocked();
+        }
+    }
+
     private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
             ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
             int uid, Bundle bundle) {
@@ -354,7 +373,21 @@
                         "Requires permission "
                         + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
-            setCurrentSpellCheckerLocked(hashCode);
+            setCurrentSpellCheckerSubtypeLocked(hashCode);
+        }
+    }
+
+    @Override
+    public void setSpellCheckerEnabled(boolean enabled) {
+        synchronized(mSpellCheckerMap) {
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException(
+                        "Requires permission "
+                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+            }
+            setSpellCheckerEnabledLocked(enabled);
         }
     }
 
@@ -372,7 +405,7 @@
         }
     }
 
-    private void setCurrentSpellCheckerLocked(int hashCode) {
+    private void setCurrentSpellCheckerSubtypeLocked(int hashCode) {
         if (DBG) {
             Slog.w(TAG, "setCurrentSpellCheckerSubtype: " + hashCode);
         }
@@ -397,6 +430,33 @@
         }
     }
 
+    private void setSpellCheckerEnabledLocked(boolean enabled) {
+        if (DBG) {
+            Slog.w(TAG, "setSpellCheckerEnabled: " + enabled);
+        }
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private boolean isSpellCheckerEnabledLocked() {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            final boolean retval = Settings.Secure.getInt(mContext.getContentResolver(),
+                    Settings.Secure.SPELL_CHECKER_ENABLED, 1) == 1;
+            if (DBG) {
+                Slog.w(TAG, "getSpellCheckerEnabled: " + retval);
+            }
+            return retval;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     // SpellCheckerBindGroup contains active text service session listeners.
     // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
     // mSpellCheckerBindGroups