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

Commit e3ecf5bb authored by Fan Zhang's avatar Fan Zhang
Browse files

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
parent f3365e91
Loading
Loading
Loading
Loading
+21 −23
Original line number Diff line number Diff line
@@ -17,8 +17,6 @@ package com.android.settings.accounts;

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

    @Test
    public void onClick_shouldNotStartConfirmDialogWhenModifyAccountsIsDisallowed() {
    public void onClick_modifyAccountsIsDisallowed_shouldNotStartConfirmDialog() {
        when(mFragment.isAdded()).thenReturn(true);

        final int userId = UserHandle.myUserId();
@@ -195,7 +195,41 @@ public class RemoveAccountPreferenceControllerTest {
        Bundle resultBundle = new Bundle();
        resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
        when(future.getResult()).thenReturn(resultBundle);

        callback.run(future);
        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();
    }
}