Merge "Add better a11y support in QS" into tm-dev
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 75d95e6..f78046d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -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 @@
String ACTION = "com.android.systemui.action.PLUGIN_QS";
- int VERSION = 13;
+ int VERSION = 14;
String TAG = "QS";
@@ -68,7 +67,12 @@
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
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 9a9683d..a8999ff 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -26,7 +26,7 @@
@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 View getSecondaryLabel() {
return null;
}
+
+ /** Sets the index of this tile in its layout */
+ public abstract void setPosition(int position);
}
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 02c58e4..77523ec9 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -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"/>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index d20141b..34f771c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -15,6 +15,7 @@
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 @@
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);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index aac5672..bcf60d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -48,10 +48,5 @@
*/
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) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 6c0ca49..61905ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -23,13 +23,11 @@
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 @@
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;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index bef4f43..0d29a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -114,12 +114,6 @@
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);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index b5e1c5e..795a606 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -31,7 +31,6 @@
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 @@
}
@Override
- public void setExpandClickListener(OnClickListener onClickListener) {
- mFooter.setExpandClickListener(onClickListener);
+ public void setCollapseExpandAction(Runnable action) {
+ mQSPanelController.setCollapseExpandAction(action);
+ mQuickQSPanelController.setCollapseExpandAction(action);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 11a36ad..8c4dedc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -34,6 +34,7 @@
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 @@
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 @@
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;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 74d1a3d..9c8fc47 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -424,6 +424,14 @@
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;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f5ae019..3c95da8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -20,6 +20,7 @@
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 @@
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;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index da82d2c..9ef90ec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -8,6 +8,7 @@
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 @@
} else {
record.tileView.setLeftTopRightBottom(left, top, right, bottom);
}
+ record.tileView.setPosition(i);
mLastTileBottom = bottom;
}
}
@@ -296,4 +298,11 @@
}
}
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
+ info.setCollectionInfo(
+ new AccessibilityNodeInfo.CollectionInfo(mRecords.size(), 1, false));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index a712ce2..72dad06 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -69,6 +69,12 @@
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 @@
}
}
}
+ if (_position != INVALID) {
+ info.collectionItemInfo =
+ AccessibilityNodeInfo.CollectionItemInfo(_position, 1, 0, 1, false)
+ }
}
override fun toString(): String {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 20fc39d..6007323 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -239,7 +239,7 @@
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 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 @@
}
}
- 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 */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 63f8641..829445e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -23,6 +23,7 @@
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 @@
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);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 04bbd60..ba02a82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -21,24 +21,19 @@
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 @@
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 @@
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 @@
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 @@
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 }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
new file mode 100644
index 0000000..60c2bde
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
@@ -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()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index bd4bfff..5abc0e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -28,6 +28,7 @@
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 @@
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);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index a2b5013..9fdc2fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -23,6 +23,7 @@
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 @@
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,