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
This commit is contained in:
@@ -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());
|
||||
|
@@ -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;
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user