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

Commit 6f9bf1da authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Only sync adapters with access can see an account - settings

This change ensures that when the user tries to toggle a sync for a
sync adapter that doesn't have access to an account we show UI for
the user to approve the sync.

bug:28163381

Change-Id: I59802df6614572cf0eaf4b72a177beb111b87b34
parent 124251d5
Loading
Loading
Loading
Loading
+89 −10
Original line number Diff line number Diff line
@@ -28,9 +28,12 @@ import android.app.Dialog;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
import android.os.Binder;
@@ -58,7 +61,6 @@ import com.android.settingslib.RestrictedLockUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@@ -73,6 +75,7 @@ public class AccountSyncSettings extends AccountPreferenceBase {
    private static final int REALLY_REMOVE_DIALOG = 100;
    private static final int FAILED_REMOVAL_DIALOG = 101;
    private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;

    private TextView mUserId;
    private TextView mProviderId;
    private ImageView mProviderIcon;
@@ -234,13 +237,15 @@ public class AccountSyncSettings extends AccountPreferenceBase {
        mAuthenticatorHelper.stopListeningToAccountUpdates();
    }

    private void addSyncStateSwitch(Account account, String authority) {
    private void addSyncStateSwitch(Account account, String authority,
            String packageName, int uid) {
        SyncStateSwitchPreference item = (SyncStateSwitchPreference) getCachedPreference(authority);
        if (item == null) {
            item = new SyncStateSwitchPreference(getPrefContext(), account, authority);
            item = new SyncStateSwitchPreference(getPrefContext(), account, authority,
                    packageName, uid);
            getPreferenceScreen().addPreference(item);
        } else {
            item.setup(account, authority);
            item.setup(account, authority, packageName, uid);
        }
        item.setPersistent(false);
        final ProviderInfo providerInfo = getPackageManager().resolveContentProviderAsUser(
@@ -322,21 +327,57 @@ public class AccountSyncSettings extends AccountPreferenceBase {
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            final int uid = requestCode;
            final int count = getPreferenceScreen().getPreferenceCount();
            for (int i = 0; i < count; i++) {
                Preference preference = getPreferenceScreen().getPreference(i);
                if (preference instanceof SyncStateSwitchPreference) {
                    SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
                    if (syncPref.getUid() == uid) {
                        onPreferenceTreeClick(syncPref);
                        return;
                    }
                }
            }
        }
    }

    @Override
    public boolean onPreferenceTreeClick(Preference preference) {
        if (getActivity() == null) {
            return false;
        }
        if (preference instanceof SyncStateSwitchPreference) {
            SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
            String authority = syncPref.getAuthority();
            Account account = syncPref.getAccount();
            final int userId = mUserHandle.getIdentifier();
            String packageName = syncPref.getPackageName();

            boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
                    authority, userId);
            if (syncPref.isOneTimeSyncMode()) {
                // If the sync adapter doesn't have access to the account we either
                // request access by starting an activity if possible or kick off the
                // sync which will end up posting an access request notification.
                if (requestAccountAccessIfNeeded(packageName)) {
                    return true;
                }
                requestOrCancelSync(account, authority, true);
            } else {
                boolean syncOn = syncPref.isChecked();
                boolean oldSyncState = syncAutomatically;
                if (syncOn != oldSyncState) {
                    // Toggling this switch triggers sync but we may need a user approval.
                    // If the sync adapter doesn't have access to the account we either
                    // request access by starting an activity if possible or kick off the
                    // sync which will end up posting an access request notification.
                    if (syncOn && requestAccountAccessIfNeeded(packageName)) {
                        return true;
                    }
                    // if we're enabling sync, this will request a sync as well
                    ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
                    // if the master sync switch is off, the request above will
@@ -353,6 +394,36 @@ public class AccountSyncSettings extends AccountPreferenceBase {
        }
    }

    private boolean requestAccountAccessIfNeeded(String packageName) {
        if (packageName == null) {
            return false;
        }

        final int uid;
        try {
            uid = getContext().getPackageManager().getPackageUidAsUser(
                    packageName, mUserHandle.getIdentifier());
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Invalid sync ", e);
            return false;
        }

        AccountManager accountManager = getContext().getSystemService(AccountManager.class);
        if (!accountManager.hasAccountAccess(mAccount, packageName, mUserHandle)) {
            IntentSender intent = accountManager.createRequestAccountAccessIntentSenderAsUser(
                    mAccount, packageName, mUserHandle);
            if (intent != null) {
                try {
                    startIntentSenderForResult(intent, uid, null, 0, 0, 0, null);
                    return true;
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Error requesting account access", e);
                }
            }
        }
        return false;
    }

    private void startSyncForEnabledProviders() {
        requestOrCancelSyncForEnabledProviders(true /* start them */);
        final Activity activity = getActivity();
@@ -520,7 +591,7 @@ public class AccountSyncSettings extends AccountPreferenceBase {

        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
                mUserHandle.getIdentifier());
        ArrayList<String> authorities = new ArrayList<String>();
        ArrayList<SyncAdapterType> authorities = new ArrayList<>();
        for (int i = 0, n = syncAdapters.length; i < n; i++) {
            final SyncAdapterType sa = syncAdapters[i];
            // Only keep track of sync adapters for this account
@@ -530,7 +601,7 @@ public class AccountSyncSettings extends AccountPreferenceBase {
                    Log.d(TAG, "updateAccountSwitches: added authority " + sa.authority
                            + " to accountType " + sa.accountType);
                }
                authorities.add(sa.authority);
                authorities.add(sa);
            } else {
                // keep track of invisible sync adapters, so sync now forces
                // them to sync as well.
@@ -543,15 +614,23 @@ public class AccountSyncSettings extends AccountPreferenceBase {
        }
        cacheRemoveAllPrefs(getPreferenceScreen());
        for (int j = 0, m = authorities.size(); j < m; j++) {
            final String authority = authorities.get(j);
            final SyncAdapterType syncAdapter = authorities.get(j);
            // We could check services here....
            int syncState = ContentResolver.getIsSyncableAsUser(mAccount, authority,
            int syncState = ContentResolver.getIsSyncableAsUser(mAccount, syncAdapter.authority,
                    mUserHandle.getIdentifier());
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.d(TAG, "  found authority " + authority + " " + syncState);
                Log.d(TAG, "  found authority " + syncAdapter.authority + " " + syncState);
            }
            if (syncState > 0) {
                addSyncStateSwitch(mAccount, authority);
                final int uid;
                try {
                    uid = getContext().getPackageManager().getPackageUidAsUser(
                            syncAdapter.getPackageName(), mUserHandle.getIdentifier());
                    addSyncStateSwitch(mAccount, syncAdapter.authority,
                            syncAdapter.getPackageName(), uid);
                } catch (PackageManager.NameNotFoundException e) {
                    Log.e(TAG, "No uid for package" + syncAdapter.getPackageName(), e);
                }
            }
        }
        removeCachedPrefs(getPreferenceScreen());
+18 −3
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ public class SyncStateSwitchPreference extends SwitchPreference {
    private boolean mFailed = false;
    private Account mAccount;
    private String mAuthority;
    private String mPackageName;
    private int mUid;

    /**
     * A mode for this preference where clicking does a one-time sync instead of
@@ -47,16 +49,21 @@ public class SyncStateSwitchPreference extends SwitchPreference {
        super(context, attrs, 0, R.style.SyncSwitchPreference);
        mAccount = null;
        mAuthority = null;
        mPackageName = null;
        mUid = 0;
    }

    public SyncStateSwitchPreference(Context context, Account account, String authority) {
    public SyncStateSwitchPreference(Context context, Account account, String authority,
            String packageName, int uid) {
        super(context, null, 0, R.style.SyncSwitchPreference);
        setup(account, authority);
        setup(account, authority, packageName, uid);
    }

    public void setup(Account account, String authority) {
    public void setup(Account account, String authority, String packageName, int uid) {
        mAccount = account;
        mAuthority = authority;
        mPackageName = packageName;
        mUid = uid;
        notifyChanged();
    }

@@ -152,4 +159,12 @@ public class SyncStateSwitchPreference extends SwitchPreference {
    public String getAuthority() {
        return mAuthority;
    }

    public String getPackageName() {
        return mPackageName;
    };

    public int getUid() {
        return mUid;
    };
}