Merge "Correction mode should not rely on the existence of the main dic"
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index cb0a9a2..d680f18 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -21,6 +21,14 @@
             <meta-data android:name="android.view.im" android:resource="@xml/method" />
         </service>
 
+        <service android:name=".spellcheck.AndroidSpellCheckerService"
+                 android:label="@string/spell_checker_service_name"
+                 android:permission="android.permission.BIND_TEXT_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.textservice.SpellCheckerService" />
+            </intent-filter>
+            <meta-data android:name="android.view.textservice.scs" android:resource="@xml/spellchecker" />
+        </service>
         <activity android:name="Settings" android:label="@string/english_ime_settings">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/java/res/drawable-hdpi/keyboard_background_holo.9.png b/java/res/drawable-hdpi/keyboard_background_holo.9.png
index 9f700c2..714db43 100644
--- a/java/res/drawable-hdpi/keyboard_background_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
index 85b6360..e173beb 100644
--- a/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
+++ b/java/res/drawable-hdpi/keyboard_suggest_strip_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/more_suggestions_hint.png b/java/res/drawable-hdpi/more_suggestions_hint.png
new file mode 100644
index 0000000..4515f44
--- /dev/null
+++ b/java/res/drawable-hdpi/more_suggestions_hint.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background_holo.9.png b/java/res/drawable-mdpi/keyboard_background_holo.9.png
index 4fe79b9..2776621 100644
--- a/java/res/drawable-mdpi/keyboard_background_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_holo.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_holo.9.png
index e488323..b1c18b4 100644
--- a/java/res/drawable-mdpi/keyboard_suggest_strip_holo.9.png
+++ b/java/res/drawable-mdpi/keyboard_suggest_strip_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/more_suggestions_hint.png b/java/res/drawable-mdpi/more_suggestions_hint.png
new file mode 100644
index 0000000..6168de3
--- /dev/null
+++ b/java/res/drawable-mdpi/more_suggestions_hint.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_background_holo.9.png
index 7b79f60..a0aa4ba 100644
--- a/java/res/drawable-xhdpi/keyboard_background_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_holo.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_holo.9.png
index b40f766..4c27072 100644
--- a/java/res/drawable-xhdpi/keyboard_suggest_strip_holo.9.png
+++ b/java/res/drawable-xhdpi/keyboard_suggest_strip_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/more_suggestions_hint.png b/java/res/drawable-xhdpi/more_suggestions_hint.png
new file mode 100644
index 0000000..f577a36
--- /dev/null
+++ b/java/res/drawable-xhdpi/more_suggestions_hint.png
Binary files differ
diff --git a/java/res/layout/candidates_strip.xml b/java/res/layout/candidates_strip.xml
index 269bc1b..bcc1322 100644
--- a/java/res/layout/candidates_strip.xml
+++ b/java/res/layout/candidates_strip.xml
@@ -29,31 +29,6 @@
         android:layout_width="0dp"
         android:layout_height="match_parent" />
     <LinearLayout
-        android:id="@+id/candidates_pane_control"
-        android:orientation="horizontal"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-    >
-        <TextView
-            android:id="@+id/expand_candidates_pane"
-            android:text="@string/label_expand_candidates_pane"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:minWidth="28dp"
-            android:textSize="@dimen/candidate_text_size"
-            android:visibility="visible" />
-        <TextView
-            android:id="@+id/close_candidates_pane"
-            android:text="@string/label_close_candidates_pane"
-            android:gravity="center"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:minWidth="28dp"
-            android:textSize="@dimen/candidate_text_size"
-            android:visibility="gone" />
-    </LinearLayout>
-    <LinearLayout
         android:id="@+id/touch_to_save"
         android:orientation="horizontal"
         android:layout_width="match_parent"
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 44e0914..2c4b35e 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -86,7 +86,7 @@
     <dimen name="candidate_padding">6dip</dimen>
     <dimen name="candidate_text_size">18dip</dimen>
     <integer name="candidate_count_in_strip">3</integer>
-    <integer name="center_candidate_percentile">40</integer>
+    <integer name="center_candidate_percentile">36</integer>
 
     <!-- If the screen height in landscape is larger than the below value, then the keyboard
          will not go into extract (fullscreen) mode. -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 1ebd2ce..c3a0f8b 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -149,6 +149,7 @@
         <item name="verticalGap">@fraction/key_bottom_gap_ics</item>
     </style>
     <style name="LatinKeyboard.IceCreamSandwich" parent="LatinKeyboard">
+        <item name="autoCorrectionSpacebarLedEnabled">false</item>
         <item name="disabledShortcutIcon">@drawable/sym_keyboard_voice_off_holo</item>
     </style>
     <style name="KeyboardView.IceCreamSandwich" parent="KeyboardView">
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 7a4e7ea..fbbc7fb 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -3,16 +3,16 @@
 /**
  * Copyright (c) 2008, 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 
+ * 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 
+ *     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 
+ * 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.
  */
 -->
diff --git a/java/res/xml/spellchecker.xml b/java/res/xml/spellchecker.xml
new file mode 100644
index 0000000..ce09264
--- /dev/null
+++ b/java/res/xml/spellchecker.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!-- The attributes in this XML file provide the configuration information -->
+<!-- for the spell checker -->
+
+<spell-checker xmlns:android="http://schemas.android.com/apk/res/android"
+        android:label="@string/spell_checker_service_name">
+    <subtype
+            android:label="@string/subtype_en_US"
+            android:subtypeLocale="en_US"
+    />
+    <subtype
+            android:label="@string/subtype_en_GB"
+            android:subtypeLocale="en_GB"
+    />
+</spell-checker>
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index db54ef6..1cf093c 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -38,6 +38,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
@@ -50,8 +51,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class CandidateView extends LinearLayout implements OnClickListener {
-
+public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
     public interface Listener {
         public boolean addWordToDictionary(String word);
         public void pickSuggestionManually(int index, CharSequence word);
@@ -65,9 +65,6 @@
     private static final boolean DBG = LatinImeLogger.sDBG;
 
     private final ViewGroup mCandidatesStrip;
-    private final ViewGroup mCandidatesPaneControl;
-    private final TextView mExpandCandidatesPane;
-    private final TextView mCloseCandidatesPane;
     private ViewGroup mCandidatesPane;
     private ViewGroup mCandidatesPaneContainer;
     private View mKeyboardView;
@@ -89,7 +86,7 @@
 
     private final SuggestionsStripParams mStripParams;
     private final SuggestionsPaneParams mPaneParams;
-    private static final float MIN_TEXT_XSCALE = 0.75f;
+    private static final float MIN_TEXT_XSCALE = 0.70f;
 
     private final UiHandler mHandler = new UiHandler(this);
 
@@ -146,7 +143,6 @@
         public final int mPadding;
         public final int mDividerWidth;
         public final int mDividerHeight;
-        public final int mControlWidth;
         public final int mCandidateStripHeight;
 
         protected final List<TextView> mWords;
@@ -154,7 +150,7 @@
         protected final List<TextView> mInfos;
 
         protected CandidateViewParams(List<TextView> words, List<View> dividers,
-                List<TextView> infos, View control) {
+                List<TextView> infos) {
             mWords = words;
             mDividers = dividers;
             mInfos = infos;
@@ -165,7 +161,6 @@
             divider.measure(WRAP_CONTENT, MATCH_PARENT);
             mDividerWidth = divider.getMeasuredWidth();
             mDividerHeight = divider.getMeasuredHeight();
-            mControlWidth = control.getMeasuredWidth();
 
             final Resources res = word.getResources();
             mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
@@ -174,8 +169,8 @@
 
     private static class SuggestionsPaneParams extends CandidateViewParams {
         public SuggestionsPaneParams(List<TextView> words, List<View> dividers,
-                List<TextView> infos, View control) {
-            super(words, dividers, infos, control);
+                List<TextView> infos) {
+            super(words, dividers, infos);
         }
 
         public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor,
@@ -268,6 +263,7 @@
         private final int mCandidateCountInStrip;
         private final float mCenterCandidateWeight;
         private final int mCenterCandidateIndex;
+        private final Drawable mMoreCandidateHint;
 
         private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
         private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
@@ -282,9 +278,11 @@
 
         private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
 
+        public boolean mMoreSuggestionsAvailable;
+
         public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle,
-                List<TextView> words, List<View> dividers, List<TextView> infos, View control) {
-            super(words, dividers, infos, control);
+                List<TextView> words, List<View> dividers, List<TextView> infos) {
+            super(words, dividers, infos);
             final TypedArray a = context.obtainStyledAttributes(
                     attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
             mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
@@ -300,12 +298,14 @@
             a.recycle();
 
             mCenterCandidateIndex = mCandidateCountInStrip / 2;
+            final Resources res = context.getResources();
+            mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint);
 
             mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
             mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
 
             mPaint = new TextPaint();
-            final float textSize = context.getResources().getDimension(R.dimen.candidate_text_size);
+            final float textSize = res.getDimension(R.dimen.candidate_text_size);
             mPaint.setTextSize(textSize);
         }
 
@@ -387,8 +387,6 @@
 
             final int countInStrip = mCandidateCountInStrip;
             setupTexts(suggestions, countInStrip);
-            final int maxWidth = (suggestions.size() <= countInStrip)
-                    ? stripWidth : stripWidth - mControlWidth;
 
             int x = 0;
             for (int index = 0; index < countInStrip; index++) {
@@ -402,10 +400,20 @@
 
                 final CharSequence styled = mTexts.get(pos);
                 final TextView word = mWords.get(pos);
+                if (index == mCenterCandidateIndex && suggestions.size() > countInStrip) {
+                    // TODO: This "more suggestions hint" should have nicely designed icon.
+                    word.setCompoundDrawablesWithIntrinsicBounds(
+                            null, null, null, mMoreCandidateHint);
+                    mMoreSuggestionsAvailable = true;
+                } else {
+                    word.setCompoundDrawables(null, null, null, null);
+                    mMoreSuggestionsAvailable = false;
+                }
+
                 // Disable this candidate if the suggestion is null or empty.
                 word.setEnabled(!TextUtils.isEmpty(styled));
                 word.setTextColor(getCandidateTextColor(index, suggestions, pos));
-                final int width = getCandidateWidth(index, maxWidth);
+                final int width = getCandidateWidth(index, stripWidth);
                 final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
                 final float scaleX = word.getTextScaleX();
                 word.setText(text); // TextView.setText() resets text scale x to 1.0.
@@ -476,9 +484,11 @@
                 final CharSequence text = suggestions.getWord(index);
                 word.setText(text);
                 word.setTextScaleX(1.0f);
+                word.setCompoundDrawables(null, null, null, null);
                 stripView.addView(word);
                 setLayoutWeight(word, 1.0f, mCandidateStripHeight);
             }
+            mMoreSuggestionsAvailable = false;
             return countInStrip;
         }
     }
@@ -521,6 +531,7 @@
             final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null);
             word.setTag(pos);
             word.setOnClickListener(this);
+            word.setOnLongClickListener(this);
             mWords.add(word);
             final View divider = inflater.inflate(R.layout.candidate_divider, null);
             divider.setTag(pos);
@@ -533,41 +544,9 @@
         mWordToSave = (TextView)findViewById(R.id.word_to_save);
         mWordToSave.setOnClickListener(this);
 
-        final TypedArray keyboardViewAttr = context.obtainStyledAttributes(
-                attrs, R.styleable.KeyboardView, R.attr.keyboardViewStyle, R.style.KeyboardView);
-        final Drawable expandBackground = keyboardViewAttr.getDrawable(
-                R.styleable.KeyboardView_keyBackground);
-        final Drawable closeBackground = keyboardViewAttr.getDrawable(
-                R.styleable.KeyboardView_keyBackground);
-        final int keyTextColor = keyboardViewAttr.getColor(
-                R.styleable.KeyboardView_keyTextColor, 0xFF000000);
-        keyboardViewAttr.recycle();
-
-        mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control);
-        mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane);
-        mExpandCandidatesPane.setBackgroundDrawable(expandBackground);
-        mExpandCandidatesPane.setTextColor(keyTextColor);
-        mExpandCandidatesPane.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                expandCandidatesPane();
-            }
-        });
-        mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane);
-        mCloseCandidatesPane.setBackgroundDrawable(closeBackground);
-        mCloseCandidatesPane.setTextColor(keyTextColor);
-        mCloseCandidatesPane.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                closeCandidatesPane();
-            }
-        });
-        mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT);
-
-        mStripParams = new SuggestionsStripParams(context, attrs, defStyle,
-                mWords, mDividers, mInfos, mCandidatesPaneControl);
-        mPaneParams = new SuggestionsPaneParams(
-                mWords, mDividers, mInfos, mCandidatesPaneControl);
+        mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers,
+                mInfos);
+        mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos);
     }
 
     /**
@@ -588,7 +567,6 @@
         if (suggestions == null)
             return;
         mSuggestions = suggestions;
-        mExpandCandidatesPane.setEnabled(false);
         if (mShowingAutoCorrectionInverted) {
             mHandler.postUpdateSuggestions();
         } else {
@@ -607,14 +585,6 @@
                 mSuggestions, mCandidatesStrip, mCandidatesPane, width);
         final int countInPane = mPaneParams.layout(
                 mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width);
-
-        if (countInPane <= 0 && !DBG) {
-            mCandidatesPaneControl.setVisibility(GONE);
-        } else {
-            mCandidatesPaneControl.setVisibility(VISIBLE);
-            mExpandCandidatesPane.setVisibility(VISIBLE);
-            mExpandCandidatesPane.setEnabled(true);
-        }
     }
 
     private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
@@ -713,16 +683,12 @@
     }
 
     private void expandCandidatesPane() {
-        mExpandCandidatesPane.setVisibility(GONE);
-        mCloseCandidatesPane.setVisibility(VISIBLE);
         mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
         mCandidatesPaneContainer.setVisibility(VISIBLE);
         mKeyboardView.setVisibility(GONE);
     }
 
     private void closeCandidatesPane() {
-        mExpandCandidatesPane.setVisibility(VISIBLE);
-        mCloseCandidatesPane.setVisibility(GONE);
         mCandidatesPaneContainer.setVisibility(GONE);
         mKeyboardView.setVisibility(VISIBLE);
     }
@@ -744,7 +710,6 @@
         mWordToSave.setText(word);
         mShowingAddToDictionary = true;
         mCandidatesStrip.setVisibility(GONE);
-        mCandidatesPaneControl.setVisibility(GONE);
         mTouchToSave.setVisibility(VISIBLE);
     }
 
@@ -803,6 +768,15 @@
     }
 
     @Override
+    public boolean onLongClick(View view) {
+        if (mStripParams.mMoreSuggestionsAvailable) {
+            expandCandidatesPane();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
     public void onClick(View view) {
         if (view == mWordToSave) {
             addToDictionary(((TextView)view).getText());
@@ -810,6 +784,11 @@
             return;
         }
 
+        if (view == mCandidatesPane) {
+            closeCandidatesPane();
+            return;
+        }
+
         final Object tag = view.getTag();
         if (!(tag instanceof Integer))
             return;