diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java index 687e6458361..47aa8a6b9a9 100644 --- a/src/com/android/settings/MasterClear.java +++ b/src/com/android/settings/MasterClear.java @@ -123,24 +123,34 @@ public class MasterClear extends InstrumentedPreferenceFragment { return !((requestCode != KEYGUARD_REQUEST) && (requestCode != CREDENTIAL_CONFIRM_REQUEST)); } - @VisibleForTesting - boolean isShowFinalConfirmation(int requestCode, int resultCode) { - return (resultCode == Activity.RESULT_OK) || (requestCode == CREDENTIAL_CONFIRM_REQUEST); - } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); + onActivityResultInternal(requestCode, resultCode, data); + } + + /* + * Internal method that allows easy testing without dealing with super references. + */ + @VisibleForTesting + void onActivityResultInternal(int requestCode, int resultCode, Intent data) { if (!isValidRequestCode(requestCode)) { return; } - // If the user entered a valid keyguard trace, present the final - // confirmation prompt; otherwise, go back to the initial state. - if (isShowFinalConfirmation(requestCode, resultCode)) { - showFinalConfirmation(); - } else { + if (resultCode != Activity.RESULT_OK) { establishInitialState(); + return; + } + + Intent intent = null; + // If returning from a Keyguard request, try to show an account confirmation request if + // applciable. + if (CREDENTIAL_CONFIRM_REQUEST != requestCode + && (intent = getAccountConfirmationIntent()) != null) { + showAccountCredentialConfirmation(intent); + } else { + showFinalConfirmation(); } } @@ -155,7 +165,12 @@ public class MasterClear extends InstrumentedPreferenceFragment { } @VisibleForTesting - boolean tryShowAccountConfirmation() { + void showAccountCredentialConfirmation(Intent intent) { + startActivityForResult(intent, CREDENTIAL_CONFIRM_REQUEST); + } + + @VisibleForTesting + Intent getAccountConfirmationIntent() { final Context context = getActivity(); final String accountType = context.getString(R.string.account_type); final String packageName = context.getString(R.string.account_confirmation_package); @@ -163,7 +178,8 @@ public class MasterClear extends InstrumentedPreferenceFragment { if (TextUtils.isEmpty(accountType) || TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) { - return false; + Log.i(TAG, "Resources not set for account confirmation."); + return null; } final AccountManager am = AccountManager.get(context); Account[] accounts = am.getAccountsByType(accountType); @@ -179,12 +195,14 @@ public class MasterClear extends InstrumentedPreferenceFragment { && packageName.equals(resolution.activityInfo.packageName)) { // Note that we need to check the packagename to make sure that an Activity resolver // wasn't returned. - startActivityForResult( - requestAccountConfirmation, CREDENTIAL_CONFIRM_REQUEST); - return true; + return requestAccountConfirmation; + } else { + Log.i(TAG, "Unable to resolve Activity: " + packageName + "/" + className); } + } else { + Log.d(TAG, "No " + accountType + " accounts installed!"); } - return false; + return null; } /** @@ -210,7 +228,14 @@ public class MasterClear extends InstrumentedPreferenceFragment { return; } - if (!tryShowAccountConfirmation() && !runKeyguardConfirmation(KEYGUARD_REQUEST)) { + if (runKeyguardConfirmation(KEYGUARD_REQUEST)) { + return; + } + + Intent intent = getAccountConfirmationIntent(); + if (intent != null) { + showAccountCredentialConfirmation(intent); + } else { showFinalConfirmation(); } } @@ -228,7 +253,8 @@ public class MasterClear extends InstrumentedPreferenceFragment { * time, then simply reuse the inflated views directly whenever we need * to change contents. */ - private void establishInitialState() { + @VisibleForTesting + void establishInitialState() { mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_master_clear); mInitiateButton.setOnClickListener(mInitiateListener); mExternalStorageContainer = mContentView.findViewById(R.id.erase_external_container); diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java index 776025f1fad..3ba3edb8d7e 100644 --- a/tests/robotests/src/com/android/settings/MasterClearTest.java +++ b/tests/robotests/src/com/android/settings/MasterClearTest.java @@ -18,11 +18,14 @@ package com.android.settings; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -86,6 +89,9 @@ public class MasterClearTest { @Mock private Activity mMockActivity; + @Mock + private Intent mMockIntent; + private ShadowActivity mShadowActivity; private ShadowAccountManager mShadowAccountManager; private Activity mActivity; @@ -110,7 +116,7 @@ public class MasterClearTest { MockitoAnnotations.initMocks(this); mMasterClear = spy(new MasterClear()); mActivity = Robolectric.setupActivity(Activity.class); - mShadowActivity = shadowOf(mActivity); + mShadowActivity = shadowOf(mActivity);https://stackoverflow.com/questions/14889951/how-to-verify-a-method-is-called-two-times-with-mockito-verify // mShadowAccountManager = shadowOf(AccountManager.get(mActivity)); mContentView = LayoutInflater.from(mActivity).inflate(R.layout.master_clear, null); @@ -213,38 +219,115 @@ public class MasterClearTest { } @Test - public void testTryShowAccountConfirmation_unsupported() { - when(mMasterClear.getActivity()).thenReturn(mActivity); - /* Using the default resources, account confirmation shouldn't trigger */ - assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse(); + public void testOnActivityResultInternal_invalideRequest() { + int invalidRequestCode = -1; + doReturn(false).when(mMasterClear).isValidRequestCode(eq(invalidRequestCode)); + + mMasterClear.onActivityResultInternal(invalidRequestCode, Activity.RESULT_OK, null); + + verify(mMasterClear, times(1)).isValidRequestCode(eq(invalidRequestCode)); + verify(mMasterClear, times(0)).establishInitialState(); + verify(mMasterClear, times(0)).getAccountConfirmationIntent(); + verify(mMasterClear, times(0)).showFinalConfirmation(); } @Test - public void testTryShowAccountConfirmation_no_relevant_accounts() { + public void testOnActivityResultInternal_resultCanceled() { + doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + doNothing().when(mMasterClear).establishInitialState(); + + mMasterClear.onActivityResultInternal( + MasterClear.KEYGUARD_REQUEST, Activity.RESULT_CANCELED, null); + + verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + verify(mMasterClear, times(1)).establishInitialState(); + verify(mMasterClear, times(0)).getAccountConfirmationIntent(); + verify(mMasterClear, times(0)).showFinalConfirmation(); + } + + @Test + public void testOnActivityResultInternal_keyguardRequestTriggeringConfirmAccount() { + doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + doReturn(mMockIntent).when(mMasterClear).getAccountConfirmationIntent(); + doNothing().when(mMasterClear).showAccountCredentialConfirmation(eq(mMockIntent)); + + mMasterClear.onActivityResultInternal( + MasterClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null); + + verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + verify(mMasterClear, times(0)).establishInitialState(); + verify(mMasterClear, times(1)).getAccountConfirmationIntent(); + verify(mMasterClear, times(1)).showAccountCredentialConfirmation(eq(mMockIntent)); + } + + @Test + public void testOnActivityResultInternal_keyguardRequestTriggeringShowFinal() { + doReturn(true).when(mMasterClear).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + doReturn(null).when(mMasterClear).getAccountConfirmationIntent(); + doNothing().when(mMasterClear).showFinalConfirmation(); + + mMasterClear.onActivityResultInternal( + MasterClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null); + + verify(mMasterClear, times(1)).isValidRequestCode(eq(MasterClear.KEYGUARD_REQUEST)); + verify(mMasterClear, times(0)).establishInitialState(); + verify(mMasterClear, times(1)).getAccountConfirmationIntent(); + verify(mMasterClear, times(1)).showFinalConfirmation(); + } + + @Test + public void testOnActivityResultInternal_confirmRequestTriggeringShowFinal() { + doReturn(true).when(mMasterClear) + .isValidRequestCode(eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST)); + doNothing().when(mMasterClear).showFinalConfirmation(); + + mMasterClear.onActivityResultInternal( + MasterClear.CREDENTIAL_CONFIRM_REQUEST, Activity.RESULT_OK, null); + + verify(mMasterClear, times(1)) + .isValidRequestCode(eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST)); + verify(mMasterClear, times(0)).establishInitialState(); + verify(mMasterClear, times(0)).getAccountConfirmationIntent(); + verify(mMasterClear, times(1)).showFinalConfirmation(); + } + + @Test + public void testGetAccountConfirmationIntent_unsupported() { + when(mMasterClear.getActivity()).thenReturn(mActivity); + /* Using the default resources, account confirmation shouldn't trigger */ + assertThat(mMasterClear.getAccountConfirmationIntent()).isNull(); + } + + @Test + public void testGetAccountConfirmationIntent_no_relevant_accounts() { when(mMasterClear.getActivity()).thenReturn(mMockActivity); when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE); - when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE); - when(mMockActivity.getString(R.string.account_confirmation_class)).thenReturn(TEST_CONFIRMATION_CLASS); + when(mMockActivity.getString(R.string.account_confirmation_package)) + .thenReturn(TEST_CONFIRMATION_PACKAGE); + when(mMockActivity.getString(R.string.account_confirmation_class)) + .thenReturn(TEST_CONFIRMATION_CLASS); Account[] accounts = new Account[0]; when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager); when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts); - assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse(); + assertThat(mMasterClear.getAccountConfirmationIntent()).isNull(); } @Test - public void testTryShowAccountConfirmation_unresolved() { + public void testGetAccountConfirmationIntent_unresolved() { when(mMasterClear.getActivity()).thenReturn(mMockActivity); when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE); - when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE); - when(mMockActivity.getString(R.string.account_confirmation_class)).thenReturn(TEST_CONFIRMATION_CLASS); + when(mMockActivity.getString(R.string.account_confirmation_package)) + .thenReturn(TEST_CONFIRMATION_PACKAGE); + when(mMockActivity.getString(R.string.account_confirmation_class)) + .thenReturn(TEST_CONFIRMATION_CLASS); Account[] accounts = new Account[] { new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE) }; when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager); when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts); // The package manager should not resolve the confirmation intent targeting the non-existent // confirmation package. when(mMockActivity.getPackageManager()).thenReturn(mPackageManager); - assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse(); + assertThat(mMasterClear.getAccountConfirmationIntent()).isNull(); } @Test @@ -252,8 +335,10 @@ public class MasterClearTest { when(mMasterClear.getActivity()).thenReturn(mMockActivity); // Only try to show account confirmation if the appropriate resource overlays are available. when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE); - when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE); - when(mMockActivity.getString(R.string.account_confirmation_class)).thenReturn(TEST_CONFIRMATION_CLASS); + when(mMockActivity.getString(R.string.account_confirmation_package)) + .thenReturn(TEST_CONFIRMATION_PACKAGE); + when(mMockActivity.getString(R.string.account_confirmation_class)) + .thenReturn(TEST_CONFIRMATION_CLASS); // Add accounts to trigger the search for a resolving intent. Account[] accounts = new Account[] { new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE) }; when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager); @@ -268,10 +353,18 @@ public class MasterClearTest { resolveInfo.activityInfo = activityInfo; when(mPackageManager.resolveActivity(any(), eq(0))).thenReturn(resolveInfo); - // Finally mock out the startActivityForResultCall - doNothing().when(mMasterClear).startActivityForResult(any(), eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST)); + Intent actualIntent = mMasterClear.getAccountConfirmationIntent(); + assertEquals(TEST_CONFIRMATION_PACKAGE, actualIntent.getComponent().getPackageName()); + assertEquals(TEST_CONFIRMATION_CLASS, actualIntent.getComponent().getClassName()); + } - assertThat(mMasterClear.tryShowAccountConfirmation()).isTrue(); + public void testShowAccountCredentialConfirmation() { + // Finally mock out the startActivityForResultCall + doNothing().when(mMasterClear) + .startActivityForResult(eq(mMockIntent), eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST)); + mMasterClear.showAccountCredentialConfirmation(mMockIntent); + verify(mMasterClear, times(1)) + .startActivityForResult(eq(mMockIntent), eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST)); } @Test