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

Commit 6f4aa084 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: Iba089698d81baa480b6cc8e7d567cef92b99998b
parents 7182ca55 5a3a7c39
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -162,10 +162,10 @@ internal class BubbleDataRepository @Inject constructor(
        }
        }
        uiScope.launch { cb(bubbles) }
        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 TAG = "BubbleDataRepository"
private const val DEBUG = false
private const val DEBUG = false
private const val SHORTCUT_QUERY_FLAG =
private const val SHORTCUT_QUERY_FLAG =
+39 −8
Original line number Original line Diff line number Diff line
@@ -15,6 +15,10 @@
 */
 */
package com.android.systemui.bubbles.storage
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.Inject
import javax.inject.Singleton
import javax.inject.Singleton


@@ -25,11 +29,19 @@ private const val CAPACITY = 16
 * manipulation.
 * manipulation.
 */
 */
@Singleton
@Singleton
class BubbleVolatileRepository @Inject constructor() {
class BubbleVolatileRepository @Inject constructor(
    private val launcherApps: LauncherApps
) {
    /**
    /**
     * An ordered set of bubbles based on their natural ordering.
     * 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.
     * Returns a snapshot of all the bubbles.
@@ -45,15 +57,34 @@ class BubbleVolatileRepository @Inject constructor() {
    @Synchronized
    @Synchronized
    fun addBubbles(bubbles: List<BubbleEntity>) {
    fun addBubbles(bubbles: List<BubbleEntity>) {
        if (bubbles.isEmpty()) return
        if (bubbles.isEmpty()) return
        bubbles.forEach { entities.remove(it) }
        // Verify the size of given bubbles is within capacity, otherwise trim down to capacity
        if (entities.size + bubbles.size >= CAPACITY) {
        val bubblesInRange = bubbles.takeLast(capacity)
            entities.drop(entities.size + bubbles.size - 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
    @Synchronized
    fun removeBubbles(bubbles: List<BubbleEntity>) {
    fun removeBubbles(bubbles: List<BubbleEntity>) = uncache(bubbles.filter { entities.remove(it) })
        bubbles.forEach { 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 Original line Diff line number Diff line
@@ -16,37 +16,92 @@


package com.android.systemui.bubbles.storage
package com.android.systemui.bubbles.storage


import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions


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


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

    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 val bubbles = listOf(bubble1, bubble2, bubble3)


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


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


    @Test
    @Test
    fun testAddAndRemoveBubbles() {
    fun testAddBubbles() {
        repository.addBubbles(bubbles)
        repository.addBubbles(bubbles)
        assertEquals(bubbles, repository.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))
        repository.addBubbles(listOf(bubble1))
        assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
        assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
        verifyNoMoreInteractions(launcherApps)
    }

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

        repository.removeBubbles(listOf(bubble3))
        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"