1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.controls.ui 18 19 import android.app.Activity 20 import android.graphics.Color 21 import android.graphics.drawable.ShapeDrawable 22 import android.util.DisplayMetrics 23 import android.view.View 24 import android.view.ViewGroup 25 import android.widget.PopupWindow.OnDismissListener 26 import androidx.test.ext.junit.rules.ActivityScenarioRule 27 import androidx.test.ext.junit.runners.AndroidJUnit4 28 import androidx.test.filters.SmallTest 29 import com.android.systemui.res.R 30 import com.android.systemui.SysuiTestCase 31 import com.android.systemui.activity.EmptyTestActivity 32 import com.android.systemui.util.mockito.whenever 33 import com.android.systemui.widget.FakeListAdapter 34 import com.android.systemui.widget.FakeListAdapter.FakeListAdapterItem 35 import com.google.common.truth.Truth.assertThat 36 import org.junit.Before 37 import org.junit.Rule 38 import org.junit.Test 39 import org.junit.runner.RunWith 40 import org.mockito.Mockito.mock 41 import org.mockito.Mockito.spy 42 import org.mockito.Mockito.verify 43 import org.mockito.MockitoAnnotations 44 45 @SmallTest 46 @RunWith(AndroidJUnit4::class) 47 open class ControlsPopupMenuTest : SysuiTestCase() { 48 49 private companion object { 50 51 const val DISPLAY_WIDTH_NARROW = 100 52 const val DISPLAY_WIDTH_WIDE = 1000 53 54 const val MAX_WIDTH = 380 55 const val HORIZONTAL_MARGIN = 16 56 } 57 58 @Rule @JvmField val activityScenarioRule = ActivityScenarioRule(EmptyTestActivity::class.java) 59 60 private val testDisplayMetrics = DisplayMetrics() 61 62 @Before 63 fun setup() { 64 MockitoAnnotations.initMocks(this) 65 } 66 67 @Test 68 fun testDismissListenerWorks() = testPopup { activity, popupMenu -> 69 popupMenu.setAdapter(FakeListAdapter()) 70 val listener = mock(OnDismissListener::class.java) 71 popupMenu.setOnDismissListener(listener) 72 popupMenu.show() 73 74 popupMenu.dismissImmediate() 75 76 verify(listener).onDismiss() 77 } 78 79 @Test 80 fun testPopupDoesntExceedMaxWidth() = testPopup { activity, popupMenu -> 81 popupMenu.setAdapter(FakeListAdapter()) 82 popupMenu.width = ViewGroup.LayoutParams.MATCH_PARENT 83 testDisplayMetrics.widthPixels = DISPLAY_WIDTH_WIDE 84 85 popupMenu.show() 86 87 assertThat(popupMenu.width).isEqualTo(MAX_WIDTH) 88 } 89 90 @Test 91 fun testPopupMarginsWidthLessMax() = testPopup { activity, popupMenu -> 92 popupMenu.setAdapter(FakeListAdapter()) 93 popupMenu.width = ViewGroup.LayoutParams.MATCH_PARENT 94 testDisplayMetrics.widthPixels = DISPLAY_WIDTH_NARROW 95 96 popupMenu.show() 97 98 assertThat(popupMenu.width).isEqualTo(DISPLAY_WIDTH_NARROW - 2 * HORIZONTAL_MARGIN) 99 } 100 101 @Test 102 fun testWrapContentDoesntExceedMax() = testPopup { activity, popupMenu -> 103 popupMenu.setAdapter( 104 FakeListAdapter( 105 listOf( 106 FakeListAdapterItem({ _, _, _ -> 107 View(activity).apply { minimumWidth = MAX_WIDTH + 1 } 108 }) 109 ) 110 ) 111 ) 112 popupMenu.width = ViewGroup.LayoutParams.WRAP_CONTENT 113 testDisplayMetrics.widthPixels = DISPLAY_WIDTH_NARROW 114 115 popupMenu.show() 116 117 assertThat(popupMenu.width).isEqualTo(DISPLAY_WIDTH_NARROW - 2 * HORIZONTAL_MARGIN) 118 } 119 120 private fun testPopup(test: (activity: Activity, popup: ControlsPopupMenu) -> Unit) { 121 activityScenarioRule.scenario.onActivity { activity -> 122 val testActivity = setupActivity(activity) 123 test( 124 testActivity, 125 ControlsPopupMenu(testActivity).apply { anchorView = View(testActivity) } 126 ) 127 } 128 } 129 130 private fun setupActivity(real: Activity): Activity { 131 val resources = 132 spy(real.resources).apply { 133 whenever(getDimensionPixelSize(R.dimen.control_popup_items_divider_height)) 134 .thenReturn(1) 135 whenever(getDimensionPixelSize(R.dimen.control_popup_horizontal_margin)) 136 .thenReturn(HORIZONTAL_MARGIN) 137 whenever(getDimensionPixelSize(R.dimen.control_popup_max_width)) 138 .thenReturn(MAX_WIDTH) 139 whenever(getDrawable(R.drawable.controls_popup_bg)).thenReturn(ShapeDrawable()) 140 whenever(getColor(R.color.control_popup_dim)).thenReturn(Color.WHITE) 141 whenever(displayMetrics).thenAnswer { testDisplayMetrics } 142 } 143 144 return spy(real).also { whenever(it.resources).thenReturn(resources) } 145 } 146 } 147