blob: bb169411298062ca1b15b0465cab6f3808c60551 [file] [log] [blame]
/*
* Copyright (C) 2015 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 androidx.appcompat.app;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static androidx.appcompat.testutils.TestUtilsActions.setSystemUiVisibility;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SdkSuppress;
import android.support.test.filters.SmallTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.Menu;
import android.view.View;
import android.view.WindowInsets;
import androidx.annotation.RequiresApi;
import androidx.appcompat.custom.FitWindowsContentLayout;
import androidx.appcompat.test.R;
import androidx.appcompat.testutils.BaseTestActivity;
import androidx.appcompat.view.ActionMode;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public abstract class BaseBasicsTestCase<A extends BaseTestActivity> {
@Rule
public final ActivityTestRule<A> mActivityTestRule;
protected BaseBasicsTestCase(Class<A> activityClass) {
mActivityTestRule = new ActivityTestRule<>(activityClass);
}
@Test
public void testActionBarExists() {
assertNotNull("ActionBar is not null",
mActivityTestRule.getActivity().getSupportActionBar());
}
@Test
public void testDefaultActionBarTitle() {
assertEquals(mActivityTestRule.getActivity().getTitle(),
mActivityTestRule.getActivity().getSupportActionBar().getTitle());
}
@UiThreadTest
@Test
public void testSetActionBarTitle() {
final String newTitle = "hello";
mActivityTestRule.getActivity().setTitle(newTitle);
assertEquals("New title is set to ActionBar",
newTitle, mActivityTestRule.getActivity().getSupportActionBar().getTitle());
}
@Test
@SdkSuppress(minSdkVersion = 16)
@RequiresApi(16)
public void testFitSystemWindowsReachesContent() {
final FitWindowsContentLayout content =
mActivityTestRule.getActivity().findViewById(R.id.test_content);
assertNotNull(content);
if (!canShowSystemUi(mActivityTestRule.getActivity())) {
// Device cannot show system UI so setSystemUiVisibility will do nothing.
return;
}
// Call setSystemUiVisibility with flags which will cause window insets to be dispatched
final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
onView(withId(R.id.test_content)).perform(setSystemUiVisibility(flags));
assertTrue(content.getFitsSystemWindowsCalled());
}
@Test
@SdkSuppress(minSdkVersion = 21)
@RequiresApi(21)
public void testOnApplyWindowInsetsReachesContent() {
final View content = mActivityTestRule.getActivity().findViewById(R.id.test_content);
assertNotNull(content);
if (!canShowSystemUi(mActivityTestRule.getActivity())) {
// Device cannot show system UI so setSystemUiVisibility will do nothing.
return;
}
// Create a spy of one of our test listener and set it on our content
final View.OnApplyWindowInsetsListener spyListener
= spy(new TestOnApplyWindowInsetsListener());
content.setOnApplyWindowInsetsListener(spyListener);
// Call setSystemUiVisibility with flags which will cause window insets to be dispatched
final int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
onView(withId(R.id.test_content)).perform(setSystemUiVisibility(flags));
// Verify that the listener was called at least once
verify(spyListener, atLeastOnce())
.onApplyWindowInsets(eq(content), any(WindowInsets.class));
}
@Test
@UiThreadTest
public void testSupportActionModeCallbacks() {
final A activity = mActivityTestRule.getActivity();
// Create a mock action mode callback which returns true from onCreateActionMode
final ActionMode.Callback callback = mock(ActionMode.Callback.class);
when(callback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).thenReturn(true);
// Start an action mode
final ActionMode actionMode = activity.startSupportActionMode(callback);
assertNotNull(actionMode);
// Now verify that onCreateActionMode and onPrepareActionMode are called once
verify(callback).onCreateActionMode(any(ActionMode.class), any(Menu.class));
verify(callback).onPrepareActionMode(any(ActionMode.class), any(Menu.class));
// Now finish and verify that onDestroyActionMode is called once, and there are no more
// interactions
actionMode.finish();
verify(callback).onDestroyActionMode(any(ActionMode.class));
verifyNoMoreInteractions(callback);
}
@Test
@UiThreadTest
public void testSupportActionModeCallbacksInvalidate() {
final A activity = mActivityTestRule.getActivity();
// Create a mock action mode callback which returns true from onCreateActionMode
final ActionMode.Callback callback = mock(ActionMode.Callback.class);
when(callback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).thenReturn(true);
// Start an action mode
final ActionMode actionMode = activity.startSupportActionMode(callback);
// Assert that one was created
assertNotNull(actionMode);
// Reset the mock so that any callback counts from the create are reset
reset(callback);
// Now invalidate the action mode
actionMode.invalidate();
// Now verify that onCreateActionMode is not called, and onPrepareActionMode is called once
verify(callback, never()).onCreateActionMode(any(ActionMode.class), any(Menu.class));
verify(callback).onPrepareActionMode(any(ActionMode.class), any(Menu.class));
}
@Test
@UiThreadTest
public void testSupportActionModeCallbacksWithFalseOnCreate() {
final A activity = mActivityTestRule.getActivity();
// Create a mock action mode callback which returns true from onCreateActionMode
final ActionMode.Callback callback = mock(ActionMode.Callback.class);
when(callback.onCreateActionMode(any(ActionMode.class), any(Menu.class))).thenReturn(false);
// Start an action mode
final ActionMode actionMode = activity.startSupportActionMode(callback);
// Now verify that onCreateActionMode is called once
verify(callback).onCreateActionMode(any(ActionMode.class), any(Menu.class));
// Now verify that onPrepareActionMode is not called (since onCreateActionMode
// returns false)
verify(callback, never()).onPrepareActionMode(any(ActionMode.class), any(Menu.class));
// Assert that an action mode was not created
assertNull(actionMode);
}
@SuppressWarnings("deprecation")
@SuppressLint("InlinedApi")
private static boolean canShowSystemUi(Activity activity) {
PackageManager manager = activity.getPackageManager();
return !manager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
&& !manager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
&& !manager.hasSystemFeature(PackageManager.FEATURE_WATCH);
}
protected void testSupportActionModeAppCompatCallbacks(final boolean fromWindow) {
final A activity = mActivityTestRule.getActivity();
// Create a mock action mode callback which returns true from onCreateActionMode
final ActionMode.Callback amCallback = mock(ActionMode.Callback.class);
when(amCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class)))
.thenReturn(true);
// Create a mock AppCompatCallback, which returns null from
// onWindowStartingSupportActionMode, and set it on the Activity
final AppCompatCallback apCallback = mock(AppCompatCallback.class);
when(apCallback.onWindowStartingSupportActionMode(any(ActionMode.Callback.class)))
.thenReturn(null);
activity.setAppCompatCallback(apCallback);
// Start an action mode with the action mode callback
final ActionMode actionMode = activity.startSupportActionMode(amCallback);
if (fromWindow) {
// Verify that the callback's onWindowStartingSupportActionMode was called
verify(apCallback).onWindowStartingSupportActionMode(any(ActionMode.Callback.class));
}
// Now assert that an action mode was created
assertNotNull(actionMode);
// Now verify that onSupportActionModeStarted is called once
verify(apCallback).onSupportActionModeStarted(any(ActionMode.class));
// Now finish and verify that onDestroyActionMode is called once
actionMode.finish();
verify(apCallback).onSupportActionModeFinished(any(ActionMode.class));
}
public static class TestOnApplyWindowInsetsListener
implements View.OnApplyWindowInsetsListener {
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
return windowInsets;
}
}
}