diff --git a/build.gradle b/build.gradle index bb7070325..d10ea21d8 100644 --- a/build.gradle +++ b/build.gradle @@ -125,6 +125,7 @@ android { dimension "buildType" buildConfigField "boolean", "IS_PLAYSTORE_BUILD", "false" buildConfigField "boolean", "UPDATE_CHECKING", "true" + getIsDefault().set(true) } playstore { dimension "buildType" @@ -205,9 +206,9 @@ dependencies { implementation 'androidx.datastore:datastore-preferences:1.0.0' implementation 'androidx.autofill:autofill:1.1.0' - implementation 'ch.acra:acra-http:5.11.1' // TODO: Remove upon release - implementation 'ch.acra:acra-mail:5.11.1' - implementation 'ch.acra:acra-dialog:5.11.1' + stableImplementation 'ch.acra:acra-http:5.11.1' // TODO: Remove upon release + stableImplementation 'ch.acra:acra-mail:5.11.1' + stableImplementation 'ch.acra:acra-dialog:5.11.1' implementation 'com.squareup.okhttp3:okhttp:4.11.0' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1' diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 5f7316c8c..0857d5e10 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -16,27 +16,16 @@ - - - - - - - - + - - - - - - - - - - - - accountVocabulary = - AccountUtils.getDeviceAccountsEmailAddresses(mContext); - if (accountVocabulary == null || accountVocabulary.isEmpty()) { - return; - } - for (String word : accountVocabulary) { - if (DEBUG) { - Log.d(TAG, "loadAccountVocabulary: " + word); - } - runGCIfRequiredLocked(true /* mindsBlockByGC */); - addUnigramLocked(word, ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS, - null, 0, - false /* isNotAWord */, false /* isPossiblyOffensive */, - BinaryDictionary.NOT_A_VALID_TIMESTAMP); - } - } - - /** - * Loads data within content providers to the dictionary. - */ - private void loadDictionaryForUriLocked(final Uri uri) { - if (!PermissionsUtil.checkAllPermissionsGranted( - mContext, Manifest.permission.READ_CONTACTS)) { - Log.i(TAG, "No permission to read contacts. Not loading the Dictionary."); - } - - final ArrayList validNames = mContactsManager.getValidNames(uri); - for (final String name : validNames) { - addNameLocked(name); - } - if (uri.equals(Contacts.CONTENT_URI)) { - // Since we were able to add content successfully, update the local - // state of the manager. - mContactsManager.updateLocalState(validNames); - } - } - - /** - * Adds the words in a name (e.g., firstname/lastname) to the binary dictionary along with their - * bigrams depending on locale. - */ - private void addNameLocked(final String name) { - int len = StringUtils.codePointCount(name); - NgramContext ngramContext = NgramContext.getEmptyPrevWordsContext( - BinaryDictionary.MAX_PREV_WORD_COUNT_FOR_N_GRAM); - // TODO: Better tokenization for non-Latin writing systems - for (int i = 0; i < len; i++) { - if (Character.isLetter(name.codePointAt(i))) { - int end = ContactsDictionaryUtils.getWordEndPosition(name, len, i); - String word = name.substring(i, end); - if (DEBUG_DUMP) { - Log.d(TAG, "addName word = " + word); - } - i = end - 1; - // Don't add single letter words, possibly confuses - // capitalization of i. - final int wordLen = StringUtils.codePointCount(word); - if (wordLen <= MAX_WORD_LENGTH && wordLen > 1) { - if (DEBUG) { - Log.d(TAG, "addName " + name + ", " + word + ", " + ngramContext); - } - runGCIfRequiredLocked(true /* mindsBlockByGC */); - addUnigramLocked(word, - ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS, - null, 0, - false /* isNotAWord */, - false /* isPossiblyOffensive */, - BinaryDictionary.NOT_A_VALID_TIMESTAMP); - if (ngramContext.isValid() && mUseFirstLastBigrams) { - runGCIfRequiredLocked(true /* mindsBlockByGC */); - addNgramEntryLocked(ngramContext, - word, - ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS_BIGRAM, - BinaryDictionary.NOT_A_VALID_TIMESTAMP); - } - ngramContext = ngramContext.getNextNgramContext( - new NgramContext.WordInfo(word)); - } - } - } - } - - @Override - public void onContactsChange() { - setNeedsToRecreate(); - } -} diff --git a/java/src/org/futo/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/org/futo/inputmethod/latin/DictionaryFacilitatorImpl.java index 341dacaa8..0f7a64908 100644 --- a/java/src/org/futo/inputmethod/latin/DictionaryFacilitatorImpl.java +++ b/java/src/org/futo/inputmethod/latin/DictionaryFacilitatorImpl.java @@ -80,7 +80,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { static { DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER_HISTORY, UserHistoryDictionary.class); DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER, UserBinaryDictionary.class); - DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTACTS, ContactsBinaryDictionary.class); } private static final String DICT_FACTORY_METHOD_NAME = "getDictionary"; diff --git a/java/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiver.java b/java/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiver.java deleted file mode 100644 index 098aecb64..000000000 --- a/java/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiver.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 org.futo.inputmethod.latin.accounts; - -import android.accounts.AccountManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.text.TextUtils; -import android.util.Log; - -import org.futo.inputmethod.annotations.UsedForTesting; -import org.futo.inputmethod.latin.settings.LocalSettingsConstants; - -/** - * {@link BroadcastReceiver} for {@link AccountManager#LOGIN_ACCOUNTS_CHANGED_ACTION}. - */ -public class AccountsChangedReceiver extends BroadcastReceiver { - static final String TAG = "AccountsChangedReceiver"; - - @Override - public void onReceive(Context context, Intent intent) { - if (!AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(intent.getAction())) { - Log.w(TAG, "Received unknown broadcast: " + intent); - return; - } - - // Ideally the account preference could live in a different preferences file - // that wasn't being backed up and restored, however the preference fragments - // currently only deal with the default shared preferences which is why - // separating this out into a different file is not trivial currently. - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - final String currentAccount = prefs.getString( - LocalSettingsConstants.PREF_ACCOUNT_NAME, null); - removeUnknownAccountFromPreference(prefs, getAccountsForLogin(context), currentAccount); - } - - /** - * Helper method to help test this receiver. - */ - @UsedForTesting - protected String[] getAccountsForLogin(Context context) { - return LoginAccountUtils.getAccountsForLogin(context); - } - - /** - * Removes the currentAccount from preferences if it's not found - * in the list of current accounts. - */ - private static void removeUnknownAccountFromPreference(final SharedPreferences prefs, - final String[] accounts, final String currentAccount) { - if (currentAccount == null) { - return; - } - for (final String account : accounts) { - if (TextUtils.equals(currentAccount, account)) { - return; - } - } - Log.i(TAG, "The current account was removed from the system: " + currentAccount); - prefs.edit() - .remove(LocalSettingsConstants.PREF_ACCOUNT_NAME) - .apply(); - } -} diff --git a/java/src/org/futo/inputmethod/latin/accounts/AuthUtils.java b/java/src/org/futo/inputmethod/latin/accounts/AuthUtils.java deleted file mode 100644 index 87924f72b..000000000 --- a/java/src/org/futo/inputmethod/latin/accounts/AuthUtils.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 org.futo.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 getAuthToken(final Account account, - final String authTokenType, final Bundle options, final boolean notifyAuthFailure, - final AccountManagerCallback 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/org/futo/inputmethod/latin/accounts/LoginAccountUtils.java b/java/src/org/futo/inputmethod/latin/accounts/LoginAccountUtils.java deleted file mode 100644 index 2a48513f7..000000000 --- a/java/src/org/futo/inputmethod/latin/accounts/LoginAccountUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 org.futo.inputmethod.latin.accounts; - -import android.content.Context; - -import javax.annotation.Nonnull; - -/** - * Utility class for retrieving accounts that may be used for login. - */ -public class LoginAccountUtils { - /** - * This defines the type of account this class deals with. - * This account type is used when listing the accounts available on the device for login. - */ - public static final String ACCOUNT_TYPE = ""; - - private LoginAccountUtils() { - // This utility class is not publicly instantiable. - } - - /** - * Get the accounts available for login. - * - * @return an array of accounts. Empty (never null) if no accounts are available for login. - */ - @Nonnull - @SuppressWarnings("unused") - public static String[] getAccountsForLogin(final Context context) { - return new String[0]; - } -} diff --git a/java/src/org/futo/inputmethod/latin/personalization/AccountUtils.java b/java/src/org/futo/inputmethod/latin/personalization/AccountUtils.java deleted file mode 100644 index 9723dddd9..000000000 --- a/java/src/org/futo/inputmethod/latin/personalization/AccountUtils.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2013 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 org.futo.inputmethod.latin.personalization; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; -import android.util.Patterns; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class AccountUtils { - private AccountUtils() { - // This utility class is not publicly instantiable. - } - - private static Account[] getAccounts(final Context context) { - return AccountManager.get(context).getAccounts(); - } - - public static List getDeviceAccountsEmailAddresses(final Context context) { - final ArrayList retval = new ArrayList<>(); - for (final Account account : getAccounts(context)) { - final String name = account.name; - if (Patterns.EMAIL_ADDRESS.matcher(name).matches()) { - retval.add(name); - retval.add(name.split("@")[0]); - } - } - return retval; - } - - /** - * Get all device accounts having specified domain name. - * @param context application context - * @param domain domain name used for filtering - * @return List of account names that contain the specified domain name - */ - public static List getDeviceAccountsWithDomain( - final Context context, final String domain) { - final ArrayList retval = new ArrayList<>(); - final String atDomain = "@" + domain.toLowerCase(Locale.ROOT); - for (final Account account : getAccounts(context)) { - if (account.name.toLowerCase(Locale.ROOT).endsWith(atDomain)) { - retval.add(account.name); - } - } - return retval; - } -} diff --git a/src/playstore/AndroidManifest.xml b/src/playstore/AndroidManifest.xml new file mode 100644 index 000000000..604670490 --- /dev/null +++ b/src/playstore/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/src/playstore/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt b/src/playstore/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt new file mode 100644 index 000000000..5b8b7ec62 --- /dev/null +++ b/src/playstore/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt @@ -0,0 +1,7 @@ +package org.futo.inputmethod.latin + +import android.app.Application + +class CrashLoggingApplication : Application() { + +} \ No newline at end of file diff --git a/src/stable/AndroidManifest.xml b/src/stable/AndroidManifest.xml new file mode 100644 index 000000000..ec0476c54 --- /dev/null +++ b/src/stable/AndroidManifest.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/src/org/futo/inputmethod/latin/CrashLoggingApplication.kt b/src/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt similarity index 100% rename from java/src/org/futo/inputmethod/latin/CrashLoggingApplication.kt rename to src/stable/java/org/futo/inputmethod/latin/CrashLoggingApplication.kt diff --git a/tests/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiverTests.java b/tests/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiverTests.java deleted file mode 100644 index 449953e6f..000000000 --- a/tests/src/org/futo/inputmethod/latin/accounts/AccountsChangedReceiverTests.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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 org.futo.inputmethod.latin.accounts; - -import static org.junit.Assert.assertEquals; - -import android.accounts.AccountManager; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.futo.inputmethod.latin.settings.LocalSettingsConstants; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests for {@link AccountsChangedReceiver}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class AccountsChangedReceiverTests { - private static final String ACCOUNT_1 = "account1@example.com"; - private static final String ACCOUNT_2 = "account2@example.com"; - - private SharedPreferences mPrefs; - private String mLastKnownAccount = null; - - private Context getContext() { - return InstrumentationRegistry.getTargetContext(); - } - - @Before - public void setUp() throws Exception { - mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - // Keep track of the current account so that we restore it when the test finishes. - mLastKnownAccount = mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null); - } - - @After - public void tearDown() throws Exception { - // Restore the account that was present before running the test. - updateAccountName(mLastKnownAccount); - } - - @Test - public void testUnknownIntent() { - updateAccountName(ACCOUNT_1); - AccountsChangedReceiver reciever = new AccountsChangedReceiver(); - reciever.onReceive(getContext(), new Intent("some-random-action")); - // Account should *not* be removed from preferences. - assertAccountName(ACCOUNT_1); - } - - @Test - public void testAccountRemoved() { - updateAccountName(ACCOUNT_1); - AccountsChangedReceiver reciever = new AccountsChangedReceiver() { - @Override - protected String[] getAccountsForLogin(Context context) { - return new String[] {ACCOUNT_2}; - } - }; - reciever.onReceive(getContext(), new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION)); - // Account should be removed from preferences. - assertAccountName(null); - } - - @Test - public void testAccountRemoved_noAccounts() { - updateAccountName(ACCOUNT_2); - AccountsChangedReceiver reciever = new AccountsChangedReceiver() { - @Override - protected String[] getAccountsForLogin(Context context) { - return new String[0]; - } - }; - reciever.onReceive(getContext(), new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION)); - // Account should be removed from preferences. - assertAccountName(null); - } - - @Test - public void testAccountNotRemoved() { - updateAccountName(ACCOUNT_2); - AccountsChangedReceiver reciever = new AccountsChangedReceiver() { - @Override - protected String[] getAccountsForLogin(Context context) { - return new String[] {ACCOUNT_1, ACCOUNT_2}; - } - }; - reciever.onReceive(getContext(), new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION)); - // Account should *not* be removed from preferences. - assertAccountName(ACCOUNT_2); - } - - private void updateAccountName(String accountName) { - if (accountName == null) { - mPrefs.edit().remove(LocalSettingsConstants.PREF_ACCOUNT_NAME).apply(); - } else { - mPrefs.edit().putString(LocalSettingsConstants.PREF_ACCOUNT_NAME, accountName).apply(); - } - } - - private void assertAccountName(String expectedAccountName) { - assertEquals(expectedAccountName, - mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null)); - } -}