Merge "Rename PrevWordsInfo to NgramContext."
diff --git a/java/res/xml/keyboard_layout_set_nordic.xml b/java/res/xml/keyboard_layout_set_nordic.xml
index d07f78a..eb3d45b 100644
--- a/java/res/xml/keyboard_layout_set_nordic.xml
+++ b/java/res/xml/keyboard_layout_set_nordic.xml
@@ -24,7 +24,7 @@
         latin:elementName="alphabet"
         latin:elementKeyboard="@xml/kbd_nordic"
         latin:enableProximityCharsCorrection="true"
-        latin:allowRedundantMoreKeys="true" />
+        latin:allowRedundantMoreKeys="false" />
     <Element
         latin:elementName="symbols"
         latin:elementKeyboard="@xml/kbd_symbols" />
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index 846e496..a778ee8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -952,20 +952,24 @@
 
     /* Locale da: Danish */
     private static final String[] TEXTS_da = {
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
         // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
         // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
         // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
         // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
         // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
         // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-        /* morekeys_a */ "\u00E1,\u00E4,\u00E0,\u00E2,\u00E3,\u0101",
+        /* morekeys_a */ "\u00E5,\u00E6,\u00E1,\u00E4,\u00E0,\u00E2,\u00E3,\u0101",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
         // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
         // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
         // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
         // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
         // U+0153: "œ" LATIN SMALL LIGATURE OE
         // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-        /* morekeys_o */ "\u00F3,\u00F4,\u00F2,\u00F5,\u0153,\u014D",
+        /* morekeys_o */ "\u00F8,\u00F6,\u00F3,\u00F4,\u00F2,\u00F5,\u0153,\u014D",
         // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
         // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
         /* morekeys_e */ "\u00E9,\u00EB",
@@ -1666,13 +1670,16 @@
 
     /* Locale fi: Finnish */
     private static final String[] TEXTS_fi = {
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
         // U+00E6: "æ" LATIN SMALL LETTER AE
         // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
         // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-        /* morekeys_a */ "\u00E6,\u00E0,\u00E1,\u00E2,\u00E3,\u0101",
+        /* morekeys_a */ "\u00E4,\u00E5,\u00E6,\u00E0,\u00E1,\u00E2,\u00E3,\u0101",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
         // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
         // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
         // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
@@ -1680,7 +1687,7 @@
         // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
         // U+0153: "œ" LATIN SMALL LIGATURE OE
         // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-        /* morekeys_o */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
+        /* morekeys_o */ "\u00F6,\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
         /* morekeys_e */ null,
         // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
         /* morekeys_u */ "\u00FC",
@@ -2784,21 +2791,24 @@
 
     /* Locale nb: Norwegian Bokmål */
     private static final String[] TEXTS_nb = {
-        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
         // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
         // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-        /* morekeys_a */ "\u00E0,\u00E4,\u00E1,\u00E2,\u00E3,\u0101",
+        /* morekeys_a */ "\u00E5,\u00E6,\u00E4,\u00E0,\u00E1,\u00E2,\u00E3,\u0101",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
         // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
         // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
         // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
         // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
         // U+0153: "œ" LATIN SMALL LIGATURE OE
         // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-        /* morekeys_o */ "\u00F4,\u00F2,\u00F3,\u00F6,\u00F5,\u0153,\u014D",
+        /* morekeys_o */ "\u00F8,\u00F6,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
         // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
         // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
         // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -3381,18 +3391,24 @@
 
     /* Locale sv: Swedish */
     private static final String[] TEXTS_sv = {
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING
+        // U+00E6: "æ" LATIN SMALL LETTER AE
         // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
         // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
         // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
         // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
         // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-        /* morekeys_a */ "\u00E1,\u00E0,\u00E2,\u0105,\u00E3",
+        /* morekeys_a */ "\u00E4,\u00E5,\u00E6,\u00E1,\u00E0,\u00E2,\u0105,\u00E3",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
         // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
         // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
         // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
         // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
         // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-        /* morekeys_o */ "\u00F3,\u00F2,\u00F4,\u00F5,\u014D",
+        /* morekeys_o */ "\u00F6,\u00F8,\u0153,\u00F3,\u00F2,\u00F4,\u00F5,\u014D",
         // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
         // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
         // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
diff --git a/java/src/com/android/inputmethod/latin/accounts/AuthUtils.java b/java/src/com/android/inputmethod/latin/accounts/AuthUtils.java
new file mode 100644
index 0000000..31aba36
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/accounts/AuthUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 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.accounts;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+
+import java.io.IOException;
+
+/**
+ * Utility class that handles generation/invalidation of auth tokens in the app.
+ */
+public class AuthUtils {
+    private final AccountManager mAccountManager;
+
+    public AuthUtils(Context context) {
+        mAccountManager = AccountManager.get(context);
+    }
+
+    /**
+     * @see AccountManager#invalidateAuthToken(String, String)
+     */
+    public void invalidateAuthToken(final String accountType, final String authToken) {
+        mAccountManager.invalidateAuthToken(accountType, authToken);
+    }
+
+    /**
+     * @see AccountManager#getAuthToken(
+     *              Account, String, Bundle, boolean, AccountManagerCallback, Handler)
+     */
+    public AccountManagerFuture<Bundle> getAuthToken(final Account account,
+            final String authTokenType, final Bundle options, final boolean notifyAuthFailure,
+            final AccountManagerCallback<Bundle> callback, final Handler handler) {
+        return mAccountManager.getAuthToken(account, authTokenType, options, notifyAuthFailure,
+                callback, handler);
+    }
+
+    /**
+     * @see AccountManager#blockingGetAuthToken(Account, String, boolean)
+     */
+    public String blockingGetAuthToken(final Account account, final String authTokenType,
+            final boolean notifyAuthFailure) throws OperationCanceledException,
+            AuthenticatorException, IOException {
+        return mAccountManager.blockingGetAuthToken(account, authTokenType, notifyAuthFailure);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java b/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java
new file mode 100644
index 0000000..0d0cbe1
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 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.network;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * A client for executing HTTP requests synchronously.
+ * This must never be called from the main thread.
+ *
+ * TODO: Remove @UsedForTesting after this is actually used.
+ */
+@UsedForTesting
+public class BlockingHttpClient {
+    private final HttpURLConnection mConnection;
+
+    /**
+     * Interface that handles processing the response for a request.
+     */
+    public interface ResponseProcessor {
+        /**
+         * Called when the HTTP request fails with an error.
+         *
+         * @param httpStatusCode The status code of the HTTP response.
+         * @param message The HTTP response message, if any, or null.
+         */
+        void onError(int httpStatusCode, @Nullable String message);
+
+        /**
+         * Called when the HTTP request finishes successfully.
+         * The {@link InputStream} is closed by the client after the method finishes,
+         * so any processing must be done in this method itself.
+         *
+         * @param response An input stream that can be used to read the HTTP response.
+         */
+        void onSuccess(InputStream response);
+    }
+
+    /**
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public BlockingHttpClient(HttpURLConnection connection) {
+        mConnection = connection;
+    }
+
+    /**
+     * Executes the request on the underlying {@link HttpURLConnection}.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     *
+     * @param request The request payload, if any, or null.
+     * @param responeProcessor A processor for the HTTP response.
+     */
+    @UsedForTesting
+    public void execute(@Nullable byte[] request, @Nonnull ResponseProcessor responseProcessor)
+            throws IOException {
+        try {
+            if (request != null) {
+                OutputStream out = new BufferedOutputStream(mConnection.getOutputStream());
+                out.write(request);
+                out.flush();
+                out.close();
+            }
+
+            final int responseCode = mConnection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                responseProcessor.onError(responseCode, mConnection.getResponseMessage());
+            } else {
+                responseProcessor.onSuccess(mConnection.getInputStream());
+            }
+        } finally {
+            mConnection.disconnect();
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java b/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java
new file mode 100644
index 0000000..35b65be
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 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.network;
+
+import android.text.TextUtils;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+/**
+ * Builder for {@link HttpURLConnection}s.
+ *
+ * TODO: Remove @UsedForTesting after this is actually used.
+ */
+@UsedForTesting
+public class HttpUrlConnectionBuilder {
+    private static final int DEFAULT_TIMEOUT_MILLIS = 5 * 1000;
+
+    /**
+     * Request header key for cache control.
+     */
+    public static final String KEY_CACHE_CONTROL = "Cache-Control";
+    /**
+     * Request header value for cache control indicating no caching.
+     * @see #KEY_CACHE_CONTROL
+     */
+    public static final String VALUE_NO_CACHE = "no-cache";
+
+    /**
+     * Indicates that the request is unidirectional - upload-only.
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public static final int MODE_UPLOAD_ONLY = 1;
+    /**
+     * Indicates that the request is unidirectional - download only.
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public static final int MODE_DOWNLOAD_ONLY = 2;
+    /**
+     * Indicates that the request is bi-directional.
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public static final int MODE_BI_DIRECTIONAL = 3;
+
+    private final HashMap<String, String> mHeaderMap = new HashMap<>();
+
+    private URL mUrl;
+    private int mConnectTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
+    private int mReadTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
+    private int mContentLength = -1;
+    private boolean mUseCache;
+    private int mMode;
+
+    /**
+     * Sets the URL that'll be used for the request.
+     * This *must* be set before calling {@link #build()}
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setUrl(String url) throws MalformedURLException {
+        if (TextUtils.isEmpty(url)) {
+            throw new IllegalArgumentException("URL must not be empty");
+        }
+        mUrl = new URL(url);
+        return this;
+    }
+
+    /**
+     * Sets the connect timeout. Defaults to {@value #DEFAULT_TIMEOUT} milliseconds.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setConnectTimeout(int timeoutMillis) {
+        if (timeoutMillis < 0) {
+            throw new IllegalArgumentException("connect-timeout must be >= 0, but was "
+                    + timeoutMillis);
+        }
+        mConnectTimeoutMillis = timeoutMillis;
+        return this;
+    }
+
+    /**
+     * Sets the read timeout. Defaults to {@value #DEFAULT_TIMEOUT} milliseconds.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setReadTimeout(int timeoutMillis) {
+        if (timeoutMillis < 0) {
+            throw new IllegalArgumentException("read-timeout must be >= 0, but was "
+                    + timeoutMillis);
+        }
+        mReadTimeoutMillis = timeoutMillis;
+        return this;
+    }
+
+    /**
+     * Adds an entry to the request header.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder addHeader(String key, String value) {
+        mHeaderMap.put(key, value);
+        return this;
+    }
+
+    /**
+     * Sets the request to be executed such that the input is not buffered.
+     * This may be set when the request size is known beforehand.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setFixedLengthForStreaming(int length) {
+        mContentLength = length;
+        return this;
+    }
+
+    /**
+     * Indicates if the request can use cached responses or not.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setUseCache(boolean useCache) {
+        mUseCache = useCache;
+        return this;
+    }
+
+    /**
+     * The request mode.
+     * Sets the request mode to be one of: upload-only, download-only or bidirectional.
+     *
+     * @see #MODE_UPLOAD_ONLY
+     * @see #MODE_DOWNLOAD_ONLY
+     * @see #MODE_BI_DIRECTIONAL
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpUrlConnectionBuilder setMode(int mode) {
+        if (mode != MODE_UPLOAD_ONLY
+                && mode != MODE_DOWNLOAD_ONLY
+                && mode != MODE_BI_DIRECTIONAL) {
+            throw new IllegalArgumentException("Invalid mode specified:" + mode);
+        }
+        mMode = mode;
+        return this;
+    }
+
+    /**
+     * Builds the {@link HttpURLConnection} instance that can be used to execute the request.
+     *
+     * TODO: Remove @UsedForTesting after this is actually used.
+     */
+    @UsedForTesting
+    public HttpURLConnection build() throws IOException {
+        if (mUrl == null) {
+            throw new IllegalArgumentException("A URL must be specified!");
+        }
+        final HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+        connection.setConnectTimeout(mConnectTimeoutMillis);
+        connection.setReadTimeout(mReadTimeoutMillis);
+        connection.setUseCaches(mUseCache);
+        switch (mMode) {
+            case MODE_UPLOAD_ONLY:
+                connection.setDoInput(true);
+                connection.setDoOutput(false);
+                break;
+            case MODE_DOWNLOAD_ONLY:
+                connection.setDoInput(false);
+                connection.setDoOutput(true);
+                break;
+            case MODE_BI_DIRECTIONAL:
+                connection.setDoInput(true);
+                connection.setDoOutput(true);
+                break;
+        }
+        for (final Entry<String, String> entry : mHeaderMap.entrySet()) {
+            connection.addRequestProperty(entry.getKey(), entry.getValue());
+        }
+        if (mContentLength >= 0) {
+            connection.setFixedLengthStreamingMode(mContentLength);
+        }
+        return connection;
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
index eb11278..b714ec7 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
@@ -51,6 +51,24 @@
         }
 
         /**
+         * Set accented letters to a specific keyboard element.
+         * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
+         *        layout.
+         * @param elementId the element id of keyboard
+         * @return the {@link ExpectedKeyboardBuilder} object that contains accented letters as
+         *        "more keys".
+         */
+        public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder,
+                final int elementId) {
+            // This method can be overridden by an extended class to provide customized expected
+            // accented letters depending on the shift state of keyboard.
+            // This is a default behavior to call a shift-state-independent
+            // {@link #setAccentedLetters(ExpectedKeyboardBuilder)} implementation, so that
+            // <code>elementId</code> is ignored here.
+            return setAccentedLetters(builder);
+        }
+
+        /**
          * Set accented letters to common layout.
          * @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
          *        layout.
@@ -386,7 +404,7 @@
     ExpectedKey[][] getCommonAlphabetShiftLayout(final boolean isPhone, final int elementId) {
         final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
                 getCommonAlphabetLayout(isPhone));
-        getCustomizer().setAccentedLetters(builder);
+        getCustomizer().setAccentedLetters(builder, elementId);
         builder.toUpperCase(getLocale());
         return builder.build();
     }
@@ -411,7 +429,7 @@
         final ExpectedKeyboardBuilder builder;
         if (elementId == KeyboardId.ELEMENT_ALPHABET) {
             builder = new ExpectedKeyboardBuilder(getCommonAlphabetLayout(isPhone));
-            getCustomizer().setAccentedLetters(builder);
+            getCustomizer().setAccentedLetters(builder, elementId);
         } else {
             final ExpectedKey[][] commonLayout = getCommonAlphabetShiftLayout(isPhone, elementId);
             if (commonLayout == null) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/DanishCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/DanishCustomizer.java
index b7c181b..2c5df60 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/DanishCustomizer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/DanishCustomizer.java
@@ -53,9 +53,35 @@
                 .setMoreKeysOf("\u00F8", "\u00F6");
     }
 
+    protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                .setMoreKeysOf("a", "\u00E1", "\u00E4", "\u00E0", "\u00E2", "\u00E3", "\u0101");
+    }
+
+    protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                // U+0153: "œ" LATIN SMALL LIGATURE OE
+                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                .setMoreKeysOf("o", "\u00F6", "\u00F3", "\u00F4", "\u00F2", "\u00F5", "\u0153",
+                        "\u014D");
+    }
+
     @Override
     public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
         setNordicKeys(builder);
+        setMoreKeysOfA(builder);
+        setMoreKeysOfO(builder);
         return builder
                 // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
                 // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -72,20 +98,6 @@
                 // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
                 // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
                 .setMoreKeysOf("i", "\u00ED", "\u00EF")
-                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
-                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
-                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                // U+0153: "œ" LATIN SMALL LIGATURE OE
-                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-                .setMoreKeysOf("o", "\u00F3", "\u00F4", "\u00F2", "\u00F5", "\u0153", "\u014D")
-                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
-                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
-                // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
-                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
-                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-                .setMoreKeysOf("a", "\u00E1", "\u00E4", "\u00E0", "\u00E2", "\u00E3", "\u0101")
                 // U+00DF: "ß" LATIN SMALL LETTER SHARP S
                 // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
                 // U+0161: "š" LATIN SMALL LETTER S WITH CARON
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/EstonianEECustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/EstonianEECustomizer.java
new file mode 100644
index 0000000..d0b8772
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/EstonianEECustomizer.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014 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.keyboard.layout.tests;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer;
+import com.android.inputmethod.keyboard.layout.Nordic;
+import com.android.inputmethod.keyboard.layout.Symbols;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+
+import java.util.Locale;
+
+class EstonianEECustomizer extends EuroCustomizer {
+    public EstonianEECustomizer(final Locale locale) {
+        super(locale);
+    }
+
+    @Override
+    public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; }
+
+    @Override
+    public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; }
+
+    protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+                .replaceKeyOfLabel(Nordic.ROW1_11, "\u00FC")
+                // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                .replaceKeyOfLabel(Nordic.ROW2_10, "\u00F6")
+                .setMoreKeysOf("\u00F6", "\u00F5")
+                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                .replaceKeyOfLabel(Nordic.ROW2_11, "\u00E4");
+    }
+
+    protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                // U+00E6: "æ" LATIN SMALL LETTER AE
+                // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+                .setMoreKeysOf("a", "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u00E5",
+                        "\u00E6", "\u0105");
+    }
+
+    protected void setMoreKeysOfI(final ExpectedKeyboardBuilder builder, final int elementId) {
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        if (elementId == KeyboardId.ELEMENT_ALPHABET) {
+            builder.setMoreKeysOf("i",
+                    "\u012B", "\u00EC", "\u012F", "\u00ED", "\u00EE", "\u00EF", "\u0131");
+        } else {
+            // The upper-case letter of "ı" in Estonian locale is "I". It should be omitted
+            // from the more keys of "I".
+            builder.setMoreKeysOf("i",
+                    "\u012B", "\u00EC", "\u012F", "\u00ED", "\u00EE", "\u00EF");
+        }
+    }
+
+    protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                // U+0153: "œ" LATIN SMALL LIGATURE OE
+                // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+                // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                .setMoreKeysOf("o", "\u00F5", "\u00F2", "\u00F3", "\u00F4", "\u0153", "\u0151",
+                        "\u00F8");
+    }
+
+    protected void setMoreKeysOfU(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+                // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+                // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+                // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+                // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+                // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+                // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+                .setMoreKeysOf("u", "\u016B", "\u0173", "\u00F9", "\u00FA", "\u00FB", "\u016F",
+                        "\u0171");
+    }
+
+    @Override
+    public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder,
+            final int elementId) {
+        setNordicKeys(builder);
+        setMoreKeysOfA(builder);
+        setMoreKeysOfI(builder, elementId);
+        setMoreKeysOfO(builder);
+        setMoreKeysOfU(builder);
+        return builder
+                // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+                // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+                // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+                // 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+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+                // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+                .setMoreKeysOf("e",
+                        "\u0113", "\u00E8", "\u0117", "\u00E9", "\u00EA", "\u00EB", "\u0119",
+                        "\u011B")
+                // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+                // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+                // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+                .setMoreKeysOf("r", "\u0157", "\u0159", "\u0155")
+                // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+                // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+                .setMoreKeysOf("t", "\u0163", "\u0165")
+                // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+                // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+                .setMoreKeysOf("y", "\u00FD", "\u00FF")
+                // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+                // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+                // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+                // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+                .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F")
+                // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+                .setMoreKeysOf("d", "\u010F")
+                // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+                // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+                .setMoreKeysOf("g", "\u0123", "\u011F")
+                // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+                .setMoreKeysOf("k", "\u0137")
+                // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+                // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+                // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+                // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+                .setMoreKeysOf("l", "\u013C", "\u0142", "\u013A", "\u013E")
+                // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+                // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+                // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+                .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A")
+                // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+                // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+                // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+                .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107")
+                // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+                // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+                // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+                .setMoreKeysOf("n", "\u0146", "\u00F1", "\u0144");
+    }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/FinnishCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/FinnishCustomizer.java
index 9adb637..912aec4 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/FinnishCustomizer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/FinnishCustomizer.java
@@ -39,12 +39,19 @@
                 .setMoreKeysOf("\u00E4", "\u00E6");
     }
 
-    @Override
-    public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
-        setNordicKeys(builder);
-        return builder
-                // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
-                .setMoreKeysOf("u", "\u00FC")
+    protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00E6: "æ" LATIN SMALL LETTER AE
+                // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                .setMoreKeysOf("a", "\u00E6", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u0101");
+    }
+
+    protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+        builder
                 // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
                 // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
                 // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
@@ -52,15 +59,18 @@
                 // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
                 // U+0153: "œ" LATIN SMALL LIGATURE OE
                 // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-                .setMoreKeysOf("o",
-                        "\u00F8", "\u00F4", "\u00F2", "\u00F3", "\u00F5", "\u0153", "\u014D")
-                // U+00E6: "æ" LATIN SMALL LETTER AE
-                // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-                .setMoreKeysOf("a", "\u00E6", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u0101")
+                .setMoreKeysOf("o", "\u00F8", "\u00F4", "\u00F2", "\u00F3", "\u00F5", "\u0153",
+                        "\u014D");
+    }
+
+    @Override
+    public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
+        setNordicKeys(builder);
+        setMoreKeysOfA(builder);
+        setMoreKeysOfO(builder);
+        return builder
+                // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+                .setMoreKeysOf("u", "\u00FC")
                 // U+0161: "š" LATIN SMALL LETTER S WITH CARON
                 // U+00DF: "ß" LATIN SMALL LETTER SHARP S
                 // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/NorwegianCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/NorwegianCustomizer.java
index 3d3ed4b..4be7a57 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/NorwegianCustomizer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/NorwegianCustomizer.java
@@ -47,9 +47,35 @@
                 .setMoreKeysOf("\u00E6", "\u00E4");
     }
 
+    protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                .setMoreKeysOf("a", "\u00E4", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u0101");
+    }
+
+    protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                // U+0153: "œ" LATIN SMALL LIGATURE OE
+                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                .setMoreKeysOf("o", "\u00F6", "\u00F4", "\u00F2", "\u00F3", "\u00F5", "\u0153",
+                        "\u014D");
+    }
+
     @Override
     public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
         setNordicKeys(builder);
+        setMoreKeysOfA(builder);
+        setMoreKeysOfO(builder);
         return builder
                 // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
                 // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -65,22 +91,6 @@
                 // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
                 // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
                 // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
-                .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B")
-                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
-                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
-                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-                // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
-                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                // U+0153: "œ" LATIN SMALL LIGATURE OE
-                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-                .setMoreKeysOf("o",
-                        "\u00F4", "\u00F2", "\u00F3", "\u00F6", "\u00F5", "\u0153", "\u014D")
-                // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
-                // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
-                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
-                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
-                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-                .setMoreKeysOf("a", "\u00E0", "\u00E4", "\u00E1", "\u00E2", "\u00E3", "\u0101");
+                .setMoreKeysOf("u", "\u00FC", "\u00FB", "\u00F9", "\u00FA", "\u016B");
     }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/SwedishCustomizer.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/SwedishCustomizer.java
index 36b55b1..af4a971 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/SwedishCustomizer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/SwedishCustomizer.java
@@ -64,9 +64,35 @@
                 .setMoreKeysOf("\u00E4", "\u00E6");
     }
 
+    protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00E6: "æ" LATIN SMALL LETTER AE
+                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+                // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+                // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                .setMoreKeysOf("a", "\u00E6", "\u00E1", "\u00E0", "\u00E2", "\u0105", "\u00E3");
+    }
+
+    protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+        builder
+                // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                // U+0153: "œ" LATIN SMALL LIGATURE OE
+                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                .setMoreKeysOf("o", "\u00F8", "\u0153", "\u00F3", "\u00F2", "\u00F4", "\u00F5",
+                        "\u014D");
+    }
+
     @Override
     public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
         setNordicKeys(builder);
+        setMoreKeysOfA(builder);
+        setMoreKeysOfO(builder);
         return builder
                 // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
                 // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -93,18 +119,6 @@
                 // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
                 // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
                 .setMoreKeysOf("i", "\u00ED", "\u00EC", "\u00EE", "\u00EF")
-                // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-                // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
-                // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
-                // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
-                .setMoreKeysOf("o", "\u00F3", "\u00F2", "\u00F4", "\u00F5", "\u014D")
-                // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
-                // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
-                // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
-                // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
-                // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                .setMoreKeysOf("a", "\u00E1", "\u00E0", "\u00E2", "\u0105", "\u00E3")
                 // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
                 // U+0161: "š" LATIN SMALL LETTER S WITH CARON
                 // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanishQwertz.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanishQwertz.java
index a53a3d4..886b3de 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanishQwertz.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDanishQwertz.java
@@ -44,5 +44,35 @@
         protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
             // QWERTZ layout doesn't have Nordic keys.
         }
+
+        @Override
+        protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+00E6: "æ" LATIN SMALL LETTER AE
+                    // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+                    // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+                    // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                    .setMoreKeysOf("a", "\u00E5", "\u00E6", "\u00E1", "\u00E4", "\u00E0", "\u00E2",
+                            "\u00E3", "\u0101");
+        }
+
+        @Override
+        protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    // U+0153: "œ" LATIN SMALL LIGATURE OE
+                    // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                    .setMoreKeysOf("o", "\u00F8", "\u00F6", "\u00F3", "\u00F4", "\u00F2", "\u00F5",
+                            "\u0153", "\u014D");
+        }
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java
index 865e9ea..28c2eb3 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEE.java
@@ -19,11 +19,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.inputmethod.keyboard.layout.LayoutBase;
-import com.android.inputmethod.keyboard.layout.LayoutBase.EuroCustomizer;
 import com.android.inputmethod.keyboard.layout.Nordic;
-import com.android.inputmethod.keyboard.layout.Symbols;
-import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
-import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
 
 import java.util.Locale;
 
@@ -37,121 +33,4 @@
 
     @Override
     LayoutBase getLayout() { return LAYOUT; }
-
-    private static class EstonianEECustomizer extends EuroCustomizer {
-        public EstonianEECustomizer(final Locale locale) {
-            super(locale);
-        }
-
-        @Override
-        public ExpectedKey[] getDoubleQuoteMoreKeys() { return Symbols.DOUBLE_QUOTES_R9L; }
-
-        @Override
-        public ExpectedKey[] getSingleQuoteMoreKeys() { return Symbols.SINGLE_QUOTES_R9L; }
-
-        @Override
-        public ExpectedKeyboardBuilder setAccentedLetters(final ExpectedKeyboardBuilder builder) {
-            return builder
-                    // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
-                    // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
-                    // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
-                    // 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+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
-                    // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
-                    .setMoreKeysOf("e",
-                            "\u0113", "\u00E8", "\u0117", "\u00E9", "\u00EA", "\u00EB", "\u0119",
-                            "\u011B")
-                    // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
-                    // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
-                    // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
-                    .setMoreKeysOf("r", "\u0157", "\u0159", "\u0155")
-                    // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
-                    // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
-                    .setMoreKeysOf("t", "\u0163", "\u0165")
-                    // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
-                    // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
-                    .setMoreKeysOf("y", "\u00FD", "\u00FF")
-                    // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
-                    // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
-                    // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
-                    // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
-                    // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
-                    // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
-                    // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
-                    // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
-                    .setMoreKeysOf("u",
-                            "\u00FC", "\u016B", "\u0173", "\u00F9", "\u00FA", "\u00FB", "\u016F",
-                            "\u0171")
-                    // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
-                    // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
-                    // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
-                    // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
-                    // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
-                    // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
-                    // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
-                    .setMoreKeysOf("i",
-                            "\u012B", "\u00EC", "\u012F", "\u00ED", "\u00EE", "\u00EF", "\u0131")
-                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
-                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
-                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
-                    // U+0153: "œ" LATIN SMALL LIGATURE OE
-                    // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
-                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
-                    .setMoreKeysOf("o",
-                            "\u00F6", "\u00F5", "\u00F2", "\u00F3", "\u00F4", "\u0153", "\u0151",
-                            "\u00F8")
-                    // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
-                    .replaceKeyOfLabel(Nordic.ROW1_11, "\u00FC")
-                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
-                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
-                    .replaceKeyOfLabel(Nordic.ROW2_10, key("\u00F6", moreKey("\u00F5")))
-                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
-                    .replaceKeyOfLabel(Nordic.ROW2_11, "\u00E4")
-                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
-                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
-                    // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
-                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
-                    // U+00E6: "æ" LATIN SMALL LETTER AE
-                    // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
-                    .setMoreKeysOf("a",
-                            "\u00E4", "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3", "\u00E5",
-                            "\u00E6", "\u0105")
-                    // U+0161: "š" LATIN SMALL LETTER S WITH CARON
-                    // U+00DF: "ß" LATIN SMALL LETTER SHARP S
-                    // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
-                    // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
-                    .setMoreKeysOf("s", "\u0161", "\u00DF", "\u015B", "\u015F")
-                    // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
-                    .setMoreKeysOf("d", "\u010F")
-                    // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
-                    // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
-                    .setMoreKeysOf("g", "\u0123", "\u011F")
-                    // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
-                    .setMoreKeysOf("k", "\u0137")
-                    // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
-                    // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
-                    // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
-                    // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
-                    .setMoreKeysOf("l", "\u013C", "\u0142", "\u013A", "\u013E")
-                    // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
-                    // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
-                    // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
-                    .setMoreKeysOf("z", "\u017E", "\u017C", "\u017A")
-                    // U+010D: "č" LATIN SMALL LETTER C WITH CARON
-                    // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
-                    // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
-                    .setMoreKeysOf("c", "\u010D", "\u00E7", "\u0107")
-                    // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
-                    // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
-                    // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
-                    .setMoreKeysOf("n", "\u0146", "\u00F1", "\u0144");
-        }
-    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEEQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEEQwerty.java
new file mode 100644
index 0000000..ab8960b
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEstonianEEQwerty.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 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.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+
+import java.util.Locale;
+
+/**
+ * et_EE: Estonian (Estonia)/qwerty
+ */
+@SmallTest
+public final class TestsEstonianEEQwerty extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("et", "EE");
+    private static final LayoutBase LAYOUT = new Qwerty(new EstonianEEQwertyCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    private static class EstonianEEQwertyCustomizer extends EstonianEECustomizer {
+        public EstonianEEQwertyCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
+            // QWERTY layout doesn't have Nordic keys.
+        }
+
+        @Override
+        protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                    // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+00E6: "æ" LATIN SMALL LETTER AE
+                    // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+                    .setMoreKeysOf("a", "\u00E4", "\u0101", "\u00E0", "\u00E1", "\u00E2", "\u00E3",
+                            "\u00E5", "\u00E6", "\u0105");
+        }
+
+        @Override
+        protected void setMoreKeysOfI(final ExpectedKeyboardBuilder builder, final int elementId) {
+            // TODO: The upper-case letter of "ı" in Estonian locale is "I". It should be omitted
+            // from the more keys of "I".
+            builder
+                    // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+                    // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+                    // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+                    // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+                    // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+                    // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+                    // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+                    .setMoreKeysOf("i",
+                            "\u012B", "\u00EC", "\u012F", "\u00ED", "\u00EE", "\u00EF", "\u0131");
+        }
+
+        @Override
+        protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+0153: "œ" LATIN SMALL LIGATURE OE
+                    // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    .setMoreKeysOf("o", "\u00F6", "\u00F5", "\u00F2", "\u00F3", "\u00F4", "\u0153",
+                            "\u0151", "\u00F8");
+        }
+
+        @Override
+        protected void setMoreKeysOfU(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+                    // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+                    // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+                    // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+                    // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+                    // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+                    // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+                    // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+                    .setMoreKeysOf("u", "\u00FC", "\u016B", "\u0173", "\u00F9", "\u00FA", "\u00FB",
+                            "\u016F", "\u0171");
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnishQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnishQwerty.java
index 2838fef..c3df9d1 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnishQwerty.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsFinnishQwerty.java
@@ -44,5 +44,35 @@
         protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
             // QWERTY layout doesn't have Nordic keys.
         }
+
+        @Override
+        protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+00E6: "æ" LATIN SMALL LETTER AE
+                    // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                    .setMoreKeysOf("a", "\u00E4", "\u00E5", "\u00E6", "\u00E0", "\u00E1", "\u00E2",
+                            "\u00E3", "\u0101");
+        }
+
+        @Override
+        protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    // U+0153: "œ" LATIN SMALL LIGATURE OE
+                    // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                    .setMoreKeysOf("o", "\u00F6", "\u00F8", "\u00F4", "\u00F2", "\u00F3", "\u00F5",
+                            "\u0153", "\u014D");
+        }
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegianColemak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegianColemak.java
index 6c3f8b9..a481796 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegianColemak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsNorwegianColemak.java
@@ -44,5 +44,36 @@
         protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
             // Colemak layout doesn't have Nordic keys.
         }
+
+        @Override
+        protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // 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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+                    .setMoreKeysOf("a", "\u00E5", "\u00E6", "\u00E4", "\u00E0", "\u00E1", "\u00E2",
+                            "\u00E3", "\u0101");
+        }
+
+        @Override
+        protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    // U+0153: "œ" LATIN SMALL LIGATURE OE
+                    // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                    .setMoreKeysOf("o", "\u00F8", "\u00F6", "\u00F4", "\u00F2", "\u00F3", "\u00F5",
+                            "\u0153", "\u014D");
+        }
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedishPcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedishPcQwerty.java
index bb4b9dd..ed74d6d 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedishPcQwerty.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSwedishPcQwerty.java
@@ -85,5 +85,36 @@
         protected void setNordicKeys(final ExpectedKeyboardBuilder builder) {
             // PC QWERTY layout doesn't have Nordic keys.
         }
+
+        @Override
+        protected void setMoreKeysOfA(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+                    // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+                    // U+00E6: "æ" LATIN SMALL LETTER AE
+                    // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+                    // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+                    // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+                    // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+                    // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+                    .setMoreKeysOf("a", "\u00E4", "\u00E5", "\u00E6", "\u00E1", "\u00E0", "\u00E2",
+                            "\u0105", "\u00E3");
+        }
+
+        @Override
+        protected void setMoreKeysOfO(final ExpectedKeyboardBuilder builder) {
+            builder
+                    // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+                    // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+                    // U+0153: "œ" LATIN SMALL LIGATURE OE
+                    // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+                    // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+                    // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+                    // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+                    // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+                    .setMoreKeysOf("o", "\u00F6", "\u00F8", "\u0153", "\u00F3", "\u00F2", "\u00F4",
+                            "\u00F5", "\u014D");
+        }
+
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java b/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java
new file mode 100644
index 0000000..d151732
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 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.network;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.latin.network.BlockingHttpClient.ResponseProcessor;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Tests for {@link BlockingHttpClient}.
+ */
+@SmallTest
+public class BlockingHttpClientTests extends AndroidTestCase {
+    @Mock HttpURLConnection mMockHttpConnection;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testError_badGateway() throws IOException {
+        when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_GATEWAY);
+        final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
+        final FakeErrorResponseProcessor processor =
+                new FakeErrorResponseProcessor(HttpURLConnection.HTTP_BAD_GATEWAY);
+
+        client.execute(null /* empty request */, processor);
+        assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+    }
+
+    public void testError_clientTimeout() throws IOException {
+        when(mMockHttpConnection.getResponseCode()).thenReturn(
+                HttpURLConnection.HTTP_CLIENT_TIMEOUT);
+        final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
+        final FakeErrorResponseProcessor processor =
+                new FakeErrorResponseProcessor(HttpURLConnection.HTTP_CLIENT_TIMEOUT);
+
+        client.execute(null /* empty request */, processor);
+        assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+    }
+
+    public void testError_forbiddenWithRequest() throws IOException {
+        final OutputStream mockOutputStream = Mockito.mock(OutputStream.class);
+        when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_FORBIDDEN);
+        when(mMockHttpConnection.getOutputStream()).thenReturn(mockOutputStream);
+        final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
+        final FakeErrorResponseProcessor processor =
+                new FakeErrorResponseProcessor(HttpURLConnection.HTTP_FORBIDDEN);
+
+        client.execute(new byte[100], processor);
+        verify(mockOutputStream).write(any(byte[].class), eq(0), eq(100));
+        assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+    }
+
+    public void testSuccess_emptyRequest() throws IOException {
+        final Random rand = new Random();
+        byte[] response = new byte[100];
+        rand.nextBytes(response);
+        when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+        when(mMockHttpConnection.getInputStream()).thenReturn(new ByteArrayInputStream(response));
+        final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
+        final FakeSuccessResponseProcessor processor =
+                new FakeSuccessResponseProcessor(response);
+
+        client.execute(null /* empty request */, processor);
+        assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+    }
+
+    public void testSuccess() throws IOException {
+        final OutputStream mockOutputStream = Mockito.mock(OutputStream.class);
+        final Random rand = new Random();
+        byte[] response = new byte[100];
+        rand.nextBytes(response);
+        when(mMockHttpConnection.getOutputStream()).thenReturn(mockOutputStream);
+        when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+        when(mMockHttpConnection.getInputStream()).thenReturn(new ByteArrayInputStream(response));
+        final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
+        final FakeSuccessResponseProcessor processor =
+                new FakeSuccessResponseProcessor(response);
+
+        client.execute(new byte[100], processor);
+        assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+    }
+
+    private static class FakeErrorResponseProcessor implements ResponseProcessor {
+        private final int mExpectedStatusCode;
+
+        boolean mInvoked;
+
+        FakeErrorResponseProcessor(int expectedStatusCode) {
+            mExpectedStatusCode = expectedStatusCode;
+        }
+
+        @Override
+        public void onError(int httpStatusCode, String message) {
+            mInvoked = true;
+            assertEquals("onError:", mExpectedStatusCode, httpStatusCode);
+        }
+
+        @Override
+        public void onSuccess(InputStream response) {
+            fail("Expected an error but received success");
+        }
+    }
+
+    private static class FakeSuccessResponseProcessor implements ResponseProcessor {
+        private final byte[] mExpectedResponse;
+
+        boolean mInvoked;
+
+        FakeSuccessResponseProcessor(byte[] expectedResponse) {
+            mExpectedResponse = expectedResponse;
+        }
+
+        @Override
+        public void onError(int httpStatusCode, String message) {
+            fail("Expected a response but received an error");
+        }
+
+        @Override
+        public void onSuccess(InputStream response) {
+            try {
+                mInvoked = true;
+                BufferedInputStream in = new BufferedInputStream(response);
+                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+                int read = 0;
+                while ((read = in.read()) != -1) {
+                    buffer.write(read);
+                }
+                byte[] actualResponse = buffer.toByteArray();
+                in.close();
+                assertTrue("Response doesn't match",
+                        Arrays.equals(mExpectedResponse, actualResponse));
+            } catch (IOException ex) {
+                fail("IOException in onSuccess");
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java b/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java
new file mode 100644
index 0000000..2b43d5b
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2014 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.network;
+
+import static com.android.inputmethod.latin.network.HttpUrlConnectionBuilder.MODE_BI_DIRECTIONAL;
+import static com.android.inputmethod.latin.network.HttpUrlConnectionBuilder.MODE_DOWNLOAD_ONLY;
+import static com.android.inputmethod.latin.network.HttpUrlConnectionBuilder.MODE_UPLOAD_ONLY;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+
+
+/**
+ * Tests for {@link HttpUrlConnectionBuilder}.
+ */
+@SmallTest
+public class HttpUrlConnectionBuilderTests extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testSetUrl_malformed() {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        try {
+            builder.setUrl("dadasd!@%@!:11");
+            fail("Expected a MalformedURLException.");
+        } catch (MalformedURLException e) {
+            // Expected
+        }
+    }
+
+    public void testSetConnectTimeout_invalid() {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        try {
+            builder.setConnectTimeout(-1);
+            fail("Expected an IllegalArgumentException.");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    public void testSetConnectTimeout() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("https://www.example.com");
+        builder.setConnectTimeout(8765);
+        HttpURLConnection connection = builder.build();
+        assertEquals(8765, connection.getConnectTimeout());
+    }
+
+    public void testSetReadTimeout_invalid() {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        try {
+            builder.setReadTimeout(-1);
+            fail("Expected an IllegalArgumentException.");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    public void testSetReadTimeout() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("https://www.example.com");
+        builder.setReadTimeout(8765);
+        HttpURLConnection connection = builder.build();
+        assertEquals(8765, connection.getReadTimeout());
+    }
+
+    public void testAddHeader() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("http://www.example.com");
+        builder.addHeader("some-random-key", "some-random-value");
+        HttpURLConnection connection = builder.build();
+        assertEquals("some-random-value", connection.getRequestProperty("some-random-key"));
+    }
+
+    public void testSetUseCache_notSet() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("http://www.example.com");
+        HttpURLConnection connection = builder.build();
+        assertFalse(connection.getUseCaches());
+    }
+
+    public void testSetUseCache_false() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("http://www.example.com");
+        HttpURLConnection connection = builder.build();
+        connection.setUseCaches(false);
+        assertFalse(connection.getUseCaches());
+    }
+
+    public void testSetUseCache_true() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("http://www.example.com");
+        HttpURLConnection connection = builder.build();
+        connection.setUseCaches(true);
+        assertTrue(connection.getUseCaches());
+    }
+
+    public void testSetMode_uploadOnly() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("http://www.example.com");
+        builder.setMode(MODE_UPLOAD_ONLY);
+        HttpURLConnection connection = builder.build();
+        assertTrue(connection.getDoInput());
+        assertFalse(connection.getDoOutput());
+    }
+
+    public void testSetMode_downloadOnly() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("https://www.example.com");
+        builder.setMode(MODE_DOWNLOAD_ONLY);
+        HttpURLConnection connection = builder.build();
+        assertFalse(connection.getDoInput());
+        assertTrue(connection.getDoOutput());
+    }
+
+    public void testSetMode_bidirectional() throws IOException {
+        HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+        builder.setUrl("https://www.example.com");
+        builder.setMode(MODE_BI_DIRECTIONAL);
+        HttpURLConnection connection = builder.build();
+        assertTrue(connection.getDoInput());
+        assertTrue(connection.getDoOutput());
+    }
+}
diff --git a/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml
index c22e262..98abb05 100644
--- a/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-da/donottranslate-more-keys.xml
@@ -18,26 +18,30 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+    <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+         U+00E6: "æ" LATIN SMALL LETTER AE
+         U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
          U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
          U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
          U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
          U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
          U+0101: "ā" LATIN SMALL LETTER A WITH MACRON -->
-    <string name="morekeys_a">&#x00E1;,&#x00E4;,&#x00E0;,&#x00E2;,&#x00E3;,&#x0101;</string>
+    <string name="morekeys_a">&#x00E5;,&#x00E6;,&#x00E1;,&#x00E4;,&#x00E0;,&#x00E2;,&#x00E3;,&#x0101;</string>
     <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
          U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS -->
     <string name="morekeys_e">&#x00E9;,&#x00EB;</string>
     <!-- U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
          U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS -->
     <string name="morekeys_i">&#x00ED;,&#x00EF;</string>
-    <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+    <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+         U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+         U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
          U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
          U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
          U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
          U+0153: "œ" LATIN SMALL LIGATURE OE
          U+014D: "ō" LATIN SMALL LETTER O WITH MACRON -->
-    <string name="morekeys_o">&#x00F3;,&#x00F4;,&#x00F2;,&#x00F5;,&#x0153;,&#x014D;</string>
+    <string name="morekeys_o">&#x00F8;,&#x00F6;,&#x00F3;,&#x00F4;,&#x00F2;,&#x00F5;,&#x0153;,&#x014D;</string>
     <!-- U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
          U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
          U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
diff --git a/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml
index 9a8fa3c..79266e8 100644
--- a/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-et-rEE/donottranslate-more-keys.xml
@@ -72,7 +72,6 @@
          U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
          U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE -->
     <string name="morekeys_n">&#x0146;,&#x00F1;,&#x0144;</string>
-
     <!-- U+010D: "č" LATIN SMALL LETTER C WITH CARON
          U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
          U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE -->
diff --git a/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml
index 82b8472..b06d9e4 100644
--- a/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-fi/donottranslate-more-keys.xml
@@ -18,21 +18,24 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+00E6: "æ" LATIN SMALL LETTER AE
+    <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+         U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+         U+00E6: "æ" LATIN SMALL LETTER AE
          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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
          U+0101: "ā" LATIN SMALL LETTER A WITH MACRON -->
-    <string name="morekeys_a">&#x00E6;,&#x00E0;,&#x00E1;,&#x00E2;,&#x00E3;,&#x0101;</string>
-    <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+    <string name="morekeys_a">&#x00E4;,&#x00E5;,&#x00E6;,&#x00E0;,&#x00E1;,&#x00E2;,&#x00E3;,&#x0101;</string>
+    <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+         U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
          U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
          U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
          U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
          U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
          U+0153: "œ" LATIN SMALL LIGATURE OE
          U+014D: "ō" LATIN SMALL LETTER O WITH MACRON -->
-    <string name="morekeys_o">&#x00F8;,&#x00F4;,&#x00F2;,&#x00F3;,&#x00F5;,&#x0153;,&#x014D;</string>
+    <string name="morekeys_o">&#x00F6;,&#x00F8;,&#x00F4;,&#x00F2;,&#x00F3;,&#x00F5;,&#x0153;,&#x014D;</string>
     <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS -->
     <string name="morekeys_u">&#x00FC;</string>
     <!-- U+0161: "š" LATIN SMALL LETTER S WITH CARON
diff --git a/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml
index c5307a9..37f9f8a 100644
--- a/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-nb/donottranslate-more-keys.xml
@@ -18,13 +18,15 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+    <!-- U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+         U+00E6: "æ" LATIN SMALL LETTER AE
          U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+         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+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
          U+0101: "ā" LATIN SMALL LETTER A WITH MACRON -->
-    <string name="morekeys_a">&#x00E0;,&#x00E4;,&#x00E1;,&#x00E2;,&#x00E3;,&#x0101;</string>
+    <string name="morekeys_a">&#x00E5;,&#x00E6;,&#x00E4;,&#x00E0;,&#x00E1;,&#x00E2;,&#x00E3;,&#x0101;</string>
     <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
          U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
          U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -33,14 +35,15 @@
          U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
          U+0113: "ē" LATIN SMALL LETTER E WITH MACRON -->
     <string name="morekeys_e">&#x00E9;,&#x00E8;,&#x00EA;,&#x00EB;,&#x0119;,&#x0117;,&#x0113;</string>
-    <!-- U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+    <!-- U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+         U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+         U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
          U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
          U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
-         U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
          U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
          U+0153: "œ" LATIN SMALL LIGATURE OE
          U+014D: "ō" LATIN SMALL LETTER O WITH MACRON -->
-    <string name="morekeys_o">&#x00F4;,&#x00F2;,&#x00F3;,&#x00F6;,&#x00F5;,&#x0153;,&#x014D;</string>
+    <string name="morekeys_o">&#x00F8;,&#x00F6;,&#x00F4;,&#x00F2;,&#x00F3;,&#x00F5;,&#x0153;,&#x014D;</string>
     <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
          U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
          U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
diff --git a/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml
index ead5140..832e438 100644
--- a/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-sv/donottranslate-more-keys.xml
@@ -18,12 +18,15 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+    <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+         U+00E5: "å" LATIN SMALL LETTER A WITH RING
+         U+00E6: "æ" LATIN SMALL LETTER AE
+         U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
          U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
          U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
          U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
          U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE -->
-    <string name="morekeys_a">&#x00E1;,&#x00E0;,&#x00E2;,&#x0105;,&#x00E3;</string>
+    <string name="morekeys_a">&#x00E4;,&#x00E5;,&#x00E6;,&#x00E1;,&#x00E0;,&#x00E2;,&#x0105;,&#x00E3;</string>
     <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
          U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
          U+010D: "č" LATIN SMALL LETTER C WITH CARON -->
@@ -48,12 +51,15 @@
          U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
          U+0148: "ň" LATIN SMALL LETTER N WITH CARON -->
     <string name="morekeys_n">&#x0144;,&#x00F1;,&#x0148;</string>
-    <!-- U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+    <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+         U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+         U+0153: "œ" LATIN SMALL LIGATURE OE
+         U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
          U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
          U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
          U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
          U+014D: "ō" LATIN SMALL LETTER O WITH MACRON -->
-    <string name="morekeys_o">&#x00F3;,&#x00F2;,&#x00F4;,&#x00F5;,&#x014D;</string>
+    <string name="morekeys_o">&#x00F6;,&#x00F8;,&#x0153;,&#x00F3;,&#x00F2;,&#x00F4;,&#x00F5;,&#x014D;</string>
     <!-- U+0159: "ř" LATIN SMALL LETTER R WITH CARON -->
     <string name="morekeys_r">&#x0159;</string>
     <!-- U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE