[DO NOT MERGE] Don't show account access request UI until app launched.

Sync adapters that don't have account access cannot run until
the user explicitly approves in the UI. This is spammy given
the user may not use the app right away. This change doesn't
show the notificaiton until the app has run.

bug:31162498

Change-Id: I1f4f2d2e9426f78763590e8aa542b94d6e93e488
This commit is contained in:
Svet Ganov
2016-09-08 20:15:55 -07:00
committed by Svetoslav Ganov
parent 72ed12c55f
commit d63cde7ba4
6 changed files with 45 additions and 6 deletions

View File

@@ -160,4 +160,12 @@ public abstract class PackageManagerInternal {
* Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
*/
public abstract boolean isPackageDataProtected(int userId, String packageName);
/**
* Gets whether the package was ever launched.
* @param packageName The package name.
* @param userId The user for which to check.
* @return Whether was launched.
*/
public abstract boolean wasPackageEverLaunched(String packageName, int userId);
}

View File

@@ -257,7 +257,9 @@ public final class AccountManagerBackupHelper {
}
// Make sure we eventually prune the in-memory pending restores
mRestoreCancelCommand = new CancelRestoreCommand();
synchronized (mLock) {
mRestoreCancelCommand = new CancelRestoreCommand();
}
mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand,
PENDING_RESTORE_TIMEOUT_MILLIS);
} catch (XmlPullParserException | IOException e) {
@@ -269,6 +271,7 @@ public final class AccountManagerBackupHelper {
@Override
public void onPackageAdded(String packageName, int uid) {
synchronized (mLock) {
// Can happen if restore is cancelled and there is a notification in flight
if (mRestorePendingAppPermissions == null) {
return;
}

View File

@@ -319,7 +319,7 @@ public class AccountManagerService
private final SparseArray<UserAccounts> mUsers = new SparseArray<>();
private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray();
private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
private final CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener>
mAppPermissionChangeListeners = new CopyOnWriteArrayList<>();
private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>();

View File

@@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
@@ -324,6 +325,8 @@ public class SyncManager {
private final AccountManagerInternal mAccountManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
private List<UserInfo> getAllUsers() {
return mUserManager.getUsers();
}
@@ -575,6 +578,7 @@ public class SyncManager {
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
// If the UID gained access to the account kick-off syncs lacking account access
@@ -891,9 +895,13 @@ public class SyncManager {
+ "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
}
Bundle finalExtras = new Bundle(extras);
String packageName = syncAdapterInfo.componentName.getPackageName();
// If the app did not run and has no account access, done
if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
continue;
}
mAccountManagerInternal.requestAccountAccess(account.account,
syncAdapterInfo.componentName.getPackageName(),
UserHandle.getUserId(owningUid),
packageName, userId,
new RemoteCallback((Bundle result) -> {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
@@ -2798,9 +2806,14 @@ public class SyncManager {
final int syncOpState = computeSyncOpState(op);
switch (syncOpState) {
case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
String packageName = op.owningPackage;
final int userId = UserHandle.getUserId(op.owningUid);
// If the app did not run and has no account access, done
if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
return;
}
mAccountManagerInternal.requestAccountAccess(op.target.account,
op.owningPackage, UserHandle.getUserId(op.owningUid),
new RemoteCallback((Bundle result) -> {
packageName, userId, new RemoteCallback((Bundle result) -> {
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
updateOrAddPeriodicSync(target, pollFrequency, flex, extras);

View File

@@ -20980,6 +20980,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
public boolean isPackageDataProtected(int userId, String packageName) {
return mProtectedPackages.isPackageDataProtected(userId, packageName);
}
@Override
public boolean wasPackageEverLaunched(String packageName, int userId) {
synchronized (mPackages) {
return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
}
}
}
@Override

View File

@@ -4154,6 +4154,14 @@ final class Settings {
return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
}
boolean wasPackageEverLaunchedLPr(String packageName, int userId) {
final PackageSetting pkgSetting = mPackages.get(packageName);
if (pkgSetting == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
return !pkgSetting.getNotLaunched(userId);
}
boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName,
boolean stopped, boolean allowedByPermission, int uid, int userId) {
int appId = UserHandle.getAppId(uid);