Loading src/com/android/settings/security/RequestManageCredentials.java +117 −38 Original line number Diff line number Diff line Loading @@ -19,17 +19,25 @@ package com.android.settings.security; import android.annotation.Nullable; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.os.RemoteException; import android.os.UserManager; import android.security.AppUriAuthenticationPolicy; import android.security.Credentials; import android.security.KeyChain; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; Loading Loading @@ -66,31 +74,100 @@ public class RequestManageCredentials extends Activity { private LinearLayout mButtonPanel; private ExtendedFloatingActionButton mExtendedFab; private HandlerThread mKeyChainTread; private KeyChain.KeyChainConnection mKeyChainConnection; private boolean mDisplayingButtonPanel = false; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Credentials.ACTION_MANAGE_CREDENTIALS.equals(getIntent().getAction())) { if (!Credentials.ACTION_MANAGE_CREDENTIALS.equals(getIntent().getAction())) { Log.e(TAG, "Unable to start activity because intent action is not " + Credentials.ACTION_MANAGE_CREDENTIALS); finishWithResultCancelled(); return; } if (isManagedDevice()) { Log.e(TAG, "Credential management on managed devices should be done by the Device " + "Policy Controller, not a credential management app"); finishWithResultCancelled(); return; } mCredentialManagerPackage = getLaunchedFromPackage(); if (TextUtils.isEmpty(mCredentialManagerPackage)) { Log.e(TAG, "Unknown credential manager app"); finishWithResultCancelled(); return; } setContentView(R.layout.request_manage_credentials); // This is not authenticated, as any app can ask to be the credential management app. mCredentialManagerPackage = getReferrer().getHost(); mAuthenticationPolicy = mKeyChainTread = new HandlerThread("KeyChainConnection"); mKeyChainTread.start(); mKeyChainConnection = getKeyChainConnection(this, mKeyChainTread); AppUriAuthenticationPolicy policy = getIntent().getParcelableExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY); enforceValidAuthenticationPolicy(mAuthenticationPolicy); if (!isValidAuthenticationPolicy(policy)) { Log.e(TAG, "Invalid authentication policy"); finishWithResultCancelled(); return; } mAuthenticationPolicy = policy; loadRecyclerView(); loadButtons(); loadExtendedFloatingActionButton(); addOnScrollListener(); } else { Log.e(TAG, "Unable to start activity because intent action is not " + Credentials.ACTION_MANAGE_CREDENTIALS); finish(); } @Override protected void onDestroy() { super.onDestroy(); if (mKeyChainConnection != null) { mKeyChainConnection.close(); mKeyChainConnection = null; mKeyChainTread.quitSafely(); } } private boolean isValidAuthenticationPolicy(AppUriAuthenticationPolicy policy) { if (policy == null || policy.getAppAndUriMappings().isEmpty()) { return false; } try { // Check whether any of the aliases in the policy already exist for (String alias : policy.getAliases()) { if (mKeyChainConnection.getService().requestPrivateKey(alias) != null) { return false; } } } catch (RemoteException e) { Log.e(TAG, "Invalid authentication policy", e); return false; } return true; } private boolean isManagedDevice() { DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); return dpm.getDeviceOwnerUser() != null || dpm.getProfileOwner() != null || hasManagedProfile(); } private boolean hasManagedProfile() { UserManager um = getSystemService(UserManager.class); for (final UserInfo userInfo : um.getProfiles(getUserId())) { if (userInfo.isManagedProfile()) { return true; } } return false; } private void loadRecyclerView() { mLayoutManager = new LinearLayoutManager(this); mRecyclerView = findViewById(R.id.apps_list); Loading @@ -107,8 +184,10 @@ public class RequestManageCredentials extends Activity { Button dontAllowButton = findViewById(R.id.dont_allow_button); Button allowButton = findViewById(R.id.allow_button); dontAllowButton.setOnClickListener(finishRequestManageCredentials()); allowButton.setOnClickListener(setCredentialManagementApp()); dontAllowButton.setOnClickListener(b -> { finishWithResultCancelled(); }); allowButton.setOnClickListener(b -> setOrUpdateCredentialManagementApp()); } private void loadExtendedFloatingActionButton() { Loading @@ -120,22 +199,26 @@ public class RequestManageCredentials extends Activity { }); } private View.OnClickListener finishRequestManageCredentials() { return v -> { Toast.makeText(this, R.string.request_manage_credentials_dont_allow, Toast.LENGTH_SHORT).show(); setResult(RESULT_CANCELED); private void setOrUpdateCredentialManagementApp() { try { mKeyChainConnection.getService().setCredentialManagementApp( mCredentialManagerPackage, mAuthenticationPolicy); } catch (RemoteException e) { Log.e(TAG, "Unable to set credential manager app", e); } finish(); }; } private View.OnClickListener setCredentialManagementApp() { return v -> { // TODO: Implement allow logic Toast.makeText(this, R.string.request_manage_credentials_allow, Toast.LENGTH_SHORT).show(); finish(); }; @VisibleForTesting KeyChain.KeyChainConnection getKeyChainConnection(Context context, HandlerThread thread) { final Handler handler = new Handler(thread.getLooper()); try { KeyChain.KeyChainConnection connection = KeyChain.bindAsUser( context, handler, Process.myUserHandle()); return connection; } catch (InterruptedException e) { throw new RuntimeException("Faile to bind to KeyChain", e); } } private void addOnScrollListener() { Loading Loading @@ -182,12 +265,8 @@ public class RequestManageCredentials extends Activity { < mRecyclerView.getAdapter().getItemCount() - 1; } private void enforceValidAuthenticationPolicy(AppUriAuthenticationPolicy policy) { // TODO: Check whether any of the aliases in the policy already exist if (policy == null || policy.getAppAndUriMappings().isEmpty()) { Log.e(TAG, "Invalid authentication policy"); private void finishWithResultCancelled() { setResult(RESULT_CANCELED); finish(); } } } tests/robotests/src/com/android/settings/security/RequestManageCredentialsTest.java +102 −25 Original line number Diff line number Diff line Loading @@ -18,18 +18,24 @@ package com.android.settings.security; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.net.Uri; import android.os.UserHandle; import android.security.AppUriAuthenticationPolicy; import android.security.Credentials; import android.security.IKeyChainService; import android.security.KeyChain; import android.widget.Button; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; Loading @@ -37,10 +43,10 @@ import com.android.settings.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowActivity; @RunWith(RobolectricTestRunner.class) public class RequestManageCredentialsTest { Loading @@ -52,7 +58,14 @@ public class RequestManageCredentialsTest { private RequestManageCredentials mActivity; private ShadowActivity mShadowActivity; @Mock private DevicePolicyManager mDevicePolicyManager; @Mock private KeyChain.KeyChainConnection mKeyChainConnection; @Mock private IKeyChainService mKeyChainService; @Before public void setUp() { Loading @@ -60,47 +73,111 @@ public class RequestManageCredentialsTest { } @Test public void onCreate_intentActionNotManageCredentials_finishActivity() { final Intent intent = new Intent("android.security.ANOTHER_ACTION"); public void onCreate_intentActionNotManageCredentials_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS + "_bad"); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_noAuthenticationPolicy_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); initActivity(intent); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_authenticationPolicyProvided_startActivity() { public void onCreate_invalidAuthenticationPolicy_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, "Invalid policy"); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_runOnManagedProfile_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); initActivity(intent); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(new ComponentName("pkg", "cls")); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isFalse(); assertThat((RecyclerView) mActivity.findViewById(R.id.apps_list)).isNotNull(); assertThat((LinearLayout) mActivity.findViewById(R.id.button_panel)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.allow_button)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.dont_allow_button)).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_dontAllowButtonClicked_finishActivity() { public void onCreate_runOnManagedDevice_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); initActivity(intent); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(UserHandle.SYSTEM); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); Button dontAllowButton = mActivity.findViewById(R.id.dont_allow_button); assertThat(dontAllowButton.hasOnClickListeners()).isTrue(); dontAllowButton.performClick(); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); assertThat(mShadowActivity.getResultCode()).isEqualTo(Activity.RESULT_CANCELED); } private void initActivity(@NonNull Intent intent) { mActivity = Robolectric.buildActivity(RequestManageCredentials.class, intent).setup().get(); mShadowActivity = shadowOf(mActivity); @Test public void onCreate_authenticationPolicyProvided_startActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isFalse(); assertThat((RecyclerView) mActivity.findViewById(R.id.apps_list)).isNotNull(); assertThat((LinearLayout) mActivity.findViewById(R.id.button_panel)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.allow_button)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.dont_allow_button)).isNotNull(); } private void setupActivityWithAction(Intent intent) throws Exception { mActivity = spy(Robolectric.buildActivity(RequestManageCredentials.class, intent).get()); doReturn(mKeyChainConnection).when(mActivity).getKeyChainConnection(eq(mActivity), any()); doReturn(mDevicePolicyManager).when(mActivity).getSystemService(DevicePolicyManager.class); when(mKeyChainConnection.getService()).thenReturn(mKeyChainService); } } Loading
src/com/android/settings/security/RequestManageCredentials.java +117 −38 Original line number Diff line number Diff line Loading @@ -19,17 +19,25 @@ package com.android.settings.security; import android.annotation.Nullable; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.os.RemoteException; import android.os.UserManager; import android.security.AppUriAuthenticationPolicy; import android.security.Credentials; import android.security.KeyChain; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; Loading Loading @@ -66,31 +74,100 @@ public class RequestManageCredentials extends Activity { private LinearLayout mButtonPanel; private ExtendedFloatingActionButton mExtendedFab; private HandlerThread mKeyChainTread; private KeyChain.KeyChainConnection mKeyChainConnection; private boolean mDisplayingButtonPanel = false; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Credentials.ACTION_MANAGE_CREDENTIALS.equals(getIntent().getAction())) { if (!Credentials.ACTION_MANAGE_CREDENTIALS.equals(getIntent().getAction())) { Log.e(TAG, "Unable to start activity because intent action is not " + Credentials.ACTION_MANAGE_CREDENTIALS); finishWithResultCancelled(); return; } if (isManagedDevice()) { Log.e(TAG, "Credential management on managed devices should be done by the Device " + "Policy Controller, not a credential management app"); finishWithResultCancelled(); return; } mCredentialManagerPackage = getLaunchedFromPackage(); if (TextUtils.isEmpty(mCredentialManagerPackage)) { Log.e(TAG, "Unknown credential manager app"); finishWithResultCancelled(); return; } setContentView(R.layout.request_manage_credentials); // This is not authenticated, as any app can ask to be the credential management app. mCredentialManagerPackage = getReferrer().getHost(); mAuthenticationPolicy = mKeyChainTread = new HandlerThread("KeyChainConnection"); mKeyChainTread.start(); mKeyChainConnection = getKeyChainConnection(this, mKeyChainTread); AppUriAuthenticationPolicy policy = getIntent().getParcelableExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY); enforceValidAuthenticationPolicy(mAuthenticationPolicy); if (!isValidAuthenticationPolicy(policy)) { Log.e(TAG, "Invalid authentication policy"); finishWithResultCancelled(); return; } mAuthenticationPolicy = policy; loadRecyclerView(); loadButtons(); loadExtendedFloatingActionButton(); addOnScrollListener(); } else { Log.e(TAG, "Unable to start activity because intent action is not " + Credentials.ACTION_MANAGE_CREDENTIALS); finish(); } @Override protected void onDestroy() { super.onDestroy(); if (mKeyChainConnection != null) { mKeyChainConnection.close(); mKeyChainConnection = null; mKeyChainTread.quitSafely(); } } private boolean isValidAuthenticationPolicy(AppUriAuthenticationPolicy policy) { if (policy == null || policy.getAppAndUriMappings().isEmpty()) { return false; } try { // Check whether any of the aliases in the policy already exist for (String alias : policy.getAliases()) { if (mKeyChainConnection.getService().requestPrivateKey(alias) != null) { return false; } } } catch (RemoteException e) { Log.e(TAG, "Invalid authentication policy", e); return false; } return true; } private boolean isManagedDevice() { DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class); return dpm.getDeviceOwnerUser() != null || dpm.getProfileOwner() != null || hasManagedProfile(); } private boolean hasManagedProfile() { UserManager um = getSystemService(UserManager.class); for (final UserInfo userInfo : um.getProfiles(getUserId())) { if (userInfo.isManagedProfile()) { return true; } } return false; } private void loadRecyclerView() { mLayoutManager = new LinearLayoutManager(this); mRecyclerView = findViewById(R.id.apps_list); Loading @@ -107,8 +184,10 @@ public class RequestManageCredentials extends Activity { Button dontAllowButton = findViewById(R.id.dont_allow_button); Button allowButton = findViewById(R.id.allow_button); dontAllowButton.setOnClickListener(finishRequestManageCredentials()); allowButton.setOnClickListener(setCredentialManagementApp()); dontAllowButton.setOnClickListener(b -> { finishWithResultCancelled(); }); allowButton.setOnClickListener(b -> setOrUpdateCredentialManagementApp()); } private void loadExtendedFloatingActionButton() { Loading @@ -120,22 +199,26 @@ public class RequestManageCredentials extends Activity { }); } private View.OnClickListener finishRequestManageCredentials() { return v -> { Toast.makeText(this, R.string.request_manage_credentials_dont_allow, Toast.LENGTH_SHORT).show(); setResult(RESULT_CANCELED); private void setOrUpdateCredentialManagementApp() { try { mKeyChainConnection.getService().setCredentialManagementApp( mCredentialManagerPackage, mAuthenticationPolicy); } catch (RemoteException e) { Log.e(TAG, "Unable to set credential manager app", e); } finish(); }; } private View.OnClickListener setCredentialManagementApp() { return v -> { // TODO: Implement allow logic Toast.makeText(this, R.string.request_manage_credentials_allow, Toast.LENGTH_SHORT).show(); finish(); }; @VisibleForTesting KeyChain.KeyChainConnection getKeyChainConnection(Context context, HandlerThread thread) { final Handler handler = new Handler(thread.getLooper()); try { KeyChain.KeyChainConnection connection = KeyChain.bindAsUser( context, handler, Process.myUserHandle()); return connection; } catch (InterruptedException e) { throw new RuntimeException("Faile to bind to KeyChain", e); } } private void addOnScrollListener() { Loading Loading @@ -182,12 +265,8 @@ public class RequestManageCredentials extends Activity { < mRecyclerView.getAdapter().getItemCount() - 1; } private void enforceValidAuthenticationPolicy(AppUriAuthenticationPolicy policy) { // TODO: Check whether any of the aliases in the policy already exist if (policy == null || policy.getAppAndUriMappings().isEmpty()) { Log.e(TAG, "Invalid authentication policy"); private void finishWithResultCancelled() { setResult(RESULT_CANCELED); finish(); } } }
tests/robotests/src/com/android/settings/security/RequestManageCredentialsTest.java +102 −25 Original line number Diff line number Diff line Loading @@ -18,18 +18,24 @@ package com.android.settings.security; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Intent; import android.net.Uri; import android.os.UserHandle; import android.security.AppUriAuthenticationPolicy; import android.security.Credentials; import android.security.IKeyChainService; import android.security.KeyChain; import android.widget.Button; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; Loading @@ -37,10 +43,10 @@ import com.android.settings.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowActivity; @RunWith(RobolectricTestRunner.class) public class RequestManageCredentialsTest { Loading @@ -52,7 +58,14 @@ public class RequestManageCredentialsTest { private RequestManageCredentials mActivity; private ShadowActivity mShadowActivity; @Mock private DevicePolicyManager mDevicePolicyManager; @Mock private KeyChain.KeyChainConnection mKeyChainConnection; @Mock private IKeyChainService mKeyChainService; @Before public void setUp() { Loading @@ -60,47 +73,111 @@ public class RequestManageCredentialsTest { } @Test public void onCreate_intentActionNotManageCredentials_finishActivity() { final Intent intent = new Intent("android.security.ANOTHER_ACTION"); public void onCreate_intentActionNotManageCredentials_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS + "_bad"); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_noAuthenticationPolicy_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); initActivity(intent); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_authenticationPolicyProvided_startActivity() { public void onCreate_invalidAuthenticationPolicy_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, "Invalid policy"); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_runOnManagedProfile_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); initActivity(intent); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(new ComponentName("pkg", "cls")); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isFalse(); assertThat((RecyclerView) mActivity.findViewById(R.id.apps_list)).isNotNull(); assertThat((LinearLayout) mActivity.findViewById(R.id.button_panel)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.allow_button)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.dont_allow_button)).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); } @Test public void onCreate_dontAllowButtonClicked_finishActivity() { public void onCreate_runOnManagedDevice_finishActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); initActivity(intent); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(UserHandle.SYSTEM); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); Button dontAllowButton = mActivity.findViewById(R.id.dont_allow_button); assertThat(dontAllowButton.hasOnClickListeners()).isTrue(); dontAllowButton.performClick(); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isTrue(); assertThat(mShadowActivity.getResultCode()).isEqualTo(Activity.RESULT_CANCELED); } private void initActivity(@NonNull Intent intent) { mActivity = Robolectric.buildActivity(RequestManageCredentials.class, intent).setup().get(); mShadowActivity = shadowOf(mActivity); @Test public void onCreate_authenticationPolicyProvided_startActivity() throws Exception { final Intent intent = new Intent(Credentials.ACTION_MANAGE_CREDENTIALS); intent.putExtra(KeyChain.EXTRA_AUTHENTICATION_POLICY, AUTHENTICATION_POLICY); setupActivityWithAction(intent); when(mDevicePolicyManager.getDeviceOwnerUser()).thenReturn(null); when(mDevicePolicyManager.getProfileOwner()).thenReturn(null); when(mActivity.getLaunchedFromPackage()).thenReturn("com.example.credapp"); mActivity.onCreate(null); assertThat(mActivity).isNotNull(); assertThat(mActivity.isFinishing()).isFalse(); assertThat((RecyclerView) mActivity.findViewById(R.id.apps_list)).isNotNull(); assertThat((LinearLayout) mActivity.findViewById(R.id.button_panel)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.allow_button)).isNotNull(); assertThat((Button) mActivity.findViewById(R.id.dont_allow_button)).isNotNull(); } private void setupActivityWithAction(Intent intent) throws Exception { mActivity = spy(Robolectric.buildActivity(RequestManageCredentials.class, intent).get()); doReturn(mKeyChainConnection).when(mActivity).getKeyChainConnection(eq(mActivity), any()); doReturn(mDevicePolicyManager).when(mActivity).getSystemService(DevicePolicyManager.class); when(mKeyChainConnection.getService()).thenReturn(mKeyChainService); } }