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

Commit 50051adc authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert AllAppsRecyclerViewPoolTest.kt" into main

parents f3a85e17 6554ab99
Loading
Loading
Loading
Loading
+10 −36
Original line number Diff line number Diff line
@@ -18,9 +18,6 @@ package com.android.launcher3.recyclerview

import android.content.Context
import android.util.Log
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.Companion.PROTECTED
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.RecycledViewPool
import androidx.recyclerview.widget.RecyclerView.ViewHolder
@@ -34,7 +31,6 @@ import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.ActivityContext.ActivityContextDelegate
import java.lang.IllegalStateException

const val PREINFLATE_ICONS_ROW_COUNT = 4
const val EXTRA_ICONS_COUNT = 2
@@ -44,11 +40,10 @@ const val EXTRA_ICONS_COUNT = 2
 * [RecyclerView]. The view inflation will happen on background thread and inflated [ViewHolder]s
 * will be added to [RecycledViewPool] on main thread.
 */
class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : ActivityContext {
class AllAppsRecyclerViewPool<T> : RecycledViewPool() {

    var hasWorkProfile = false
    @VisibleForTesting(otherwise = PROTECTED)
    var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
    private var mCancellableTask: CancellableTask<List<ViewHolder>>? = null

    companion object {
        private const val TAG = "AllAppsRecyclerViewPool"
@@ -59,7 +54,7 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : Act
    /**
     * Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
     */
    fun preInflateAllAppsViewHolders(context: T) {
    fun <T> preInflateAllAppsViewHolders(context: T) where T : Context, T : ActivityContext {
        val appsView = context.appsView ?: return
        val activeRv: RecyclerView = appsView.activeRecyclerView ?: return
        val preInflateCount = getPreinflateCount(context)
@@ -103,52 +98,31 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : Act
                override fun getLayoutManager(): RecyclerView.LayoutManager? = null
            }

        preInflateAllAppsViewHolders(
            adapter,
            BaseAllAppsAdapter.VIEW_TYPE_ICON,
            activeRv,
            preInflateCount
        ) {
            getPreinflateCount(context)
        }
    }

    @VisibleForTesting(otherwise = PROTECTED)
    fun preInflateAllAppsViewHolders(
        adapter: RecyclerView.Adapter<*>,
        viewType: Int,
        parent: ViewGroup,
        preInflationCount: Int,
        preInflationCountProvider: () -> Int
    ) {
        if (preInflationCount <= 0) {
            return
        }
        mCancellableTask?.cancel()
        var task: CancellableTask<List<ViewHolder>>? = null
        task =
            CancellableTask(
                {
                    val list: ArrayList<ViewHolder> = ArrayList()
                    for (i in 0 until preInflationCount) {
                    for (i in 0 until preInflateCount) {
                        if (task?.canceled == true) {
                            break
                        }
                        list.add(adapter.createViewHolder(parent, viewType))
                        list.add(
                            adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
                        )
                    }
                    list
                },
                MAIN_EXECUTOR,
                { viewHolders ->
                    // Run preInflationCountProvider again as the needed VH might have changed
                    val newPreInflationCount = preInflationCountProvider.invoke()
                    for (i in 0 until minOf(viewHolders.size, newPreInflationCount)) {
                    for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
                        putRecycledView(viewHolders[i])
                    }
                }
            )
        mCancellableTask = task
        VIEW_PREINFLATION_EXECUTOR.execute(mCancellableTask)
        VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
    }

    /**
@@ -169,7 +143,7 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() where T : Context, T : Act
     * app icons in size of one all apps pages, so that opening all apps don't need to inflate app
     * icons.
     */
    fun getPreinflateCount(context: T): Int {
    fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext {
        var targetPreinflateCount =
            PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns +
                EXTRA_ICONS_COUNT
+0 −116
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.recyclerview

import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.util.Executors
import com.android.launcher3.views.ActivityContext
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.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(AndroidJUnit4::class)
class AllAppsRecyclerViewPoolTest<T> where T : Context, T : ActivityContext {

    private lateinit var underTest: AllAppsRecyclerViewPool<T>
    private lateinit var adapter: RecyclerView.Adapter<*>

    @Mock private lateinit var parent: ViewGroup
    @Mock private lateinit var itemView: View

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        underTest = spy(AllAppsRecyclerViewPool())
        adapter =
            object : RecyclerView.Adapter<ViewHolder>() {
                override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
                    object : ViewHolder(itemView) {}

                override fun getItemCount() = 0

                override fun onBindViewHolder(holder: ViewHolder, position: Int) {}
            }
        underTest.setMaxRecycledViews(VIEW_TYPE, 20)
    }

    @Test
    fun preinflate_success() {
        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }

        awaitTasksCompleted()
        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(10)
    }

    @Test
    fun preinflate_not_triggered() {
        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 0) { 0 }

        awaitTasksCompleted()
        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
    }

    @Test
    fun preinflate_cancel_before_runOnMainThread() {
        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }
        assertThat(underTest.mCancellableTask!!.canceled).isFalse()

        underTest.clear()

        awaitTasksCompleted()
        verify(underTest, never()).putRecycledView(any(ViewHolder::class.java))
        assertThat(underTest.mCancellableTask!!.canceled).isTrue()
        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
    }

    @Test
    fun preinflate_cancel_after_run() {
        underTest.preInflateAllAppsViewHolders(adapter, VIEW_TYPE, parent, 10) { 10 }
        assertThat(underTest.mCancellableTask!!.canceled).isFalse()
        awaitTasksCompleted()

        underTest.clear()

        verify(underTest, times(10)).putRecycledView(any(ViewHolder::class.java))
        assertThat(underTest.mCancellableTask!!.canceled).isTrue()
        assertThat(underTest.getRecycledViewCount(VIEW_TYPE)).isEqualTo(0)
    }

    private fun awaitTasksCompleted() {
        Executors.VIEW_PREINFLATION_EXECUTOR.submit<Any> { null }.get()
        Executors.MAIN_EXECUTOR.submit<Any> { null }.get()
    }

    companion object {
        private const val VIEW_TYPE: Int = 4
    }
}