blob: a07e8c9ea0c2d83909c8aeb7853920045f954a52 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.webapps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.Feature;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Test for the dialog warning that WebApks have an updated name/icon.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class WebApkIconNameUpdateDialogTest {
// A callback that fires when an action is taken in a dialog.
private final CallbackHelper mOnActionCallback = new CallbackHelper();
private final MockModalDialogManager mDialogManager = new MockModalDialogManager();
private Integer mLastDismissalCause;
private static class DialogParams {
public static DialogParams createDefault() {
DialogParams dialogParams = new DialogParams();
dialogParams.iconChanged = false;
dialogParams.expectIconShownAnyway = false;
dialogParams.bitmapBefore = null;
dialogParams.bitmapAfter = null;
dialogParams.shortNameChanged = false;
dialogParams.expectShortNameShownAnyway = false;
dialogParams.shortNameBefore = "";
dialogParams.shortNameAfter = "";
dialogParams.nameChanged = false;
dialogParams.nameBefore = "";
dialogParams.nameAfter = "";
return dialogParams;
}
public boolean iconChanged;
public boolean expectIconShownAnyway;
public Bitmap bitmapBefore;
public Bitmap bitmapAfter;
public boolean shortNameChanged;
public boolean expectShortNameShownAnyway;
public String shortNameBefore;
public String shortNameAfter;
public boolean nameChanged;
public String nameBefore;
public String nameAfter;
}
private static class MockModalDialogManager extends ModalDialogManager {
private PropertyModel mCurrentDialogModel;
public MockModalDialogManager() {
super(Mockito.mock(Presenter.class), 0);
}
@Override
public void showDialog(PropertyModel model, int dialogType) {
mCurrentDialogModel = model;
}
public PropertyModel getCurrentDialogModel() {
return mCurrentDialogModel;
}
public void dismissCurrentDialog(int dismissalCause) {
mCurrentDialogModel.get(ModalDialogProperties.CONTROLLER)
.onDismiss(mCurrentDialogModel, dismissalCause);
}
}
/**
* Generates a 320x320 test single-colored bitmap.
*/
private static Bitmap generateTestBitmap(int color) {
int width = 320;
int height = 320;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColor(color);
paint.setStyle(Paint.Style.FILL);
canvas.drawPaint(paint);
return bitmap;
}
private View getDialogCustomView() {
return mDialogManager.getCurrentDialogModel().get(ModalDialogProperties.CUSTOM_VIEW);
}
private String getDialogTitle() {
return mDialogManager.getCurrentDialogModel().get(ModalDialogProperties.TITLE).toString();
}
private Bitmap getUpdateDialogBitmap(int resId) {
ImageView imageView = getDialogCustomView().findViewById(resId);
if (imageView.getVisibility() != View.VISIBLE) return null;
return ((BitmapDrawable) imageView.getDrawable()).getBitmap();
}
private String getUpdateDialogAppNameLabel(int resId) {
TextView textView = getDialogCustomView().findViewById(resId);
if (textView.getVisibility() != View.VISIBLE) return null;
return textView.getText().toString();
}
private void onUpdateDialogResult(Integer dialogDismissalCause) {
mLastDismissalCause = dialogDismissalCause;
mOnActionCallback.notifyCalled();
}
private void onAbuseDialogResult() {
mOnActionCallback.notifyCalled();
}
public void verifyValues(boolean clickAccept, DialogParams dialogParams) {
int callCount = mOnActionCallback.getCallCount();
WebApkIconNameUpdateDialog dialog = new WebApkIconNameUpdateDialog();
dialog.show(mDialogManager, /* packageName= */ "", dialogParams.iconChanged,
dialogParams.shortNameChanged, dialogParams.nameChanged,
dialogParams.shortNameBefore, dialogParams.shortNameAfter, dialogParams.nameBefore,
dialogParams.nameAfter, dialogParams.bitmapBefore, dialogParams.bitmapAfter, false,
false, this::onUpdateDialogResult);
Assert.assertEquals(dialogParams.shortNameChanged || dialogParams.expectShortNameShownAnyway
? dialogParams.shortNameBefore
: null,
getUpdateDialogAppNameLabel(R.id.short_app_name_old));
Assert.assertEquals(dialogParams.shortNameChanged || dialogParams.expectShortNameShownAnyway
? dialogParams.shortNameAfter
: null,
getUpdateDialogAppNameLabel(R.id.short_app_name_new));
Assert.assertEquals(dialogParams.nameChanged ? dialogParams.nameBefore : null,
getUpdateDialogAppNameLabel(R.id.app_name_old));
Assert.assertEquals(dialogParams.nameChanged ? dialogParams.nameAfter : null,
getUpdateDialogAppNameLabel(R.id.app_name_new));
Assert.assertEquals(dialogParams.iconChanged || dialogParams.expectIconShownAnyway
? dialogParams.bitmapBefore
: null,
getUpdateDialogBitmap(R.id.app_icon_old));
Assert.assertEquals(dialogParams.iconChanged || dialogParams.expectIconShownAnyway
? dialogParams.bitmapAfter
: null,
getUpdateDialogBitmap(R.id.app_icon_new));
mDialogManager.dismissCurrentDialog(clickAccept
? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
: DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
Assert.assertEquals(callCount + 1, mOnActionCallback.getCallCount());
Assert.assertEquals(clickAccept ? (Integer) DialogDismissalCause.POSITIVE_BUTTON_CLICKED
: (Integer) DialogDismissalCause.NEGATIVE_BUTTON_CLICKED,
mLastDismissalCause);
}
public void verifyReportAbuseValues(
boolean clickAccept, String shortAppName, String expectedTitle) throws Exception {
int callCount = mOnActionCallback.getCallCount();
WebApkUpdateReportAbuseDialog dialog = new WebApkUpdateReportAbuseDialog(
mDialogManager, /* packageName= */ "", shortAppName, this::onAbuseDialogResult);
dialog.show();
Assert.assertEquals(expectedTitle, getDialogTitle());
mDialogManager.dismissCurrentDialog(clickAccept
? DialogDismissalCause.POSITIVE_BUTTON_CLICKED
: DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
// Pressing Cancel on the Abuse dialog does not activate the dismiss-parent callback
// (because the parent dialog is not supposed to dismiss).
Assert.assertEquals(callCount + (clickAccept ? 1 : 0), mOnActionCallback.getCallCount());
}
@Test
@SmallTest
@Feature({"Webapps"})
public void testCombinations() throws Throwable {
Bitmap blue = generateTestBitmap(Color.BLUE);
Bitmap red = generateTestBitmap(Color.RED);
// Test only icons changing.
DialogParams dialogParams = DialogParams.createDefault();
dialogParams.iconChanged = true;
dialogParams.bitmapBefore = blue;
dialogParams.bitmapAfter = red;
// When only the icon changes, the short name is shown (as unchanged) to provide context.
dialogParams.expectShortNameShownAnyway = true;
verifyValues(/* clickAccept= */ true, dialogParams);
// Test only short name changing.
dialogParams = DialogParams.createDefault();
dialogParams.shortNameChanged = true;
dialogParams.shortNameBefore = "short1";
dialogParams.shortNameAfter = "short2";
// When only the short name changes, the icon is shown (as unchanged) to provide context.
dialogParams.expectIconShownAnyway = true;
verifyValues(/* clickAccept= */ true, dialogParams);
// Test only long name changing.
dialogParams = DialogParams.createDefault();
dialogParams.nameChanged = true;
dialogParams.nameBefore = "name1";
dialogParams.nameAfter = "name2";
// Icons always show, even if unchanged.
dialogParams.expectIconShownAnyway = true;
verifyValues(/* clickAccept= */ true, dialogParams);
// Test only short name and icon changing.
dialogParams = DialogParams.createDefault();
dialogParams.iconChanged = true;
dialogParams.bitmapBefore = blue;
dialogParams.bitmapAfter = red;
dialogParams.shortNameChanged = true;
dialogParams.shortNameBefore = "short1";
dialogParams.shortNameAfter = "short2";
verifyValues(/* clickAccept= */ true, dialogParams);
// Test only name and icon changing.
dialogParams = DialogParams.createDefault();
dialogParams.iconChanged = true;
dialogParams.bitmapBefore = blue;
dialogParams.bitmapAfter = red;
dialogParams.nameChanged = true;
dialogParams.nameBefore = "name1";
dialogParams.nameAfter = "name2";
verifyValues(/* clickAccept= */ true, dialogParams);
// Test all values changing.
dialogParams = DialogParams.createDefault();
dialogParams.iconChanged = true;
dialogParams.bitmapBefore = blue;
dialogParams.bitmapAfter = red;
dialogParams.shortNameChanged = true;
dialogParams.shortNameBefore = "short1";
dialogParams.shortNameAfter = "short2";
dialogParams.nameChanged = true;
dialogParams.nameBefore = "name1";
dialogParams.nameAfter = "name2";
verifyValues(/* clickAccept= */ true, dialogParams);
// Test all values changing, but dialog gets canceled.
dialogParams = DialogParams.createDefault();
dialogParams.iconChanged = true;
dialogParams.bitmapBefore = blue;
dialogParams.bitmapAfter = red;
dialogParams.shortNameChanged = true;
dialogParams.shortNameBefore = "short1";
dialogParams.shortNameAfter = "short2";
dialogParams.nameChanged = true;
dialogParams.nameBefore = "name1";
dialogParams.nameAfter = "name2";
verifyValues(/* clickAccept= */ false, dialogParams);
}
@Test
@SmallTest
@Feature({"Webapps"})
public void testReportAbuse() throws Throwable {
// Make sure the dialog shows the right values.
verifyReportAbuseValues(/* clickAccept= */ true, "short", "Uninstall 'short'?");
// Make sure Canceling the dialog does the right thing.
verifyReportAbuseValues(/* clickAccept= */ false, "short", "Uninstall 'short'?");
}
}