diff options
Diffstat (limited to 'java')
5 files changed, 406 insertions, 11 deletions
diff --git a/java/res/xml/keyboard_layout_set_nordic.xml b/java/res/xml/keyboard_layout_set_nordic.xml index d07f78a9a..eb3d45be0 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 846e4968a..a778ee80b 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 @@ public final class KeyboardTextsTable { /* 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 @@ public final class KeyboardTextsTable { /* 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 @@ public final class KeyboardTextsTable { // 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 @@ public final class KeyboardTextsTable { /* 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 @@ public final class KeyboardTextsTable { /* 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 000000000..31aba3631 --- /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 000000000..0d0cbe169 --- /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 000000000..35b65be56 --- /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; + } +} |