blob: 1683c538186cff68e7381ce2ec47d45145f0a9f0 [file] [log] [blame]
/*
* Copyright (C) 2020 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.car.ui;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.android.car.ui.core.CarUi.MIN_TARGET_API;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import androidx.test.espresso.Root;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import com.android.car.ui.recyclerview.CarUiContentListItem;
import com.android.car.ui.recyclerview.CarUiListItemAdapter;
import com.android.car.ui.recyclerview.CarUiRadioButtonListItem;
import com.android.car.ui.recyclerview.CarUiRadioButtonListItemAdapter;
import com.android.car.ui.test.R;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
@TargetApi(MIN_TARGET_API)
public class AlertDialogBuilderTest {
@Rule
public ActivityScenarioRule<TestActivity> mActivityRule =
new ActivityScenarioRule<>(TestActivity.class);
@Test
public void test_AlertDialogBuilder_works() {
String title = "Test message from AlertDialogBuilder";
String subtitle = "Subtitle from AlertDialogBuilder";
runOnUiThread(activity ->
new AlertDialogBuilder(activity)
.setMessage(title)
.setSubtitle(subtitle)
.show());
AlertDialog dialog = checkDefaultButtonExists(true,
runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setMessage(title)
.setSubtitle(subtitle)));
onView(withText(title))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(subtitle))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
}
@Test
public void test_simplePropertiesWithResources_work() {
AlertDialog dialog = runOnUiThread(activity ->
new AlertDialogBuilder(activity)
.setTitle(R.string.title)
.setSubtitle(R.string.subtitle)
.setIcon(R.drawable.ic_launcher)
.setMessage(R.string.message)
.setPositiveButton(R.string.positive, (d, which) -> {})
.setNegativeButton(R.string.negative, (d, which) -> {})
.setNeutralButton(R.string.neutral, (d, which) -> {})
.show());
assertNotNull(dialog);
onView(withText(R.string.title))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(R.string.subtitle))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(R.string.message))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(R.string.positive))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(R.string.negative))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText(R.string.neutral))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
}
@Test
public void test_simplePropertiesWithStrings_work() {
AlertDialog dialog = runOnUiThread(activity ->
new AlertDialogBuilder(activity)
.setTitle("Title!!")
.setSubtitle("Subtitle!!")
.setIcon(activity.getDrawable(R.drawable.ic_launcher))
.setMessage("Message!!")
.setPositiveButton("Positive!!", (d, which) -> {})
.setNegativeButton("Negative!!", (d, which) -> {})
.setNeutralButton("Neutral!!", (d, which) -> {})
.show());
assertNotNull(dialog);
onView(withText("Title!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Subtitle!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Message!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Positive!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Negative!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Neutral!!"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
}
@Test
public void test_setCursor_works() {
FakeCursor cursor = new FakeCursor(Arrays.asList("Item 1", "Item 2"), "items");
AlertDialog dialog = runOnUiThread(activity ->
new AlertDialogBuilder(activity)
.setCursor(cursor, (d, which) -> {}, "items")
.show());
assertNotNull(dialog);
onView(withText("Item 1"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Item 2"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
}
@Test
public void test_getContext_works() {
Context context = runOnUiThread(activity ->
new AlertDialogBuilder(activity).getContext());
assertNotNull(context);
}
@Test
public void test_setCarUiRadioButtons_works() {
CarUiRadioButtonListItem item1 = new CarUiRadioButtonListItem();
item1.setTitle("Item 1");
CarUiRadioButtonListItem item2 = new CarUiRadioButtonListItem();
item2.setTitle("Item 2");
AlertDialog dialog = runOnUiThread(activity ->
new AlertDialogBuilder(activity)
.setSingleChoiceItems(
new CarUiRadioButtonListItemAdapter(Arrays.asList(item1, item2)))
.show());
assertNotNull(dialog);
onView(withText("Item 1"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
onView(withText("Item 2"))
.inRoot(RootWithDecorMatcher.get(dialog))
.check(matches(isDisplayed()));
}
@Test
public void test_showSingleListChoiceItem_StringArray_hidesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setSingleChoiceItems(new CharSequence[]{"Item 1", "Item 2"}, 0,
(dialog, which) -> {}));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_showSingleListChoiceItem_StringArrayResource_hidesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setSingleChoiceItems(R.array.test_string_array, 0, (dialog, which) -> {}));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_singleListChoiceItems_CarUiRadioButtonListItemAdapter_forcesDefaultButton() {
CarUiRadioButtonListItem item1 = new CarUiRadioButtonListItem();
item1.setTitle("Item 1");
CarUiRadioButtonListItem item2 = new CarUiRadioButtonListItem();
item2.setTitle("Item 2");
CarUiRadioButtonListItem item3 = new CarUiRadioButtonListItem();
item3.setTitle("Item 3");
CarUiRadioButtonListItemAdapter adapter = new CarUiRadioButtonListItemAdapter(
Arrays.asList(item1, item2, item3));
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setSingleChoiceItems(adapter));
checkDefaultButtonExists(true, builder);
}
@Test
public void test_showSingleListChoiceItem_cursor_hidesDefaultButton() {
Cursor cursor = new FakeCursor(Arrays.asList("Item 1", "Item 2"), "ColumnName");
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setTitle("Title")
.setAllowDismissButton(false)
.setSingleChoiceItems(cursor, 0, "ColumnName", (dialog, which) -> {}));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_setItems_StringArrayResource_hidesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setItems(R.array.test_string_array, (dialog, which) -> {}));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_setItems_StringArray_hidesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setItems(new CharSequence[]{"Item 1", "Item 2"}, (dialog, which) -> {}));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_setAdapter_hidesDefaultButton() {
CarUiContentListItem item1 = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
item1.setTitle("Item 1");
CarUiContentListItem item2 = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
item2.setTitle("Item 2");
CarUiContentListItem item3 = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
item3.setTitle("Item 3");
CarUiListItemAdapter adapter = new CarUiListItemAdapter(
Arrays.asList(item1, item2, item3));
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setAdapter(adapter));
checkDefaultButtonExists(false, builder);
}
@Test
public void test_multichoiceItems_StringArrayResource_forcesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setMultiChoiceItems(R.array.test_string_array, null,
(dialog, which, isChecked) -> {}));
checkDefaultButtonExists(true, builder);
}
@Test
public void test_multichoiceItems_StringArray_forcesDefaultButton() {
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setMultiChoiceItems(new CharSequence[]{"Test 1", "Test 2"}, null,
(dialog, which, isChecked) -> {}));
checkDefaultButtonExists(true, builder);
}
@Test
public void test_multichoiceItems_Cursor_forcesDefaultButton() {
Cursor cursor = new FakeCursor(Arrays.asList("Item 1", "Item 2"), "Label");
AlertDialogBuilder builder = runOnUiThread(activity -> new AlertDialogBuilder(activity)
.setAllowDismissButton(false)
.setMultiChoiceItems(cursor, "isChecked", "Label",
(dialog, which, isChecked) -> {}));
checkDefaultButtonExists(true, builder);
}
private AlertDialog checkDefaultButtonExists(boolean shouldExist, AlertDialogBuilder builder) {
AtomicBoolean didThrowException = new AtomicBoolean(false);
AlertDialog[] result = new AlertDialog[1];
RuntimeException[] exception = new RuntimeException[1];
mActivityRule.getScenario().onActivity(activity -> {
try {
result[0] = builder.create();
result[0].show();
} catch (RuntimeException e) {
exception[0] = e;
didThrowException.set(true);
}
});
if (didThrowException.get()) {
assertNotNull(exception[0]);
assertEquals("The dialog must have at least one button to disable the dismiss button",
exception[0].getMessage());
assertTrue(shouldExist);
return result[0];
}
if (shouldExist) {
onView(withText(R.string.car_ui_alert_dialog_default_button))
.inRoot(RootWithDecorMatcher.get(result[0]))
.check(matches(isDisplayed()));
} else {
onView(withText(R.string.car_ui_alert_dialog_default_button))
.inRoot(RootWithDecorMatcher.get(result[0]))
.check(doesNotExist());
}
return result[0];
}
private <T> T runOnUiThread(Function<Activity, T> block) {
ArrayList<T> result = new ArrayList<>();
mActivityRule.getScenario().onActivity(activity -> result.add(block.apply(activity)));
if (result.isEmpty()) {
return null;
} else {
return result.get(0);
}
}
private static class RootWithDecorMatcher extends TypeSafeMatcher<Root> {
private final View mView;
static RootWithDecorMatcher get(Dialog dialog) {
return new RootWithDecorMatcher(dialog.getWindow().getDecorView());
}
RootWithDecorMatcher(View view) {
mView = view;
}
@Override
public void describeTo(Description description) {
description.appendText("is a root with a certain decor");
}
@Override
protected boolean matchesSafely(Root item) {
return item.getDecorView() == mView;
}
}
}