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.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentSender;
|
||||||
import android.content.SyncAdapterType;
|
import android.content.SyncAdapterType;
|
||||||
import android.content.SyncInfo;
|
import android.content.SyncInfo;
|
||||||
import android.content.SyncStatusInfo;
|
import android.content.SyncStatusInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ProviderInfo;
|
import android.content.pm.ProviderInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -58,7 +61,6 @@ import com.android.settingslib.RestrictedLockUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
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 REALLY_REMOVE_DIALOG = 100;
|
||||||
private static final int FAILED_REMOVAL_DIALOG = 101;
|
private static final int FAILED_REMOVAL_DIALOG = 101;
|
||||||
private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;
|
private static final int CANT_DO_ONETIME_SYNC_DIALOG = 102;
|
||||||
|
|
||||||
private TextView mUserId;
|
private TextView mUserId;
|
||||||
private TextView mProviderId;
|
private TextView mProviderId;
|
||||||
private ImageView mProviderIcon;
|
private ImageView mProviderIcon;
|
||||||
@@ -234,13 +237,15 @@ public class AccountSyncSettings extends AccountPreferenceBase {
|
|||||||
mAuthenticatorHelper.stopListeningToAccountUpdates();
|
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);
|
SyncStateSwitchPreference item = (SyncStateSwitchPreference) getCachedPreference(authority);
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
item = new SyncStateSwitchPreference(getPrefContext(), account, authority);
|
item = new SyncStateSwitchPreference(getPrefContext(), account, authority,
|
||||||
|
packageName, uid);
|
||||||
getPreferenceScreen().addPreference(item);
|
getPreferenceScreen().addPreference(item);
|
||||||
} else {
|
} else {
|
||||||
item.setup(account, authority);
|
item.setup(account, authority, packageName, uid);
|
||||||
}
|
}
|
||||||
item.setPersistent(false);
|
item.setPersistent(false);
|
||||||
final ProviderInfo providerInfo = getPackageManager().resolveContentProviderAsUser(
|
final ProviderInfo providerInfo = getPackageManager().resolveContentProviderAsUser(
|
||||||
@@ -322,21 +327,57 @@ public class AccountSyncSettings extends AccountPreferenceBase {
|
|||||||
return super.onOptionsItemSelected(item);
|
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
|
@Override
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
|
if (getActivity() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (preference instanceof SyncStateSwitchPreference) {
|
if (preference instanceof SyncStateSwitchPreference) {
|
||||||
SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
|
SyncStateSwitchPreference syncPref = (SyncStateSwitchPreference) preference;
|
||||||
String authority = syncPref.getAuthority();
|
String authority = syncPref.getAuthority();
|
||||||
Account account = syncPref.getAccount();
|
Account account = syncPref.getAccount();
|
||||||
final int userId = mUserHandle.getIdentifier();
|
final int userId = mUserHandle.getIdentifier();
|
||||||
|
String packageName = syncPref.getPackageName();
|
||||||
|
|
||||||
boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
|
boolean syncAutomatically = ContentResolver.getSyncAutomaticallyAsUser(account,
|
||||||
authority, userId);
|
authority, userId);
|
||||||
if (syncPref.isOneTimeSyncMode()) {
|
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);
|
requestOrCancelSync(account, authority, true);
|
||||||
} else {
|
} else {
|
||||||
boolean syncOn = syncPref.isChecked();
|
boolean syncOn = syncPref.isChecked();
|
||||||
boolean oldSyncState = syncAutomatically;
|
boolean oldSyncState = syncAutomatically;
|
||||||
if (syncOn != oldSyncState) {
|
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
|
// if we're enabling sync, this will request a sync as well
|
||||||
ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
|
ContentResolver.setSyncAutomaticallyAsUser(account, authority, syncOn, userId);
|
||||||
// if the master sync switch is off, the request above will
|
// 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() {
|
private void startSyncForEnabledProviders() {
|
||||||
requestOrCancelSyncForEnabledProviders(true /* start them */);
|
requestOrCancelSyncForEnabledProviders(true /* start them */);
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
@@ -520,7 +591,7 @@ public class AccountSyncSettings extends AccountPreferenceBase {
|
|||||||
|
|
||||||
SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
|
SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
|
||||||
mUserHandle.getIdentifier());
|
mUserHandle.getIdentifier());
|
||||||
ArrayList<String> authorities = new ArrayList<String>();
|
ArrayList<SyncAdapterType> authorities = new ArrayList<>();
|
||||||
for (int i = 0, n = syncAdapters.length; i < n; i++) {
|
for (int i = 0, n = syncAdapters.length; i < n; i++) {
|
||||||
final SyncAdapterType sa = syncAdapters[i];
|
final SyncAdapterType sa = syncAdapters[i];
|
||||||
// Only keep track of sync adapters for this account
|
// 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
|
Log.d(TAG, "updateAccountSwitches: added authority " + sa.authority
|
||||||
+ " to accountType " + sa.accountType);
|
+ " to accountType " + sa.accountType);
|
||||||
}
|
}
|
||||||
authorities.add(sa.authority);
|
authorities.add(sa);
|
||||||
} else {
|
} else {
|
||||||
// keep track of invisible sync adapters, so sync now forces
|
// keep track of invisible sync adapters, so sync now forces
|
||||||
// them to sync as well.
|
// them to sync as well.
|
||||||
@@ -543,15 +614,23 @@ public class AccountSyncSettings extends AccountPreferenceBase {
|
|||||||
}
|
}
|
||||||
cacheRemoveAllPrefs(getPreferenceScreen());
|
cacheRemoveAllPrefs(getPreferenceScreen());
|
||||||
for (int j = 0, m = authorities.size(); j < m; j++) {
|
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....
|
// We could check services here....
|
||||||
int syncState = ContentResolver.getIsSyncableAsUser(mAccount, authority,
|
int syncState = ContentResolver.getIsSyncableAsUser(mAccount, syncAdapter.authority,
|
||||||
mUserHandle.getIdentifier());
|
mUserHandle.getIdentifier());
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.d(TAG, " found authority " + authority + " " + syncState);
|
Log.d(TAG, " found authority " + syncAdapter.authority + " " + syncState);
|
||||||
}
|
}
|
||||||
if (syncState > 0) {
|
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());
|
removeCachedPrefs(getPreferenceScreen());
|
||||||
|
@@ -36,6 +36,8 @@ public class SyncStateSwitchPreference extends SwitchPreference {
|
|||||||
private boolean mFailed = false;
|
private boolean mFailed = false;
|
||||||
private Account mAccount;
|
private Account mAccount;
|
||||||
private String mAuthority;
|
private String mAuthority;
|
||||||
|
private String mPackageName;
|
||||||
|
private int mUid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mode for this preference where clicking does a one-time sync instead of
|
* 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);
|
super(context, attrs, 0, R.style.SyncSwitchPreference);
|
||||||
mAccount = null;
|
mAccount = null;
|
||||||
mAuthority = 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);
|
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;
|
mAccount = account;
|
||||||
mAuthority = authority;
|
mAuthority = authority;
|
||||||
|
mPackageName = packageName;
|
||||||
|
mUid = uid;
|
||||||
notifyChanged();
|
notifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,4 +159,12 @@ public class SyncStateSwitchPreference extends SwitchPreference {
|
|||||||
public String getAuthority() {
|
public String getAuthority() {
|
||||||
return mAuthority;
|
return mAuthority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPackageName() {
|
||||||
|
return mPackageName;
|
||||||
|
};
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return mUid;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user