Loading res/layout/widgets_list_row_header_two_pane.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ android:importantForAccessibility="yes" android:focusable="true" launcher:appIconSize="48dp" launcher:collapsable="false" android:descendantFocusability="afterDescendants" android:background="@drawable/bg_widgets_header_two_pane" > Loading res/values/attrs.xml +1 −0 Original line number Diff line number Diff line Loading @@ -582,6 +582,7 @@ <declare-styleable name="WidgetsListRowHeader"> <attr name="appIconSize" format="dimension" /> <attr name="collapsable" format="boolean" /> </declare-styleable> <attr name="materialColorOnSecondaryFixedVariant" format="color" /> Loading src/com/android/launcher3/widget/picker/WidgetsListHeader.java +33 −24 Original line number Diff line number Diff line Loading @@ -52,7 +52,11 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd private static final int[] EXPANDED_DRAWABLE_STATE = new int[] {android.R.attr.state_expanded}; private final int mIconSize; /** * Indicates if the header is collapsable. For example, when displayed in a two pane layout, * widget apps aren't collapsable. */ private final boolean mIsCollapsable; @Nullable private HandlerRunnable mIconLoadRequest; @Nullable private Drawable mIconDrawable; @Nullable private WidgetsListDrawableState mListDrawableState; Loading @@ -79,6 +83,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0); mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize, grid.iconSizePx); mIsCollapsable = a.getBoolean(R.styleable.WidgetsListRowHeader_collapsable, true); } @Override Loading @@ -87,10 +92,13 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd mAppIcon = findViewById(R.id.app_icon); mTitle = findViewById(R.id.app_title); mSubtitle = findViewById(R.id.app_subtitle); // Lists that cannot collapse, don't need EXPAND or COLLAPSE accessibility actions. if (mIsCollapsable) { setAccessibilityDelegate(new AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { if (mIsExpanded) { info.removeAction(AccessibilityNodeInfo.ACTION_EXPAND); info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE); Loading @@ -114,6 +122,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd } }); } } /** Sets the expand toggle to expand / collapse. */ @UiThread Loading tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderAccessibilityTest.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.launcher3.widget.picker; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.launcher3.R; import com.android.launcher3.util.ActivityContextWrapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidJUnit4.class) public class WidgetsListHeaderAccessibilityTest { private Context mContext; private LayoutInflater mLayoutInflater; @Mock private View.OnClickListener mOnClickListener; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = new ActivityContextWrapper(getApplicationContext()); mLayoutInflater = LayoutInflater.from( new ContextThemeWrapper(mContext, R.style.WidgetContainerTheme)); } @Test public void singlePaneCollapsable_hasCustomAccessibilityActions() { WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate( R.layout.widgets_list_row_header, new FrameLayout(mContext), false); assertThat(header.getAccessibilityDelegate()).isNotNull(); header.setOnClickListener(mOnClickListener); header.getAccessibilityDelegate().performAccessibilityAction(header, AccessibilityNodeInfo.ACTION_EXPAND, null); header.getAccessibilityDelegate().performAccessibilityAction(header, AccessibilityNodeInfo.ACTION_COLLAPSE, null); verify(mOnClickListener, times(2)).onClick(header); } @Test public void twoPaneNonCollapsable_noCustomAccessibilityDelegate() { WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate( R.layout.widgets_list_row_header_two_pane, new FrameLayout(mContext), false); assertThat(header.getAccessibilityDelegate()).isNull(); } } Loading
res/layout/widgets_list_row_header_two_pane.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ android:importantForAccessibility="yes" android:focusable="true" launcher:appIconSize="48dp" launcher:collapsable="false" android:descendantFocusability="afterDescendants" android:background="@drawable/bg_widgets_header_two_pane" > Loading
res/values/attrs.xml +1 −0 Original line number Diff line number Diff line Loading @@ -582,6 +582,7 @@ <declare-styleable name="WidgetsListRowHeader"> <attr name="appIconSize" format="dimension" /> <attr name="collapsable" format="boolean" /> </declare-styleable> <attr name="materialColorOnSecondaryFixedVariant" format="color" /> Loading
src/com/android/launcher3/widget/picker/WidgetsListHeader.java +33 −24 Original line number Diff line number Diff line Loading @@ -52,7 +52,11 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd private static final int[] EXPANDED_DRAWABLE_STATE = new int[] {android.R.attr.state_expanded}; private final int mIconSize; /** * Indicates if the header is collapsable. For example, when displayed in a two pane layout, * widget apps aren't collapsable. */ private final boolean mIsCollapsable; @Nullable private HandlerRunnable mIconLoadRequest; @Nullable private Drawable mIconDrawable; @Nullable private WidgetsListDrawableState mListDrawableState; Loading @@ -79,6 +83,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0); mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize, grid.iconSizePx); mIsCollapsable = a.getBoolean(R.styleable.WidgetsListRowHeader_collapsable, true); } @Override Loading @@ -87,10 +92,13 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd mAppIcon = findViewById(R.id.app_icon); mTitle = findViewById(R.id.app_title); mSubtitle = findViewById(R.id.app_subtitle); // Lists that cannot collapse, don't need EXPAND or COLLAPSE accessibility actions. if (mIsCollapsable) { setAccessibilityDelegate(new AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { if (mIsExpanded) { info.removeAction(AccessibilityNodeInfo.ACTION_EXPAND); info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE); Loading @@ -114,6 +122,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd } }); } } /** Sets the expand toggle to expand / collapse. */ @UiThread Loading
tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderAccessibilityTest.java 0 → 100644 +87 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.launcher3.widget.picker; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.launcher3.R; import com.android.launcher3.util.ActivityContextWrapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidJUnit4.class) public class WidgetsListHeaderAccessibilityTest { private Context mContext; private LayoutInflater mLayoutInflater; @Mock private View.OnClickListener mOnClickListener; @Before public void setUp() { MockitoAnnotations.initMocks(this); mContext = new ActivityContextWrapper(getApplicationContext()); mLayoutInflater = LayoutInflater.from( new ContextThemeWrapper(mContext, R.style.WidgetContainerTheme)); } @Test public void singlePaneCollapsable_hasCustomAccessibilityActions() { WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate( R.layout.widgets_list_row_header, new FrameLayout(mContext), false); assertThat(header.getAccessibilityDelegate()).isNotNull(); header.setOnClickListener(mOnClickListener); header.getAccessibilityDelegate().performAccessibilityAction(header, AccessibilityNodeInfo.ACTION_EXPAND, null); header.getAccessibilityDelegate().performAccessibilityAction(header, AccessibilityNodeInfo.ACTION_COLLAPSE, null); verify(mOnClickListener, times(2)).onClick(header); } @Test public void twoPaneNonCollapsable_noCustomAccessibilityDelegate() { WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate( R.layout.widgets_list_row_header_two_pane, new FrameLayout(mContext), false); assertThat(header.getAccessibilityDelegate()).isNull(); } }