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

Commit 1381c19b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "cache/uncache ShortcutInfo associated with the bubbles" into rvc-dev am: 5a3a7c39

Change-Id: Ia9c7640f1dd89af7cb419dde985e1531a1f1ab62
parents d4f0e485 5a3a7c39
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -162,10 +162,10 @@ internal class BubbleDataRepository @Inject constructor(
        }
        uiScope.launch { cb(bubbles) }
    }

    private data class ShortcutKey(val userId: Int, val pkg: String)
}

data class ShortcutKey(val userId: Int, val pkg: String)

private const val TAG = "BubbleDataRepository"
private const val DEBUG = false
private const val SHORTCUT_QUERY_FLAG =
+39 −8
Original line number Diff line number Diff line
@@ -15,6 +15,10 @@
 */
package com.android.systemui.bubbles.storage

import android.content.pm.LauncherApps
import android.os.UserHandle
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.bubbles.ShortcutKey
import javax.inject.Inject
import javax.inject.Singleton

@@ -25,11 +29,19 @@ private const val CAPACITY = 16
 * manipulation.
 */
@Singleton
class BubbleVolatileRepository @Inject constructor() {
class BubbleVolatileRepository @Inject constructor(
    private val launcherApps: LauncherApps
) {
    /**
     * An ordered set of bubbles based on their natural ordering.
     */
    private val entities = mutableSetOf<BubbleEntity>()
    private var entities = mutableSetOf<BubbleEntity>()

    /**
     * The capacity of the cache.
     */
    @VisibleForTesting
    var capacity = CAPACITY

    /**
     * Returns a snapshot of all the bubbles.
@@ -45,15 +57,34 @@ class BubbleVolatileRepository @Inject constructor() {
    @Synchronized
    fun addBubbles(bubbles: List<BubbleEntity>) {
        if (bubbles.isEmpty()) return
        bubbles.forEach { entities.remove(it) }
        if (entities.size + bubbles.size >= CAPACITY) {
            entities.drop(entities.size + bubbles.size - CAPACITY)
        // Verify the size of given bubbles is within capacity, otherwise trim down to capacity
        val bubblesInRange = bubbles.takeLast(capacity)
        // To ensure natural ordering of the bubbles, removes bubbles which already exist
        val uniqueBubbles = bubblesInRange.filterNot { entities.remove(it) }
        val overflowCount = entities.size + bubblesInRange.size - capacity
        if (overflowCount > 0) {
            // Uncache ShortcutInfo of bubbles that will be removed due to capacity
            uncache(entities.take(overflowCount))
            entities = entities.drop(overflowCount).toMutableSet()
        }
        entities.addAll(bubbles)
        entities.addAll(bubblesInRange)
        cache(uniqueBubbles)
    }

    @Synchronized
    fun removeBubbles(bubbles: List<BubbleEntity>) {
        bubbles.forEach { entities.remove(it) }
    fun removeBubbles(bubbles: List<BubbleEntity>) = uncache(bubbles.filter { entities.remove(it) })

    private fun cache(bubbles: List<BubbleEntity>) {
        bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) ->
            launcherApps.cacheShortcuts(key.pkg, bubbles.map { it.shortcutId },
                    UserHandle.of(key.userId), LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)
        }
    }

    private fun uncache(bubbles: List<BubbleEntity>) {
        bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) ->
            launcherApps.uncacheShortcuts(key.pkg, bubbles.map { it.shortcutId },
                    UserHandle.of(key.userId), LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)
        }
    }
}
+62 −7
Original line number Diff line number Diff line
@@ -16,37 +16,92 @@

package com.android.systemui.bubbles.storage

import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
import junit.framework.Assert.assertEquals
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.verifyNoMoreInteractions

@SmallTest
@RunWith(AndroidTestingRunner::class)
class BubbleVolatileRepositoryTest : SysuiTestCase() {

    private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1")
    private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob", "k2")
    private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3")
    private val user0 = UserHandle.of(0)
    private val user10 = UserHandle.of(10)

    private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1")
    private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2")
    private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3")

    private val bubbles = listOf(bubble1, bubble2, bubble3)

    private lateinit var repository: BubbleVolatileRepository
    private lateinit var launcherApps: LauncherApps

    @Before
    fun setup() {
        repository = BubbleVolatileRepository()
        launcherApps = mock(LauncherApps::class.java)
        repository = BubbleVolatileRepository(launcherApps)
    }

    @Test
    fun testAddAndRemoveBubbles() {
    fun testAddBubbles() {
        repository.addBubbles(bubbles)
        assertEquals(bubbles, repository.bubbles)
        verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER),
                eq(listOf("shortcut-1", "shortcut-2")), eq(user0),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
        verify(launcherApps).cacheShortcuts(eq(PKG_CHAT),
                eq(listOf("alice and bob")), eq(user10),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))

        repository.addBubbles(listOf(bubble1))
        assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
        verifyNoMoreInteractions(launcherApps)
    }

    @Test
    fun testRemoveBubbles() {
        repository.addBubbles(bubbles)
        assertEquals(bubbles, repository.bubbles)

        repository.removeBubbles(listOf(bubble3))
        assertEquals(listOf(bubble2, bubble1), repository.bubbles)
        assertEquals(listOf(bubble1, bubble2), repository.bubbles)
        verify(launcherApps).uncacheShortcuts(eq(PKG_MESSENGER),
                eq(listOf("shortcut-2")), eq(user0),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
    }

    @Test
    fun testAddAndRemoveBubblesWhenExceedingCapacity() {
        repository.capacity = 2
        // push bubbles beyond capacity
        repository.addBubbles(bubbles)
        // verify it is trim down to capacity
        assertEquals(listOf(bubble2, bubble3), repository.bubbles)
        verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER),
                eq(listOf("shortcut-2")), eq(user0),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
        verify(launcherApps).cacheShortcuts(eq(PKG_CHAT),
                eq(listOf("alice and bob")), eq(user10),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))

        repository.addBubbles(listOf(bubble1))
        // verify the oldest bubble is popped
        assertEquals(listOf(bubble3, bubble1), repository.bubbles)
        verify(launcherApps).uncacheShortcuts(eq(PKG_CHAT),
                eq(listOf("alice and bob")), eq(user10),
                eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
    }
}

private const val PKG_MESSENGER = "com.example.messenger"
private const val PKG_CHAT = "com.example.chat"