Fix a NPE when removing accounts.

Guard against null activity. If activity is already null, there is no
need to call finish().

Fixes: 131180213
Test: robotests
Change-Id: I19232ed67ddd0c3539b1827de23fdc584850b519
This commit is contained in:
Fan Zhang
2019-04-23 15:09:39 -07:00
parent f3365e911d
commit e3ecf5bb9e
2 changed files with 56 additions and 24 deletions

View File

@@ -17,8 +17,6 @@ package com.android.settings.accounts;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException; import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException; import android.accounts.OperationCanceledException;
import android.app.Activity; import android.app.Activity;
@@ -30,6 +28,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.Button;
@@ -153,28 +152,27 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
Activity activity = getTargetFragment().getActivity(); Activity activity = getTargetFragment().getActivity();
AccountManager.get(activity).removeAccountAsUser(mAccount, activity, AccountManager.get(activity).removeAccountAsUser(mAccount, activity,
new AccountManagerCallback<Bundle>() { future -> {
@Override final Activity targetActivity = getTargetFragment().getActivity();
public void run(AccountManagerFuture<Bundle> future) { if (targetActivity == null || targetActivity.isFinishing()) {
Log.w(TAG, "Activity is no longer alive, skipping results");
return;
}
boolean failed = true; boolean failed = true;
try { try {
if (future.getResult() if (future.getResult()
.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
failed = false; failed = false;
} }
} catch (OperationCanceledException e) { } catch (OperationCanceledException
// handled below | IOException
} catch (IOException e) { | AuthenticatorException e) {
// handled below
} catch (AuthenticatorException e) {
// handled below // handled below
} }
final Activity activity = getTargetFragment().getActivity(); if (failed) {
if (failed && activity != null && !activity.isFinishing()) {
RemoveAccountFailureDialog.show(getTargetFragment()); RemoveAccountFailureDialog.show(getTargetFragment());
} else { } else {
activity.finish(); targetActivity.finish();
}
} }
}, null, mUserHandle); }, null, mUserHandle);
} }

View File

@@ -144,7 +144,7 @@ public class RemoveAccountPreferenceControllerTest {
} }
@Test @Test
public void onClick_shouldNotStartConfirmDialogWhenModifyAccountsIsDisallowed() { public void onClick_modifyAccountsIsDisallowed_shouldNotStartConfirmDialog() {
when(mFragment.isAdded()).thenReturn(true); when(mFragment.isAdded()).thenReturn(true);
final int userId = UserHandle.myUserId(); final int userId = UserHandle.myUserId();
@@ -195,7 +195,41 @@ public class RemoveAccountPreferenceControllerTest {
Bundle resultBundle = new Bundle(); Bundle resultBundle = new Bundle();
resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
when(future.getResult()).thenReturn(resultBundle); when(future.getResult()).thenReturn(resultBundle);
callback.run(future); callback.run(future);
verify(activity).finish(); verify(activity).finish();
} }
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void confirmRemove_activityGone_shouldSilentlyRemoveAccount()
throws AuthenticatorException, OperationCanceledException, IOException {
final Account account = new Account("Account11", "com.acct1");
final UserHandle userHandle = new UserHandle(10);
final FragmentActivity activity = mock(FragmentActivity.class);
when(mFragment.isAdded()).thenReturn(true);
when(activity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
when(mFragment.getActivity()).thenReturn(activity).thenReturn(null);
final RemoveAccountPreferenceController.ConfirmRemoveAccountDialog dialog =
RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.show(
mFragment, account, userHandle);
dialog.onCreate(new Bundle());
dialog.onClick(null, 0);
ArgumentCaptor<AccountManagerCallback<Bundle>> callbackCaptor = ArgumentCaptor.forClass(
AccountManagerCallback.class);
verify(mAccountManager).removeAccountAsUser(eq(account), nullable(Activity.class),
callbackCaptor.capture(), nullable(Handler.class), eq(userHandle));
AccountManagerCallback<Bundle> callback = callbackCaptor.getValue();
assertThat(callback).isNotNull();
AccountManagerFuture<Bundle> future = mock(AccountManagerFuture.class);
Bundle resultBundle = new Bundle();
resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
when(future.getResult()).thenReturn(resultBundle);
callback.run(future);
verify(activity, never()).finish();
}
} }