Merge "Add better a11y support in QS" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d99c2e88e3
@@ -15,7 +15,6 @@
|
||||
package com.android.systemui.plugins.qs;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
import com.android.systemui.plugins.FragmentBase;
|
||||
import com.android.systemui.plugins.annotations.DependsOn;
|
||||
@@ -34,7 +33,7 @@ public interface QS extends FragmentBase {
|
||||
|
||||
String ACTION = "com.android.systemui.action.PLUGIN_QS";
|
||||
|
||||
int VERSION = 13;
|
||||
int VERSION = 14;
|
||||
|
||||
String TAG = "QS";
|
||||
|
||||
@@ -68,7 +67,12 @@ public interface QS extends FragmentBase {
|
||||
void setHeaderListening(boolean listening);
|
||||
void notifyCustomizeChanged();
|
||||
void setContainerController(QSContainerController controller);
|
||||
void setExpandClickListener(OnClickListener onClickListener);
|
||||
|
||||
/**
|
||||
* Provide an action to collapse if expanded or expand if collapsed.
|
||||
* @param action
|
||||
*/
|
||||
void setCollapseExpandAction(Runnable action);
|
||||
|
||||
/**
|
||||
* Returns the height difference between the QSPanel container and the QuickQSPanel container
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.android.systemui.plugins.qs.QSTile.State;
|
||||
@DependsOn(target = QSIconView.class)
|
||||
@DependsOn(target = QSTile.class)
|
||||
public abstract class QSTileView extends LinearLayout {
|
||||
public static final int VERSION = 2;
|
||||
public static final int VERSION = 3;
|
||||
|
||||
public QSTileView(Context context) {
|
||||
super(context);
|
||||
@@ -71,4 +71,7 @@ public abstract class QSTileView extends LinearLayout {
|
||||
public View getSecondaryLabel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Sets the index of this tile in its layout */
|
||||
public abstract void setPosition(int position);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_marginStart="@dimen/qs_label_container_margin"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:layout_gravity="center_vertical | start">
|
||||
|
||||
<com.android.systemui.util.SafeMarqueeTextView
|
||||
@@ -35,6 +37,8 @@
|
||||
android:ellipsize="marquee"
|
||||
android:marqueeRepeatLimit="1"
|
||||
android:singleLine="true"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:textAppearance="@style/TextAppearance.QS.TileLabel"/>
|
||||
|
||||
<com.android.systemui.util.SafeMarqueeTextView
|
||||
@@ -47,6 +51,8 @@
|
||||
android:marqueeRepeatLimit="1"
|
||||
android:singleLine="true"
|
||||
android:visibility="gone"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:textAppearance="@style/TextAppearance.QS.TileLabel.Secondary"
|
||||
android:textColor="?android:attr/textColorSecondary"/>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Scroller;
|
||||
@@ -552,6 +553,51 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
|
||||
postInvalidateOnAnimation();
|
||||
}
|
||||
|
||||
private int sanitizePageAction(int action) {
|
||||
int pageLeftId = AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT.getId();
|
||||
int pageRightId = AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT.getId();
|
||||
if (action == pageLeftId || action == pageRightId) {
|
||||
if (!isLayoutRtl()) {
|
||||
if (action == pageLeftId) {
|
||||
return AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
|
||||
} else {
|
||||
return AccessibilityNodeInfo.ACTION_SCROLL_FORWARD;
|
||||
}
|
||||
} else {
|
||||
if (action == pageLeftId) {
|
||||
return AccessibilityNodeInfo.ACTION_SCROLL_FORWARD;
|
||||
} else {
|
||||
return AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||
action = sanitizePageAction(action);
|
||||
boolean performed = super.performAccessibilityAction(action, arguments);
|
||||
if (performed && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
|
||||
|| action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)) {
|
||||
requestAccessibilityFocus();
|
||||
}
|
||||
return performed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfoInternal(info);
|
||||
// getCurrentItem does not respect RTL, so it works well together with page actions that
|
||||
// use left/right positioning.
|
||||
if (getCurrentItem() != 0) {
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);
|
||||
}
|
||||
if (getCurrentItem() != mPages.size() - 1) {
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private static Animator setupBounceAnimator(View view, int ordinal) {
|
||||
view.setAlpha(0f);
|
||||
view.setScaleX(0f);
|
||||
|
||||
@@ -48,10 +48,5 @@ public interface QSFooter {
|
||||
*/
|
||||
void setKeyguardShowing(boolean keyguardShowing);
|
||||
|
||||
/**
|
||||
* Sets the {@link android.view.View.OnClickListener to be used on elements that expend QS.
|
||||
*/
|
||||
void setExpandClickListener(View.OnClickListener onClickListener);
|
||||
|
||||
default void disable(int state1, int state2, boolean animate) {}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,11 @@ import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -168,23 +166,6 @@ public class QSFooterView extends FrameLayout {
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||
if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
|
||||
if (mExpandClickListener != null) {
|
||||
mExpandClickListener.onClick(null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
||||
}
|
||||
|
||||
void disable(int state2) {
|
||||
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
|
||||
if (disabled == mQsDisabled) return;
|
||||
|
||||
@@ -114,12 +114,6 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
|
||||
mView.setKeyguardShowing();
|
||||
}
|
||||
|
||||
/** */
|
||||
@Override
|
||||
public void setExpandClickListener(View.OnClickListener onClickListener) {
|
||||
mView.setExpandClickListener(onClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable(int state1, int state2, boolean animate) {
|
||||
mView.disable(state2);
|
||||
|
||||
@@ -31,7 +31,6 @@ import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
@@ -717,8 +716,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpandClickListener(OnClickListener onClickListener) {
|
||||
mFooter.setExpandClickListener(onClickListener);
|
||||
public void setCollapseExpandAction(Runnable action) {
|
||||
mQSPanelController.setCollapseExpandAction(action);
|
||||
mQuickQSPanelController.setCollapseExpandAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -62,6 +63,8 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
private final int mMediaTopMargin;
|
||||
private final int mMediaTotalBottomMargin;
|
||||
|
||||
private Runnable mCollapseExpandAction;
|
||||
|
||||
/**
|
||||
* The index where the content starts that needs to be moved between parents
|
||||
*/
|
||||
@@ -678,6 +681,28 @@ public class QSPanel extends LinearLayout implements Tunable {
|
||||
mShouldMoveMediaOnExpansion = shouldMoveMediaOnExpansion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, Bundle arguments) {
|
||||
if (action == AccessibilityNodeInfo.ACTION_EXPAND
|
||||
|| action == AccessibilityNodeInfo.ACTION_COLLAPSE) {
|
||||
if (mCollapseExpandAction != null) {
|
||||
mCollapseExpandAction.run();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
|
||||
public void setCollapseExpandAction(Runnable action) {
|
||||
mCollapseExpandAction = action;
|
||||
}
|
||||
|
||||
private class H extends Handler {
|
||||
private static final int ANNOUNCE_FOR_ACCESSIBILITY = 1;
|
||||
|
||||
|
||||
@@ -424,6 +424,14 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
|
||||
return mView.getBrightnessView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a listener to collapse/expand QS.
|
||||
* @param action
|
||||
*/
|
||||
public void setCollapseExpandAction(Runnable action) {
|
||||
mView.setCollapseExpandAction(action);
|
||||
}
|
||||
|
||||
/** Sets whether we are currently on lock screen. */
|
||||
public void setIsOnKeyguard(boolean isOnKeyguard) {
|
||||
boolean isOnSplitShadeLockscreen = mShouldUseSplitNotificationShade && isOnKeyguard;
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
@@ -167,6 +168,14 @@ public class QuickQSPanel extends QSPanel {
|
||||
return QSEvent.QQS_TILE_VISIBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
// Remove the collapse action from QSPanel
|
||||
info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
|
||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
|
||||
}
|
||||
|
||||
static class QQSSideLabelTileLayout extends SideLabelTileLayout {
|
||||
|
||||
private boolean mLastSelected;
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -240,6 +241,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
|
||||
} else {
|
||||
record.tileView.setLeftTopRightBottom(left, top, right, bottom);
|
||||
}
|
||||
record.tileView.setPosition(i);
|
||||
mLastTileBottom = bottom;
|
||||
}
|
||||
}
|
||||
@@ -296,4 +298,11 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfoInternal(info);
|
||||
info.setCollectionInfo(
|
||||
new AccessibilityNodeInfo.CollectionInfo(mRecords.size(), 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,12 @@ open class QSTileViewImpl @JvmOverloads constructor(
|
||||
internal const val TILE_STATE_RES_PREFIX = "tile_states_"
|
||||
}
|
||||
|
||||
private var _position: Int = INVALID
|
||||
|
||||
override fun setPosition(position: Int) {
|
||||
_position = position
|
||||
}
|
||||
|
||||
override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
@@ -404,6 +410,10 @@ open class QSTileViewImpl @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_position != INVALID) {
|
||||
info.collectionItemInfo =
|
||||
AccessibilityNodeInfo.CollectionItemInfo(_position, 1, 0, 1, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
@@ -239,7 +239,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
|
||||
private final DozeParameters mDozeParameters;
|
||||
private final OnHeightChangedListener mOnHeightChangedListener = new OnHeightChangedListener();
|
||||
private final OnClickListener mOnClickListener = new OnClickListener();
|
||||
private final Runnable mCollapseExpandAction = new CollapseExpandAction();
|
||||
private final OnOverscrollTopChangedListener
|
||||
mOnOverscrollTopChangedListener =
|
||||
new OnOverscrollTopChangedListener();
|
||||
@@ -3573,7 +3573,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
public void onFragmentViewCreated(String tag, Fragment fragment) {
|
||||
mQs = (QS) fragment;
|
||||
mQs.setPanelView(mHeightListener);
|
||||
mQs.setExpandClickListener(mOnClickListener);
|
||||
mQs.setCollapseExpandAction(mCollapseExpandAction);
|
||||
mQs.setHeaderClickable(isQsExpansionEnabled());
|
||||
mQs.setOverscrolling(mStackScrollerOverscrolling);
|
||||
mQs.setInSplitShade(mShouldUseSplitNotificationShade);
|
||||
@@ -4216,9 +4216,9 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private class OnClickListener implements View.OnClickListener {
|
||||
private class CollapseExpandAction implements Runnable {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
public void run() {
|
||||
onQsExpansionStarted();
|
||||
if (mQsExpanded) {
|
||||
flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Fragment;
|
||||
@@ -304,6 +305,16 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
|
||||
assertThat(mQsFragmentView.getY()).isEqualTo(-qsAbsoluteBottom);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCollapseExpandAction_passedToControllers() {
|
||||
Runnable action = () -> {};
|
||||
QSFragment fragment = resumeAndGetFragment();
|
||||
fragment.setCollapseExpandAction(action);
|
||||
|
||||
verify(mQSPanelController).setCollapseExpandAction(action);
|
||||
verify(mQuickQSPanelController).setCollapseExpandAction(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fragment instantiate(Context context, String className, Bundle arguments) {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
@@ -21,24 +21,19 @@ import android.testing.TestableLooper
|
||||
import android.testing.TestableLooper.RunWithLooper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.plugins.qs.QSTileView
|
||||
import com.android.systemui.qs.QSPanelControllerBase.TileRecord
|
||||
import com.android.systemui.qs.logging.QSLogger
|
||||
import com.android.systemui.qs.tileimpl.QSTileImpl
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyBoolean
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
@@ -47,22 +42,8 @@ class QSPanelTest : SysuiTestCase() {
|
||||
private lateinit var mTestableLooper: TestableLooper
|
||||
private lateinit var mQsPanel: QSPanel
|
||||
|
||||
@Mock
|
||||
private lateinit var mHost: QSTileHost
|
||||
|
||||
@Mock
|
||||
private lateinit var dndTile: QSTileImpl<*>
|
||||
|
||||
@Mock
|
||||
private lateinit var mDndTileRecord: TileRecord
|
||||
|
||||
@Mock
|
||||
private lateinit var mQSLogger: QSLogger
|
||||
private lateinit var mParentView: ViewGroup
|
||||
|
||||
@Mock
|
||||
private lateinit var mQSTileView: QSTileView
|
||||
|
||||
private lateinit var mFooter: View
|
||||
|
||||
@Before
|
||||
@@ -71,8 +52,6 @@ class QSPanelTest : SysuiTestCase() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
mTestableLooper = TestableLooper.get(this)
|
||||
|
||||
mDndTileRecord.tile = dndTile
|
||||
mDndTileRecord.tileView = mQSTileView
|
||||
mTestableLooper.runWithLooper {
|
||||
mQsPanel = QSPanel(mContext, null)
|
||||
mQsPanel.initialize()
|
||||
@@ -86,11 +65,6 @@ class QSPanelTest : SysuiTestCase() {
|
||||
mParentView = FrameLayout(mContext).apply {
|
||||
addView(mQsPanel)
|
||||
}
|
||||
|
||||
whenever(dndTile.tileSpec).thenReturn("dnd")
|
||||
whenever(mHost.tiles).thenReturn(emptyList())
|
||||
whenever(mHost.createTileView(any(), any(), anyBoolean())).thenReturn(mQSTileView)
|
||||
mQsPanel.addTile(mDndTileRecord)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +111,24 @@ class QSPanelTest : SysuiTestCase() {
|
||||
assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(-1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHasCollapseAccessibilityAction() {
|
||||
val info = AccessibilityNodeInfo(mQsPanel)
|
||||
mQsPanel.onInitializeAccessibilityNodeInfo(info)
|
||||
|
||||
assertThat(info.actions and AccessibilityNodeInfo.ACTION_COLLAPSE).isNotEqualTo(0)
|
||||
assertThat(info.actions and AccessibilityNodeInfo.ACTION_EXPAND).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCollapseActionCallsRunnable() {
|
||||
val mockRunnable = mock(Runnable::class.java)
|
||||
mQsPanel.setCollapseExpandAction(mockRunnable)
|
||||
|
||||
mQsPanel.performAccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE, null)
|
||||
verify(mockRunnable).run()
|
||||
}
|
||||
|
||||
private fun getNewOrientationConfig(@Configuration.Orientation newOrientation: Int) =
|
||||
context.resources.configuration.apply { orientation = newOrientation }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.android.systemui.qs
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@SmallTest
|
||||
class QuickQSPanelTest : SysuiTestCase() {
|
||||
|
||||
private lateinit var testableLooper: TestableLooper
|
||||
private lateinit var quickQSPanel: QuickQSPanel
|
||||
|
||||
private lateinit var parentView: ViewGroup
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
testableLooper = TestableLooper.get(this)
|
||||
|
||||
testableLooper.runWithLooper {
|
||||
quickQSPanel = QuickQSPanel(mContext, null)
|
||||
quickQSPanel.initialize()
|
||||
|
||||
quickQSPanel.onFinishInflate()
|
||||
quickQSPanel.setSecurityFooter(View(mContext), false)
|
||||
quickQSPanel.setHeaderContainer(LinearLayout(mContext))
|
||||
// Provides a parent with non-zero size for QSPanel
|
||||
parentView = FrameLayout(mContext).apply {
|
||||
addView(quickQSPanel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHasExpandAccessibilityAction() {
|
||||
val info = AccessibilityNodeInfo(quickQSPanel)
|
||||
quickQSPanel.onInitializeAccessibilityNodeInfo(info)
|
||||
|
||||
Truth.assertThat(info.actions and AccessibilityNodeInfo.ACTION_EXPAND).isNotEqualTo(0)
|
||||
Truth.assertThat(info.actions and AccessibilityNodeInfo.ACTION_COLLAPSE).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExpandActionCallsRunnable() {
|
||||
val mockRunnable = Mockito.mock(Runnable::class.java)
|
||||
quickQSPanel.setCollapseExpandAction(mockRunnable)
|
||||
|
||||
quickQSPanel.performAccessibilityAction(AccessibilityNodeInfo.ACTION_EXPAND, null)
|
||||
Mockito.verify(mockRunnable).run()
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
@@ -170,4 +171,36 @@ public class TileLayoutTest extends SysuiTestCase {
|
||||
mTileLayout.measure(mLayoutSizeForOneTile, mLayoutSizeForOneTile);
|
||||
assertEquals(0, mTileLayout.getMeasuredHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectionInfo() {
|
||||
QSPanelControllerBase.TileRecord tileRecord1 = createTileRecord();
|
||||
QSPanelControllerBase.TileRecord tileRecord2 = createTileRecord();
|
||||
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(mTileLayout);
|
||||
mTileLayout.addTile(tileRecord1);
|
||||
|
||||
mTileLayout.onInitializeAccessibilityNodeInfo(info);
|
||||
AccessibilityNodeInfo.CollectionInfo collectionInfo = info.getCollectionInfo();
|
||||
assertEquals(1, collectionInfo.getRowCount());
|
||||
assertEquals(1, collectionInfo.getColumnCount()); // always use one column
|
||||
|
||||
mTileLayout.addTile(tileRecord2);
|
||||
mTileLayout.onInitializeAccessibilityNodeInfo(info);
|
||||
collectionInfo = info.getCollectionInfo();
|
||||
assertEquals(2, collectionInfo.getRowCount());
|
||||
assertEquals(1, collectionInfo.getColumnCount()); // always use one column
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetPositionOnTiles() {
|
||||
QSPanelControllerBase.TileRecord tileRecord1 = createTileRecord();
|
||||
QSPanelControllerBase.TileRecord tileRecord2 = createTileRecord();
|
||||
mTileLayout.addTile(tileRecord1);
|
||||
mTileLayout.addTile(tileRecord2);
|
||||
mTileLayout.measure(mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
|
||||
mTileLayout.layout(0, 0, mLayoutSizeForOneTile * 2, mLayoutSizeForOneTile * 2);
|
||||
|
||||
verify(tileRecord1.tileView).setPosition(0);
|
||||
verify(tileRecord2.tileView).setPosition(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import android.widget.TextView
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.R
|
||||
@@ -257,6 +258,28 @@ class QSTileViewImplTest : SysuiTestCase() {
|
||||
assertThat((tileView.secondaryLabel as TextView).text).isEqualTo(onString)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCollectionItemInfoHasPosition() {
|
||||
val position = 5
|
||||
tileView.setPosition(position)
|
||||
|
||||
val info = AccessibilityNodeInfo(tileView)
|
||||
tileView.onInitializeAccessibilityNodeInfo(info)
|
||||
|
||||
assertThat(info.collectionItemInfo.rowIndex).isEqualTo(position)
|
||||
assertThat(info.collectionItemInfo.rowSpan).isEqualTo(1)
|
||||
assertThat(info.collectionItemInfo.columnIndex).isEqualTo(0)
|
||||
assertThat(info.collectionItemInfo.columnSpan).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCollectionItemInfoNoPosition() {
|
||||
val info = AccessibilityNodeInfo(tileView)
|
||||
tileView.onInitializeAccessibilityNodeInfo(info)
|
||||
|
||||
assertThat(info.collectionItemInfo).isNull()
|
||||
}
|
||||
|
||||
class FakeTileView(
|
||||
context: Context,
|
||||
icon: QSIconView,
|
||||
|
||||
Reference in New Issue
Block a user