blob: 41f406df29e50f387aaf44106b471c91ad735217 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.managedprovisioning.provisioning;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static com.android.managedprovisioning.common.LogoUtils.saveOrganisationLogo;
import static com.android.managedprovisioning.provisioning.AbstractProvisioningActivity.CANCEL_PROVISIONING_DIALOG_OK;
import static com.android.managedprovisioning.provisioning.AbstractProvisioningActivity.ERROR_DIALOG_OK;
import static com.android.managedprovisioning.provisioning.AbstractProvisioningActivity.ERROR_DIALOG_RESET;
import static com.android.managedprovisioning.provisioning.ProvisioningActivity.RESULT_CODE_DEVICE_OWNER_SET;
import static com.android.managedprovisioning.provisioning.ProvisioningActivity.RESULT_CODE_WORK_PROFILE_CREATED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import static org.robolectric.shadows.ShadowUserManager.FLAG_MANAGED_PROFILE;
import android.app.Activity;
import android.app.Application;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.net.Uri;
import android.os.UserManager;
import android.widget.ImageView;
import androidx.test.core.content.pm.ApplicationInfoBuilder;
import androidx.test.core.content.pm.PackageInfoBuilder;
import com.android.managedprovisioning.R;
import com.android.managedprovisioning.model.ProvisioningParams;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;
/**
* Robolectric tests for {@link ProvisioningActivity}.
*/
@RunWith(RobolectricTestRunner.class)
public class ProvisioningActivityRoboTest {
private static final String ADMIN_PACKAGE = "com.test.admin";
private static final ComponentName ADMIN = new ComponentName(ADMIN_PACKAGE, ".Receiver");
private static final ProvisioningParams DEVICE_OWNER_PARAMS = new ProvisioningParams.Builder()
.setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
.setDeviceAdminComponentName(ADMIN)
.build();
private static final ProvisioningParams PROFILE_OWNER_PARAMS = new ProvisioningParams.Builder()
.setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
.setDeviceAdminComponentName(ADMIN)
.build();
private static final ProvisioningParams QR_PROVISIONING_PARAMS_DO = new ProvisioningParams.Builder()
.setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
.setDeviceAdminComponentName(ADMIN)
.setIsOrganizationOwnedProvisioning(true)
.setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED)
.build();
private static final ProvisioningParams QR_PROVISIONING_PARAMS_PO = new ProvisioningParams.Builder()
.setProvisioningAction(ACTION_PROVISION_MANAGED_PROFILE)
.setDeviceAdminComponentName(ADMIN)
.setIsOrganizationOwnedProvisioning(true)
.setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED)
.build();
private static final Intent PROFILE_OWNER_INTENT = new Intent()
.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, PROFILE_OWNER_PARAMS);
private static final Intent DEVICE_OWNER_INTENT = new Intent()
.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, DEVICE_OWNER_PARAMS);
private static final Intent ADMIN_INTEGRATED_FLOW_INTENT_PO = new Intent()
.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, QR_PROVISIONING_PARAMS_PO);
private static final Intent ADMIN_INTEGRATED_FLOW_INTENT_DO = new Intent()
.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, QR_PROVISIONING_PARAMS_DO);
private static final int ERROR_MESSAGE_ID = R.string.managed_provisioning_error_text;
private static final int DEFAULT_LOGO_COLOR = -15043608;
private static final int CUSTOM_COLOR = Color.parseColor("#d40000");
private static final Uri LOGO_URI = Uri.parse("http://logo");
private ProvisioningManager mMockProvisioningManager = Mockito.mock(ProvisioningManager.class);
private Application mContext = RuntimeEnvironment.application;
@Test
public void error_noFactoryReset_showsDialogue() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT).get();
activity.error(R.string.cant_set_up_device, ERROR_MESSAGE_ID, /* resetRequired= */ false);
final Fragment dialog = activity.getFragmentManager().findFragmentByTag(ERROR_DIALOG_OK);
assertThat(dialog).isNotNull();
}
@Test
public void error_noFactoryReset_doesNotReset() throws Exception {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT).get();
activity.error(R.string.cant_set_up_device, ERROR_MESSAGE_ID, /* resetRequired= */ false);
final Fragment dialog = activity.getFragmentManager().findFragmentByTag(ERROR_DIALOG_OK);
clickOnPositiveButton(activity, (DialogFragment) dialog);
final List<Intent> intents = shadowOf(mContext).getBroadcastIntents();
assertThat(intentsContainsAction(intents, Intent.ACTION_FACTORY_RESET)).isFalse();
}
@Test
public void error_factoryReset_showsDialogue() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT).get();
activity.error(R.string.cant_set_up_device, ERROR_MESSAGE_ID, /* resetRequired= */ true);
final Fragment dialog = activity.getFragmentManager().findFragmentByTag(ERROR_DIALOG_RESET);
assertThat(dialog).isNotNull();
}
@Test
public void error_factoryReset_resets() throws Exception {
DevicePolicyManager devicePolicyManager =
mContext.getSystemService(DevicePolicyManager.class);
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT).get();
activity.error(R.string.cant_set_up_device, ERROR_MESSAGE_ID, /* resetRequired= */ true);
final Fragment dialog = activity.getFragmentManager().findFragmentByTag(ERROR_DIALOG_RESET);
clickOnPositiveButton(activity, (DialogFragment) dialog);
assertThat(shadowOf(devicePolicyManager).getWipeCalledTimes()).isEqualTo(1);
}
@Ignore("b/181326453")
@Test
public void profileOwnerIntent_usesDefaultLogo() throws Throwable {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
assertUsesDefaultLogo(activity);
}
@Ignore("b/181326453")
@Test
public void profileOwnerIntent_setCustomLogo_usesCustomLogo() throws Throwable {
setupCustomLogo(mContext, LOGO_URI);
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
assertUsesCustomLogo(activity);
}
@Ignore("b/181326453")
@Test
public void deviceOwnerIntent_usesDefaultLogo() throws Throwable {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, DEVICE_OWNER_INTENT)
.setup().get();
assertUsesDefaultLogo(activity);
}
@Ignore("b/181326453")
@Test
public void deviceOwnerIntent_setCustomLogo_usesCustomLogo() throws Throwable {
setupCustomLogo(mContext, LOGO_URI);
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, DEVICE_OWNER_INTENT)
.setup().get();
assertUsesCustomLogo(activity);
}
@Ignore("b/181326453")
@Test
public void managedProfileIntent_defaultColor_colorCorrect() {
assertColorsCorrect(
PROFILE_OWNER_INTENT,
DEFAULT_LOGO_COLOR);
}
@Ignore("b/181326453")
@Test
public void deviceOwnerIntent_defaultColor_colorCorrect() {
assertColorsCorrect(
DEVICE_OWNER_INTENT,
DEFAULT_LOGO_COLOR);
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_backPressed_showsCancelDialog() throws Throwable {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
activity.onBackPressed();
final Fragment dialog =
activity.getFragmentManager().findFragmentByTag(CANCEL_PROVISIONING_DIALOG_OK);
assertThat(dialog).isNotNull();
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_backPressed_doNotCancel_doesNotFinishActivity() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
activity.onBackPressed();
final Fragment dialog =
activity.getFragmentManager().findFragmentByTag(CANCEL_PROVISIONING_DIALOG_OK);
clickOnNegativeButton(activity, (DialogFragment) dialog);
assertThat(activity.isFinishing()).isFalse();
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_backPressed_doNotCancel_doesNotCancelProvisioning() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
activity.setProvisioningManager(mMockProvisioningManager);
activity.onBackPressed();
final Fragment dialog =
activity.getFragmentManager().findFragmentByTag(CANCEL_PROVISIONING_DIALOG_OK);
clickOnNegativeButton(activity, (DialogFragment) dialog);
verify(mMockProvisioningManager, never()).cancelProvisioning();
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_backPressed_cancel_doesFinishActivity() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
activity.onBackPressed();
final Fragment dialog =
activity.getFragmentManager().findFragmentByTag(CANCEL_PROVISIONING_DIALOG_OK);
clickOnPositiveButton(activity, (DialogFragment) dialog);
assertThat(activity.isFinishing()).isTrue();
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_backPressed_cancel_doesCancelProvisioning() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, PROFILE_OWNER_INTENT)
.setup().get();
activity.setProvisioningManager(mMockProvisioningManager);
activity.onBackPressed();
final Fragment dialog =
activity.getFragmentManager().findFragmentByTag(CANCEL_PROVISIONING_DIALOG_OK);
clickOnPositiveButton(activity, (DialogFragment) dialog);
verify(mMockProvisioningManager).cancelProvisioning();
}
@Ignore("b/181326453")
@Test
public void activity_profileOwner_adminIntegrated_returnsIntermediateResult() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class,
ADMIN_INTEGRATED_FLOW_INTENT_PO)
.setup().get();
shadowOf(activity.getPackageManager())
.installPackage(
PackageInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.setApplicationInfo(ApplicationInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.build())
.build());
activity.preFinalizationCompleted();
activity.onAllTransitionsShown();
UserManager userManager = activity.getSystemService(UserManager.class);
shadowOf(userManager).addProfile(0, 10, "profile name", FLAG_MANAGED_PROFILE);
activity.onNextButtonClicked();
assertThat(activity.isFinishing()).isTrue();
assertThat(shadowOf(activity).getResultCode()).isEqualTo(RESULT_CODE_WORK_PROFILE_CREATED);
}
@Ignore("b/181326453")
@Test
public void activity_deviceOwner_adminIntegrated_returnsIntermediateResult() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class,
ADMIN_INTEGRATED_FLOW_INTENT_DO)
.setup().get();
shadowOf(activity.getPackageManager())
.installPackage(
PackageInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.setApplicationInfo(ApplicationInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.build())
.build());
activity.preFinalizationCompleted();
activity.onAllTransitionsShown();
activity.onNextButtonClicked();
assertThat(activity.isFinishing()).isTrue();
assertThat(shadowOf(activity).getResultCode()).isEqualTo(RESULT_CODE_DEVICE_OWNER_SET);
}
@Ignore("b/181326453")
@Test
public void activity_deviceOwner_notAdminIntegrated_returnsOk() {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class,
DEVICE_OWNER_INTENT)
.setup().get();
shadowOf(activity.getPackageManager())
.installPackage(
PackageInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.setApplicationInfo(ApplicationInfoBuilder.newBuilder()
.setPackageName(ADMIN_PACKAGE)
.build())
.build());
activity.preFinalizationCompleted();
activity.onAllTransitionsShown();
activity.onNextButtonClicked();
assertThat(activity.isFinishing()).isTrue();
assertThat(shadowOf(activity).getResultCode()).isEqualTo(Activity.RESULT_OK);
}
private Intent createProvisioningIntent(String action) {
final ProvisioningParams provisioningParams = new ProvisioningParams.Builder()
.setProvisioningAction(action)
.setDeviceAdminComponentName(ADMIN)
.build();
final Intent intent = new Intent();
intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, provisioningParams);
return intent;
}
private void assertColorsCorrect(Intent intent, int logoColor) {
final ProvisioningActivity activity =
Robolectric.buildActivity(ProvisioningActivity.class, intent)
.setup().get();
assertDefaultLogoColorCorrect(activity, logoColor);
}
private void assertDefaultLogoColorCorrect(Activity activity, int targetColor) {
Drawable actualLogo =
((ImageView) activity.findViewById(R.id.sud_layout_icon)).getDrawable();
PorterDuffColorFilter colorFilter = (PorterDuffColorFilter) actualLogo.getColorFilter();
assertThat(colorFilter.getColor()).isEqualTo(targetColor);
}
private static boolean intentsContainsAction(List<Intent> intents, String action) {
return intents.stream().anyMatch(intent -> intent.getAction().equals(action));
}
private void clickOnOkButton(ProvisioningActivity activity, DialogFragment dialog) {
// TODO(135181317): This should be replaced by
// activity.findViewById(android.R.id.button1).performClick();
activity.onPositiveButtonClick(dialog);
}
private static void setupCustomLogo(Context context, Uri logoUri) {
Bitmap bitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
InputStream inputStream = bitmapToInputStream(bitmap);
shadowOf(context.getContentResolver()).registerInputStream(logoUri, inputStream);
saveOrganisationLogo(context, logoUri);
}
private static InputStream bitmapToInputStream(Bitmap bitmap) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0 /* ignored for PNG */, bos);
byte[] bitmapdata = bos.toByteArray();
return new ByteArrayInputStream(bitmapdata);
}
private static void assertUsesDefaultLogo(Activity activity) {
final ImageView imageView = activity.findViewById(R.id.sud_layout_icon);
// We default to a vector logo
assertThat(imageView.getDrawable()).isInstanceOf(VectorDrawable.class);
}
private static void assertUsesCustomLogo(Activity activity) {
final ImageView imageView = activity.findViewById(R.id.sud_layout_icon);
// The custom logo we have set is a bitmap
assertThat(imageView.getDrawable()).isInstanceOf(BitmapDrawable.class);
}
private void clickOnPositiveButton(ProvisioningActivity activity, DialogFragment dialog) {
// TODO(135181317): This should be replaced by
// activity.findViewById(android.R.id.button1).performClick();
activity.onPositiveButtonClick(dialog);
}
private void clickOnNegativeButton(ProvisioningActivity activity, DialogFragment dialog) {
// TODO(135181317): This should be replaced by
// activity.findViewById(android.R.id.button2).performClick();
activity.onNegativeButtonClick(dialog);
}
}