Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a680b13 authored by Andrew Cole's avatar Andrew Cole Committed by Android (Google) Code Review
Browse files

Merge "Test Week - AccessibleDragLstenerAdapterTest" into main

parents abc4a958 6ace1c0d
Loading
Loading
Loading
Loading
+0 −89
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.accessibility;

import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.OnHierarchyChangeListener;

import androidx.annotation.Nullable;

import com.android.launcher3.CellLayout;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Launcher;
import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragOptions;

import java.util.function.Function;

/**
 * Utility listener to enable/disable accessibility drag flags for a ViewGroup
 * containing CellLayouts
 */
public class AccessibleDragListenerAdapter implements DragListener, OnHierarchyChangeListener {

    private final ViewGroup mViewGroup;
    private final Function<CellLayout, DragAndDropAccessibilityDelegate> mDelegateFactory;

    /**
     * @param parent the viewgroup containing all the children
     * @param delegateFactory function to create no delegates
     */
    public AccessibleDragListenerAdapter(ViewGroup parent,
            Function<CellLayout, DragAndDropAccessibilityDelegate> delegateFactory) {
        mViewGroup = parent;
        mDelegateFactory = delegateFactory;
    }

    @Override
    public void onDragStart(DragObject dragObject, DragOptions options) {
        mViewGroup.setOnHierarchyChangeListener(this);
        enableAccessibleDrag(true, dragObject);
    }

    @Override
    public void onDragEnd() {
        mViewGroup.setOnHierarchyChangeListener(null);
        enableAccessibleDrag(false, null);
        Launcher.getLauncher(mViewGroup.getContext()).getDragController().removeDragListener(this);
    }


    @Override
    public void onChildViewAdded(View parent, View child) {
        if (parent == mViewGroup) {
            setEnableForLayout((CellLayout) child, true);
        }
    }

    @Override
    public void onChildViewRemoved(View parent, View child) {
        if (parent == mViewGroup) {
            setEnableForLayout((CellLayout) child, false);
        }
    }

    protected void enableAccessibleDrag(boolean enable, @Nullable DragObject dragObject) {
        for (int i = 0; i < mViewGroup.getChildCount(); i++) {
            setEnableForLayout((CellLayout) mViewGroup.getChildAt(i), enable);
        }
    }

    protected final void setEnableForLayout(CellLayout layout, boolean enable) {
        layout.setDragAndDropAccessibilityDelegate(enable ? mDelegateFactory.apply(layout) : null);
    }
}
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.accessibility

import android.view.View
import android.view.ViewGroup
import com.android.launcher3.CellLayout
import com.android.launcher3.DropTarget.DragObject
import com.android.launcher3.dragndrop.DragController
import com.android.launcher3.dragndrop.DragOptions
import com.android.launcher3.views.ActivityContext
import java.util.function.Function

/**
 * Utility listener to enable/disable accessibility drag flags for a ViewGroup containing
 * CellLayouts
 */
open class AccessibleDragListenerAdapter
/**
 * @param parent the viewgroup containing all the children
 * @param delegateFactory function to create no delegates
 */
(
    private val mViewGroup: ViewGroup,
    private val mDelegateFactory: Function<CellLayout, DragAndDropAccessibilityDelegate>
) : DragController.DragListener, ViewGroup.OnHierarchyChangeListener {
    override fun onDragStart(dragObject: DragObject, options: DragOptions) {
        mViewGroup.setOnHierarchyChangeListener(this)
        enableAccessibleDrag(true, dragObject)
    }

    override fun onDragEnd() {
        mViewGroup.setOnHierarchyChangeListener(null)
        enableAccessibleDrag(false, null)
        val activityContext = ActivityContext.lookupContext(mViewGroup.context) as ActivityContext
        activityContext.getDragController<DragController<*>>()?.removeDragListener(this)
    }

    override fun onChildViewAdded(parent: View, child: View) {
        if (parent === mViewGroup) {
            setEnableForLayout(child as CellLayout, true)
        }
    }

    override fun onChildViewRemoved(parent: View, child: View) {
        if (parent === mViewGroup) {
            setEnableForLayout(child as CellLayout, false)
        }
    }

    protected open fun enableAccessibleDrag(enable: Boolean, dragObject: DragObject?) {
        for (i in 0 until mViewGroup.childCount) {
            setEnableForLayout(mViewGroup.getChildAt(i) as CellLayout, enable)
        }
    }

    protected fun setEnableForLayout(layout: CellLayout, enable: Boolean) {
        layout.setDragAndDropAccessibilityDelegate(
            if (enable) mDelegateFactory.apply(layout) else null
        )
    }
}
+110 −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.accessibility

import android.content.Context
import android.view.ViewGroup
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.CellLayout
import com.android.launcher3.DropTarget.DragObject
import com.android.launcher3.dragndrop.DragOptions
import com.android.launcher3.util.ActivityContextWrapper
import java.util.function.Function
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.kotlin.any

@SmallTest
@RunWith(AndroidJUnit4::class)
class AccessibleDragListenerAdapterTest {

    private lateinit var mockViewGroup: ViewGroup
    private lateinit var mockChildOne: CellLayout
    private lateinit var mockChildTwo: CellLayout
    private lateinit var mDelegateFactory: Function<CellLayout, DragAndDropAccessibilityDelegate>
    private lateinit var adapter: AccessibleDragListenerAdapter
    private lateinit var mContext: Context

    @Before
    fun setup() {
        mContext = ActivityContextWrapper(getApplicationContext())
        mockViewGroup = mock(ViewGroup::class.java)
        mockChildOne = mock(CellLayout::class.java)
        mockChildTwo = mock(CellLayout::class.java)
        `when`(mockViewGroup.context).thenReturn(mContext)
        `when`(mockViewGroup.childCount).thenReturn(2)
        `when`(mockViewGroup.getChildAt(0)).thenReturn(mockChildOne)
        `when`(mockViewGroup.getChildAt(1)).thenReturn(mockChildTwo)
        // Mock Delegate factory
        mDelegateFactory =
            mock(Function::class.java) as Function<CellLayout, DragAndDropAccessibilityDelegate>
        `when`(mDelegateFactory.apply(any()))
            .thenReturn(mock(DragAndDropAccessibilityDelegate::class.java))
        adapter = AccessibleDragListenerAdapter(mockViewGroup, mDelegateFactory)
    }

    @Test
    fun `onDragStart enables accessible drag for all view children`() {
        // Create mock view children
        val mockDragObject = mock(DragObject::class.java)
        val mockDragOptions = mock(DragOptions::class.java)

        // Action
        adapter.onDragStart(mockDragObject, mockDragOptions)

        // Assertion
        verify(mockChildOne).setDragAndDropAccessibilityDelegate(any())
        verify(mockChildTwo).setDragAndDropAccessibilityDelegate(any())
    }

    @Test
    fun `onDragEnd removes the accessibility delegate`() {
        // Action
        adapter = AccessibleDragListenerAdapter(mockViewGroup, mDelegateFactory)
        adapter.onDragEnd()

        // Assertion
        verify(mockChildOne).setDragAndDropAccessibilityDelegate(null)
        verify(mockChildTwo).setDragAndDropAccessibilityDelegate(null)
    }

    @Test
    fun `onChildViewAdded sets enabled as true for childview`() {
        // Action
        adapter = AccessibleDragListenerAdapter(mockViewGroup, mDelegateFactory)
        adapter.onChildViewAdded(mockViewGroup, mockChildOne)

        // Assertion
        verify(mockChildOne).setDragAndDropAccessibilityDelegate(any())
    }

    @Test
    fun `onChildViewRemoved sets enabled as false for childview`() {
        // Action
        adapter = AccessibleDragListenerAdapter(mockViewGroup, mDelegateFactory)
        adapter.onChildViewRemoved(mockViewGroup, mockChildOne)

        // Assertion
        verify(mockChildOne).setDragAndDropAccessibilityDelegate(null)
    }
}