Remove some unneeded code and permissions

This commit is contained in:
Aleksandras Kostarevas 2024-04-11 21:47:24 -05:00
parent 76231dc7a7
commit ecafe8f86a
15 changed files with 33 additions and 674 deletions

View File

@ -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'

View File

@ -16,27 +16,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_SYNC_STATS"/>
<!--<uses-permission android:name="android.permission.READ_PROFILE"/>--> <!-- ? -->
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- A signature-protected permission to ask AOSP Keyboard to close the software keyboard.
To use this, add the following line into calling application's AndroidManifest.xml
@ -77,12 +66,6 @@
android:resource="@xml/method"/>
</service>
<service
android:name="org.futo.inputmethod.updates.UpdateCheckingService"
android:label="@string/update_checking_service"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
<service android:name=".spellcheck.AndroidSpellCheckerService"
android:label="@string/spell_checker_service_name"
android:permission="android.permission.BIND_TEXT_SERVICE"
@ -177,16 +160,6 @@
</intent-filter>
</receiver>
<!-- Broadcast receiver for AccountManager#LOGIN_ACCOUNTS_CHANGED_ACTION. -->
<receiver android:name=".accounts.AccountsChangedReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
</intent-filter>
</receiver>
<receiver android:name="org.futo.inputmethod.updates.InstallReceiver" />
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="specialUse"

View File

@ -1,36 +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.compat;
import android.net.ConnectivityManager;
import java.lang.reflect.Method;
public final class ConnectivityManagerCompatUtils {
// ConnectivityManager#isActiveNetworkMetered() has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Method METHOD_isActiveNetworkMetered = CompatUtils.getMethod(
ConnectivityManager.class, "isActiveNetworkMetered");
public static boolean isActiveNetworkMetered(final ConnectivityManager manager) {
return (Boolean)CompatUtils.invoke(manager,
// If the API telling whether the network is metered or not is not available,
// then the closest thing is "if it's a mobile connection".
manager.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_MOBILE,
METHOD_isActiveNetworkMetered);
}
}

View File

@ -1,36 +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.dictionarypack;
import android.app.DownloadManager;
/**
* Struct class to encapsulate the result of a completed download.
*/
public class CompletedDownloadInfo {
final String mUri;
final long mDownloadId;
final int mStatus;
public CompletedDownloadInfo(final String uri, final long downloadId, final int status) {
mUri = uri;
mDownloadId = downloadId;
mStatus = status;
}
public boolean wasSuccessful() {
return DownloadManager.STATUS_SUCCESSFUL == mStatus;
}
}

View File

@ -1,179 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.futo.inputmethod.latin;
import android.Manifest;
import android.content.Context;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.util.Log;
import org.futo.inputmethod.annotations.ExternallyReferenced;
import org.futo.inputmethod.latin.ContactsManager.ContactsChangedListener;
import org.futo.inputmethod.latin.common.StringUtils;
import org.futo.inputmethod.latin.permissions.PermissionsUtil;
import org.futo.inputmethod.latin.personalization.AccountUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
implements ContactsChangedListener {
private static final String TAG = ContactsBinaryDictionary.class.getSimpleName();
private static final String NAME = "contacts";
private static final boolean DEBUG = false;
private static final boolean DEBUG_DUMP = false;
/**
* Whether to use "firstname lastname" in bigram predictions.
*/
private final boolean mUseFirstLastBigrams;
private final ContactsManager mContactsManager;
protected ContactsBinaryDictionary(final Context context, final Locale locale,
final File dictFile, final String name) {
super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_CONTACTS,
dictFile);
mUseFirstLastBigrams = ContactsDictionaryUtils.useFirstLastBigramsForLocale(locale);
mContactsManager = new ContactsManager(context);
mContactsManager.registerForUpdates(this /* listener */);
reloadDictionaryIfRequired();
}
// Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@ExternallyReferenced
public static ContactsBinaryDictionary getDictionary(final Context context, final Locale locale,
final File dictFile, final String dictNamePrefix, @Nullable final String account) {
return new ContactsBinaryDictionary(context, locale, dictFile, dictNamePrefix + NAME);
}
@Override
public synchronized void close() {
mContactsManager.close();
super.close();
}
/**
* Typically called whenever the dictionary is created for the first time or
* recreated when we think that there are updates to the dictionary.
* This is called asynchronously.
*/
@Override
public void loadInitialContentsLocked() {
loadDeviceAccountsEmailAddressesLocked();
loadDictionaryForUriLocked(ContactsContract.Profile.CONTENT_URI);
// TODO: Switch this URL to the newer ContactsContract too
loadDictionaryForUriLocked(Contacts.CONTENT_URI);
}
/**
* Loads device accounts to the dictionary.
*/
private void loadDeviceAccountsEmailAddressesLocked() {
final List<String> 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<String> 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();
}
}

View File

@ -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";

View File

@ -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();
}
}

View File

@ -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<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);
}
}

View File

@ -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];
}
}

View File

@ -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<String> getDeviceAccountsEmailAddresses(final Context context) {
final ArrayList<String> 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<String> getDeviceAccountsWithDomain(
final Context context, final String domain) {
final ArrayList<String> 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;
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
</manifest>

View File

@ -0,0 +1,7 @@
package org.futo.inputmethod.latin
import android.app.Application
class CrashLoggingApplication : Application() {
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<service
android:name="org.futo.inputmethod.updates.UpdateCheckingService"
android:label="@string/update_checking_service"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
<receiver android:name="org.futo.inputmethod.updates.InstallReceiver" />
</application>
</manifest>

View File

@ -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));
}
}