Merge "Add Icelandic keyboard"
diff --git a/java/res/values-en/donottranslate-more-keys.xml b/java/res/values-en/donottranslate-more-keys.xml
index 9073d3b..6e43e86 100644
--- a/java/res/values-en/donottranslate-more-keys.xml
+++ b/java/res/values-en/donottranslate-more-keys.xml
@@ -18,12 +18,46 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="more_keys_for_a">à,á,â,ä,æ,ã,å,ā</string>
-    <string name="more_keys_for_e">è,é,ê,ë,ē</string>
-    <string name="more_keys_for_i">î,ï,í,ī,ì</string>
-    <string name="more_keys_for_o">ô,ö,ò,ó,œ,ø,ō,õ</string>
-    <string name="more_keys_for_s">ß</string>
-    <string name="more_keys_for_u">û,ü,ù,ú,ū</string>
-    <string name="more_keys_for_n">ñ</string>
-    <string name="more_keys_for_c">ç</string>
+    <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+         U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+         U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+         U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+         U+00E6: "æ" LATIN SMALL LETTER AE
+         U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+         U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+         U+0101: "ā" LATIN SMALL LETTER A WITH MACRON -->
+    <string name="more_keys_for_a">&#x00E0;,&#x00E1;,&#x00E2;,&#x00E4;,&#x00E6;,&#x00E3;,&#x00E5;,&#x0101;</string>
+    <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+         U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+         U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+         U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+         U+0113: "ē" LATIN SMALL LETTER E WITH MACRON -->
+    <string name="more_keys_for_e">&#x00E8;,&#x00E9;,&#x00EA;,&#x00EB;,&#x0103;</string>
+    <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+         U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+         U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+         U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+         U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE -->
+    <string name="more_keys_for_i">&#x00EE;,&#x00EF;,&#x00ED;,&#x012B;,&#x00EC;</string>
+    <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+         U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+         U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+         U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+         U+0153: "œ" LATIN SMALL LIGATURE OE
+         U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+         U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+         U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE -->
+    <string name="more_keys_for_o">&#x00F4;,&#x00F6;,&#x00F2;,&#x00F3;,&#x0153;,&#x00F8;&#x014D;,&#x00F5;</string>
+    <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+         U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+         U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+         U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+         U+016B: "ū" LATIN SMALL LETTER U WITH MACRON -->
+    <string name="more_keys_for_u">&#x00FB;,&#x00FC;,&#x00F9;,&#x00FA;,&#x016B;</string>
+    <!-- U+00DF: "ß" LATIN SMALL LETTER SHARP S -->
+    <string name="more_keys_for_s">&#x00DF;</string>
+    <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE -->
+    <string name="more_keys_for_n">&#x00F1;</string>
+    <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA -->
+    <string name="more_keys_for_c">&#x00E7;</string>
 </resources>
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 3f6c374..7194cce 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -52,6 +52,7 @@
 import com.android.inputmethod.latin.SubtypeUtils;
 import com.android.inputmethod.latin.Utils;
 import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
+import com.android.inputmethod.latin.define.ProductionFlag;
 
 import java.util.Locale;
 import java.util.WeakHashMap;
@@ -694,15 +695,17 @@
                         + size + "," + pressure);
             }
         }
-        if (ResearchLogger.sIsLogging) {
-            // TODO: remove redundant calculations of size and pressure by
-            // removing UsabilityStudyLog code once the ResearchLogger is mature enough
-            final float size = me.getSize(index);
-            final float pressure = me.getPressure(index);
-            if (action != MotionEvent.ACTION_MOVE) {
-                // Skip ACTION_MOVE events as they are logged below
-                ResearchLogger.getInstance().logMotionEvent(action, eventTime, id, x,
-                        y, size, pressure);
+        if (ProductionFlag.IS_EXPERIMENTAL) {
+            if (ResearchLogger.sIsLogging) {
+                // TODO: remove redundant calculations of size and pressure by
+                // removing UsabilityStudyLog code once the ResearchLogger is mature enough
+                final float size = me.getSize(index);
+                final float pressure = me.getPressure(index);
+                if (action != MotionEvent.ACTION_MOVE) {
+                    // Skip ACTION_MOVE events as they are logged below
+                    ResearchLogger.getInstance().logMotionEvent(action, eventTime, id, x, y,
+                            size, pressure);
+                }
             }
         }
 
@@ -770,12 +773,14 @@
                             + pointerId + "," + px + "," + py + ","
                             + pointerSize + "," + pointerPressure);
                 }
-                if (ResearchLogger.sIsLogging) {
-                    // TODO: earlier comment about redundant calculations applies here too
-                    final float pointerSize = me.getSize(i);
-                    final float pointerPressure = me.getPressure(i);
-                    ResearchLogger.getInstance().logMotionEvent(action, eventTime, pointerId,
-                            px, py, pointerSize, pointerPressure);
+                if (ProductionFlag.IS_EXPERIMENTAL) {
+                    if (ResearchLogger.sIsLogging) {
+                        // TODO: earlier comment about redundant calculations applies here too
+                        final float pointerSize = me.getSize(i);
+                        final float pointerPressure = me.getPressure(i);
+                        ResearchLogger.getInstance().logMotionEvent(action, eventTime, pointerId,
+                                px, py, pointerSize, pointerPressure);
+                    }
                 }
             }
         } else {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 7272006..0669ee6 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -69,6 +69,7 @@
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.LatinKeyboardView;
 import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
+import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.suggestions.SuggestionsView;
 
 import java.io.FileDescriptor;
@@ -439,7 +440,9 @@
         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
         mPrefs = prefs;
         LatinImeLogger.init(this, prefs);
-        ResearchLogger.init(this, prefs);
+        if (ProductionFlag.IS_EXPERIMENTAL) {
+            ResearchLogger.init(this, prefs);
+        }
         LanguageSwitcherProxy.init(this, prefs);
         InputMethodManagerCompatWrapper.init(this);
         SubtypeSwitcher.init(this);
@@ -1264,8 +1267,10 @@
         }
         mLastKeyTime = when;
 
-        if (ResearchLogger.sIsLogging) {
-            ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y);
+        if (ProductionFlag.IS_EXPERIMENTAL) {
+            if (ResearchLogger.sIsLogging) {
+                ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y);
+            }
         }
 
         final KeyboardSwitcher switcher = mKeyboardSwitcher;
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index 079f3b5..732efad 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -80,8 +80,4 @@
 
     public static void onPrintAllUsabilityStudyLogs() {
     }
-
-    public static boolean isResearcherPackage(Context context) {
-        return false;
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java
index 3b110bd..0694ffe 100644
--- a/java/src/com/android/inputmethod/latin/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java
@@ -41,7 +41,7 @@
  * This class logs operations on the IME keyboard, including what the user has typed.
  * Data is stored locally in a file in app-specific storage.
  *
- * This functionality is off by default.
+ * This functionality is off by default. See {@link ProductionFlag.IS_EXPERIMENTAL}.
  */
 public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
     private static final String TAG = ResearchLogger.class.getSimpleName();
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 72391f3..1102648 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -46,6 +46,7 @@
 import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
 import com.android.inputmethod.compat.VibratorCompatWrapper;
 import com.android.inputmethod.deprecated.VoiceProxy;
+import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethodcommon.InputMethodSettingsActivity;
 
 import java.util.Locale;
@@ -238,17 +239,16 @@
             textCorrectionGroup.removePreference(dictionaryLink);
         }
 
-        final boolean isResearcherPackage = LatinImeLogger.isResearcherPackage(this);
         final boolean showUsabilityStudyModeOption =
                 res.getBoolean(R.bool.config_enable_usability_study_mode_option)
-                        || isResearcherPackage || ENABLE_EXPERIMENTAL_SETTINGS;
+                        || ProductionFlag.IS_EXPERIMENTAL || ENABLE_EXPERIMENTAL_SETTINGS;
         final Preference usabilityStudyPref = findPreference(PREF_USABILITY_STUDY_MODE);
         if (!showUsabilityStudyModeOption) {
             if (usabilityStudyPref != null) {
                 miscSettings.removePreference(usabilityStudyPref);
             }
         }
-        if (isResearcherPackage) {
+        if (ProductionFlag.IS_EXPERIMENTAL) {
             if (usabilityStudyPref instanceof CheckBoxPreference) {
                 CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
                 checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE, true));
diff --git a/tests/src/com/android/inputmethod/latin/ResearchLoggerTests.java b/tests/src/com/android/inputmethod/latin/ResearchLoggerTests.java
deleted file mode 100644
index 6ccc4f2..0000000
--- a/tests/src/com/android/inputmethod/latin/ResearchLoggerTests.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 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.inputmethod.latin;
-
-import android.inputmethodservice.InputMethodService;
-import android.os.Handler;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.inputmethod.latin.ResearchLogger.LogFileManager;
-
-import java.io.FileNotFoundException;
-
-public class ResearchLoggerTests extends InputTestsBase {
-
-    private static final String TAG = ResearchLoggerTests.class.getSimpleName();
-    private static final int TEST_INT = 0x12345678;
-    private static final long TEST_LONG = 0x1234567812345678L;
-
-    private static ResearchLogger sLogger;
-    private MockLogFileManager mMockLogFileManager;
-
-    @Override
-    protected void setUp() {
-        super.setUp();
-        sLogger = ResearchLogger.getInstance();
-        mMockLogFileManager = new MockLogFileManager();
-        sLogger.setLogFileManager(mMockLogFileManager);
-        ResearchLogger.sIsLogging = true;
-    }
-
-    public static class MockLogFileManager extends LogFileManager {
-        private final StringBuilder mContents = new StringBuilder();
-
-        @Override
-        public void init(InputMethodService ims) {
-        }
-
-        @Override
-        public synchronized void createLogFile() {
-            mContents.setLength(0);
-        }
-
-        @Override
-        public synchronized void createLogFile(String dir, String filename)
-                throws FileNotFoundException {
-            mContents.setLength(0);
-        }
-
-        @Override
-        public synchronized boolean append(String s) {
-            mContents.append(s);
-            return true;
-        }
-
-        @Override
-        public synchronized void reset() {
-            mContents.setLength(0);
-        }
-
-        @Override
-        public synchronized void close() {
-            mContents.setLength(0);
-        }
-
-        private String getAppendedString() {
-            return mContents.toString();
-        }
-    }
-
-    private void waitOnResearchLogger() {
-        // post another Runnable that notify()'s the test that it may proceed.
-        // assumes that the MessageQueue is processed in-order
-        Handler handler = sLogger.mLoggingHandler;
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                synchronized (ResearchLoggerTests.this) {
-                    ResearchLoggerTests.this.notify();
-                }
-            }
-        });
-        synchronized (this) {
-            try {
-                wait();
-            } catch (InterruptedException e) {
-                Log.i(TAG, "interrupted when waiting for handler to finish.", e);
-            }
-        }
-    }
-
-    /*********************** Tests *********************/
-    public void testLogStartsEmpty() {
-        waitOnResearchLogger();
-        String result = mMockLogFileManager.getAppendedString();
-        assertEquals(result, "");
-    }
-
-    public void testMotionEvent() {
-        // verify that input values appear somewhere in output
-        sLogger.logMotionEvent(MotionEvent.ACTION_CANCEL,
-                TEST_LONG, TEST_INT, 1111, 3333, 5555, 7777);
-        waitOnResearchLogger();
-        String output = mMockLogFileManager.getAppendedString();
-        assertTrue(output.matches("(?sui).*\\bcancel\\b.*"));
-        assertFalse(output.matches("(?sui).*\\bdown\\b.*"));
-        assertTrue(output.matches("(?s).*\\b" + TEST_LONG + "\\b.*"));
-        assertTrue(output.matches("(?s).*\\b" + TEST_INT + "\\b.*"));
-        assertTrue(output.matches("(?s).*\\b1111\\b.*"));
-        assertTrue(output.matches("(?s).*\\b3333\\b.*"));
-        assertTrue(output.matches("(?s).*\\b5555\\b.*"));
-        assertTrue(output.matches("(?s).*\\b7777\\b.*"));
-    }
-
-    public void testKeyEvent() {
-        type("abc");
-        waitOnResearchLogger();
-        String output = mMockLogFileManager.getAppendedString();
-        assertTrue(output.matches("(?s).*\\ba\\b.*"));
-        assertTrue(output.matches("(?s).*\\bb\\b.*"));
-        assertTrue(output.matches("(?s).*\\bc\\b.*"));
-    }
-
-    public void testCorrection() {
-        sLogger.logCorrection("aaaa", "thos", "this", 1);
-        waitOnResearchLogger();
-        String output = mMockLogFileManager.getAppendedString();
-        assertTrue(output.matches("(?sui).*\\baaaa\\b.*"));
-        assertTrue(output.matches("(?sui).*\\bthos\\b.*"));
-        assertTrue(output.matches("(?sui).*\\bthis\\b.*"));
-    }
-
-    public void testStateChange() {
-        sLogger.logStateChange("aaaa", "bbbb");
-        waitOnResearchLogger();
-        String output = mMockLogFileManager.getAppendedString();
-        assertTrue(output.matches("(?sui).*\\baaaa\\b.*"));
-        assertTrue(output.matches("(?sui).*\\bbbbb\\b.*"));
-    }
-
-    // TODO: add integration tests that start at point of event generation.
-}