Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b17a3bc4 authored by Sandeep Siddhartha's avatar Sandeep Siddhartha
Browse files

Move sync policy related code out of account settings

Bug: 17981687
Bug: 17464069
Change-Id: I0ae3400564fd346cc84af74dfef65f01cc1ce6a8
parent 296b1150
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
/*
 * 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.support.annotation.NonNull;

import javax.annotation.Nullable;

/**
 * Handles changes to account used to sign in to the keyboard.
 * e.g. account switching/sign-in/sign-out from the keyboard
 * user toggling the sync preference.
 */
public class AccountStateChangedListener {

    /**
     * Called when the current account being used in keyboard is signed out.
     *
     * @param oldAccount the account that was signed out of.
     */
    public static void onAccountSignedOut(@NonNull String oldAccount) {
    }

    /**
     * Called when the user signs-in to the keyboard.
     * This may be called when the user switches accounts to sign in with a different account.
     *
     * @param oldAccount the previous account that was being used for sign-in.
     *        May be null for a fresh sign-in.
     * @param newAccount the account being used for sign-in.
     */
    public static void onAccountSignedIn(@Nullable String oldAccount, @NonNull String newAccount) {
    }

    /**
     * Called when the user toggles the sync preference.
     *
     * @param account the account being used for sync.
     * @param syncEnabled indicates whether sync has been enabled or not.
     */
    public static void onSyncPreferenceChanged(@Nullable String account, boolean syncEnabled) {
    }

    /**
     * Forces an immediate sync to happen.
     * This should only be used for debugging purposes.
     *
     * @param account the account to use for sync.
     */
    public static void forceSync(@Nullable String account) {
    }
}
+10 −45
Original line number Diff line number Diff line
@@ -19,9 +19,7 @@ package com.android.inputmethod.latin.settings;
import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ACCOUNT_NAME;
import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ENABLE_CLOUD_SYNC;

import android.accounts.Account;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
@@ -37,6 +35,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.accounts.LoginAccountUtils;
import com.android.inputmethod.latin.accounts.AccountStateChangedListener;
import com.android.inputmethod.latin.define.ProductionFlags;

import javax.annotation.Nullable;
@@ -52,7 +51,6 @@ import javax.annotation.Nullable;
public final class AccountsSettingsFragment extends SubScreenFragment {
    private static final String PREF_SYNC_NOW = "pref_beanstalk";

    @UsedForTesting static final String AUTHORITY = "com.android.inputmethod.latin.provider";
    static final String PREF_ACCCOUNT_SWITCHER = "account_switcher";

    private final DialogInterface.OnClickListener mAccountChangedListener =
@@ -111,7 +109,8 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
                    prefs.getString(PREF_ACCOUNT_NAME, null));
        } else if (TextUtils.equals(key, PREF_ENABLE_CLOUD_SYNC)) {
            final boolean syncEnabled = prefs.getBoolean(PREF_ENABLE_CLOUD_SYNC, false);
            updateSyncPolicy(syncEnabled, getSignedInAccountName());
            AccountStateChangedListener.onSyncPreferenceChanged(
                    getSignedInAccountName(), syncEnabled);
        }
    }

@@ -177,36 +176,6 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
        syncPreference.setSummary(R.string.cloud_sync_summary_disabled_signed_out);
    }

    /**
     * Given a non-null accountToUse, this method looks at the enabled value to either
     * set or unset the syncable property of the sync authority.
     * If the account is null, this method is a no-op currently, but we may want
     * to perform some cleanup in the future.
     *
     * @param enabled indicates whether the sync preference is enabled or not.
     * @param accountToUse indicaes the account to be used for sync, or null if the user
     *        is not logged in.
     */
    @UsedForTesting
    void updateSyncPolicy(boolean enabled, @Nullable String accountToUse) {
        if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
            return;
        }

        if (accountToUse != null) {
            final int syncable = enabled ? 1 : 0;
            ContentResolver.setIsSyncable(
                    new Account(accountToUse, LoginAccountUtils.ACCOUNT_TYPE),
                    AUTHORITY, syncable);
            // TODO: Also add a periodic sync here.
            // See ContentResolver.addPeriodicSync
        } else {
            // Without an account, we cannot really set the sync to off.
            // Hopefully the account sign-out listener would have taken care of that for us.
            // But cases such as clear data are still not handled cleanly.
        }
    }

    @Nullable
    String getSignedInAccountName() {
        return getSharedPreferences().getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
@@ -261,22 +230,20 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
    class AccountChangedListener implements DialogInterface.OnClickListener {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            final String oldAccount = getSignedInAccountName();
            switch (which) {
                case DialogInterface.BUTTON_POSITIVE: // Signed in
                    final ListView lv = ((AlertDialog)dialog).getListView();
                    final Object selectedItem = lv.getItemAtPosition(lv.getCheckedItemPosition());
                    final String newAccount =
                            (String) lv.getItemAtPosition(lv.getCheckedItemPosition());
                    getSharedPreferences()
                            .edit()
                            .putString(PREF_ACCOUNT_NAME, (String) selectedItem)
                            .putString(PREF_ACCOUNT_NAME, newAccount)
                            .apply();
                    // Attempt starting sync for the new account if sync was
                    // previously enabled.
                    // If not, stop it.
                    updateSyncPolicy(isSyncEnabled(), getSignedInAccountName());
                    AccountStateChangedListener.onAccountSignedIn(oldAccount, newAccount);
                    break;
                case DialogInterface.BUTTON_NEUTRAL: // Signed out
                    // Stop sync for the account that's being signed out of.
                    updateSyncPolicy(false, getSignedInAccountName());
                    AccountStateChangedListener.onAccountSignedOut(oldAccount);
                    getSharedPreferences()
                            .edit()
                            .remove(PREF_ACCOUNT_NAME)
@@ -292,9 +259,7 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
    class SyncNowListener implements Preference.OnPreferenceClickListener {
        @Override
        public boolean onPreferenceClick(final Preference preference) {
            ContentResolver.requestSync(
                    new Account(getSignedInAccountName(), LoginAccountUtils.ACCOUNT_TYPE),
                    AUTHORITY, Bundle.EMPTY);
            AccountStateChangedListener.forceSync(getSignedInAccountName());
            return true;
        }
    }
+0 −70
Original line number Diff line number Diff line
@@ -16,21 +16,14 @@

package com.android.inputmethod.latin.settings;

import static com.android.inputmethod.latin.settings.AccountsSettingsFragment.AUTHORITY;

import android.accounts.Account;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.widget.ListView;

import com.android.inputmethod.latin.accounts.LoginAccountUtils;
import com.android.inputmethod.latin.define.ProductionFlags;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -39,9 +32,6 @@ public class AccountsSettingsFragmentTests
        extends ActivityInstrumentationTestCase2<TestFragmentActivity> {
    private static final String FRAG_NAME = AccountsSettingsFragment.class.getName();
    private static final long TEST_TIMEOUT_MILLIS = 5000;
    private static final String TEST_ACCOUNT_NAME = "AccountsSettingsFragmentTests";
    private static final Account TEST_ACCOUNT =
            new Account(TEST_ACCOUNT_NAME, LoginAccountUtils.ACCOUNT_TYPE);

    private AlertDialog mDialog;

@@ -57,13 +47,6 @@ public class AccountsSettingsFragmentTests
        setActivityIntent(intent);
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
        // reset the syncable state to unknown
        ContentResolver.setIsSyncable(TEST_ACCOUNT, AUTHORITY, -1);
    }

    public void testEmptyAccounts() {
        final AccountsSettingsFragment fragment =
                (AccountsSettingsFragment) getActivity().mFragment;
@@ -146,57 +129,4 @@ public class AccountsSettingsFragmentTests
        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_NEGATIVE).getVisibility());
        assertEquals(View.VISIBLE, mDialog.getButton(Dialog.BUTTON_POSITIVE).getVisibility());
    }

    public void testUpdateSyncPolicy_enable() {
        // This test is a no-op when ENABLE_PERSONAL_DICTIONARY_SYNC is not enabled
        if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
            return;
        }
        // Should be unknown by default.
        assertTrue(ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY) < 0);

        final AccountsSettingsFragment fragment =
                (AccountsSettingsFragment) getActivity().mFragment;
        fragment.updateSyncPolicy(true, TEST_ACCOUNT_NAME);

        // Should be syncable now.
        assertEquals(1, ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY));
    }

    public void testUpdateSyncPolicy_disable() {
        // This test is a no-op when ENABLE_PERSONAL_DICTIONARY_SYNC is not enabled
        if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
            return;
        }
        // Should be unknown by default.
        assertTrue(ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY) < 0);

        final AccountsSettingsFragment fragment =
                (AccountsSettingsFragment) getActivity().mFragment;
        fragment.updateSyncPolicy(false, TEST_ACCOUNT_NAME);

        // Should not be syncable now.
        assertEquals(0, ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY));
    }

    public void testUpdateSyncPolicy_enableDisable() {
        // This test is a no-op when ENABLE_PERSONAL_DICTIONARY_SYNC is not enabled
        if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
            return;
        }
        // Should be unknown by default.
        assertTrue(ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY) < 0);

        final AccountsSettingsFragment fragment =
                (AccountsSettingsFragment) getActivity().mFragment;
        fragment.updateSyncPolicy(true, TEST_ACCOUNT_NAME);

        // Should be syncable now.
        assertEquals(1, ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY));

        fragment.updateSyncPolicy(false, TEST_ACCOUNT_NAME);

        // Should not be syncable now.
        assertEquals(0, ContentResolver.getIsSyncable(TEST_ACCOUNT, AUTHORITY));
    }
}