diff options
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java | 7 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt | 73 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt) | 2 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt | 4 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt | 8 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt | 12 |
6 files changed, 83 insertions, 23 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 0dbee663c1c9..f1b401e77fbc 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -102,6 +102,13 @@ class Bubble implements BubbleViewProvider { return user.getIdentifier() + "|" + entry.getSbn().getPackageName(); } + // TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble + Bubble(ShortcutInfo shortcutInfo) { + mShortcutInfo = shortcutInfo; + mKey = shortcutInfo.getId(); + mGroupId = shortcutInfo.getId(); + } + /** Used in tests when no UI is required. */ @VisibleForTesting(visibility = PRIVATE) Bubble(NotificationEntry e, diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt index b9825e1d21e5..ba93f4125ea5 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt @@ -15,24 +15,32 @@ */ package com.android.systemui.bubbles +import android.annotation.SuppressLint import android.annotation.UserIdInt +import android.content.pm.LauncherApps +import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC +import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER +import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED +import android.os.UserHandle import android.util.Log +import com.android.systemui.bubbles.storage.BubbleEntity import com.android.systemui.bubbles.storage.BubblePersistentRepository import com.android.systemui.bubbles.storage.BubbleVolatileRepository -import com.android.systemui.bubbles.storage.BubbleXmlEntity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.launch import kotlinx.coroutines.yield + import javax.inject.Inject import javax.inject.Singleton @Singleton internal class BubbleDataRepository @Inject constructor( private val volatileRepository: BubbleVolatileRepository, - private val persistentRepository: BubblePersistentRepository + private val persistentRepository: BubblePersistentRepository, + private val launcherApps: LauncherApps ) { private val ioScope = CoroutineScope(Dispatchers.IO) @@ -64,10 +72,10 @@ internal class BubbleDataRepository @Inject constructor( if (entities.isNotEmpty()) persistToDisk() } - private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleXmlEntity> { + private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> { return bubbles.mapNotNull { b -> val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null - BubbleXmlEntity(userId, b.packageName, shortcutId) + BubbleEntity(userId, b.packageName, shortcutId) } } @@ -100,15 +108,60 @@ internal class BubbleDataRepository @Inject constructor( /** * Load bubbles from disk. */ + // TODO: call this method from BubbleController and update UI + @SuppressLint("WrongConstant") fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch { - val bubbleXmlEntities = persistentRepository.readFromDisk() - volatileRepository.addBubbles(bubbleXmlEntities) - uiScope.launch { - // TODO: transform bubbleXmlEntities into bubbles - // cb(bubbles) - } + /** + * Load BubbleEntity from disk. + * e.g. + * [ + * BubbleEntity(0, "com.example.messenger", "id-2"), + * BubbleEntity(10, "com.example.chat", "my-id1") + * BubbleEntity(0, "com.example.messenger", "id-1") + * ] + */ + val entities = persistentRepository.readFromDisk() + volatileRepository.addBubbles(entities) + /** + * Extract userId/packageName from these entities. + * e.g. + * [ + * ShortcutKey(0, "com.example.messenger"), ShortcutKey(0, "com.example.chat") + * ] + */ + val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet() + /** + * Retrieve shortcuts with given userId/packageName combination, then construct a mapping + * between BubbleEntity and ShortcutInfo. + * e.g. + * { + * BubbleEntity(0, "com.example.messenger", "id-0") -> + * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-0"), + * BubbleEntity(0, "com.example.messenger", "id-2") -> + * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2"), + * BubbleEntity(10, "com.example.chat", "id-1") -> + * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-1"), + * BubbleEntity(10, "com.example.chat", "id-3") -> + * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-3") + * } + */ + val shortcutMap = shortcutKeys.flatMap { key -> + launcherApps.getShortcuts( + LauncherApps.ShortcutQuery() + .setPackage(key.pkg) + .setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId)) + ?.map { BubbleEntity(key.userId, key.pkg, it.id) to it } ?: emptyList() + }.toMap() + // For each entity loaded from xml, find the corresponding ShortcutInfo then convert them + // into Bubble. + val bubbles = entities.mapNotNull { entity -> shortcutMap[entity]?.let { Bubble(it) } } + uiScope.launch { cb(bubbles) } } + + private 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 = + FLAG_MATCH_DYNAMIC or FLAG_MATCH_PINNED_BY_ANY_LAUNCHER or FLAG_MATCH_CACHED
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt index d0f76077cd51..4690a8e14072 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlEntity.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt @@ -17,7 +17,7 @@ package com.android.systemui.bubbles.storage import android.annotation.UserIdInt -data class BubbleXmlEntity( +data class BubbleEntity( @UserIdInt val userId: Int, val packageName: String, val shortcutId: String diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt index 149e2c4c4022..7c3271e4b76c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt @@ -32,7 +32,7 @@ class BubblePersistentRepository @Inject constructor( private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir, "overflow_bubbles.xml"), "overflow-bubbles") - fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean { + fun persistsToDisk(bubbles: List<BubbleEntity>): Boolean { if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles") synchronized(bubbleFile) { val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) { @@ -52,7 +52,7 @@ class BubblePersistentRepository @Inject constructor( return false } - fun readFromDisk(): List<BubbleXmlEntity> { + fun readFromDisk(): List<BubbleEntity> { synchronized(bubbleFile) { try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) { Log.e(TAG, "Failed to open bubble file", e) diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt index e1f675b83583..d1eee2f69b63 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt @@ -29,12 +29,12 @@ class BubbleVolatileRepository @Inject constructor() { /** * An ordered set of bubbles based on their natural ordering. */ - private val entities = mutableSetOf<BubbleXmlEntity>() + private val entities = mutableSetOf<BubbleEntity>() /** * Returns a snapshot of all the bubbles. */ - val bubbles: List<BubbleXmlEntity> + val bubbles: List<BubbleEntity> @Synchronized get() = entities.toList() @@ -43,7 +43,7 @@ class BubbleVolatileRepository @Inject constructor() { * it will be moved to the last. */ @Synchronized - fun addBubbles(bubbles: List<BubbleXmlEntity>) { + fun addBubbles(bubbles: List<BubbleEntity>) { if (bubbles.isEmpty()) return bubbles.forEach { entities.remove(it) } if (entities.size + bubbles.size >= CAPACITY) { @@ -53,7 +53,7 @@ class BubbleVolatileRepository @Inject constructor() { } @Synchronized - fun removeBubbles(bubbles: List<BubbleXmlEntity>) { + fun removeBubbles(bubbles: List<BubbleEntity>) { bubbles.forEach { entities.remove(it) } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt index 1e91653c6db7..821b64ce5e6e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt @@ -35,7 +35,7 @@ private const val ATTR_SHORTCUT_ID = "sid" * Writes the bubbles in xml format into given output stream. */ @Throws(IOException::class) -fun writeXml(stream: OutputStream, bubbles: List<BubbleXmlEntity>) { +fun writeXml(stream: OutputStream, bubbles: List<BubbleEntity>) { val serializer: XmlSerializer = FastXmlSerializer() serializer.setOutput(stream, StandardCharsets.UTF_8.name()) serializer.startDocument(null, true) @@ -51,7 +51,7 @@ fun writeXml(stream: OutputStream, bubbles: List<BubbleXmlEntity>) { * <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" /> * ``` */ -private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) { +private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) { try { serializer.startTag(null, TAG_BUBBLE) serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString()) @@ -66,8 +66,8 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) { /** * Reads the bubbles from xml file. */ -fun readXml(stream: InputStream): List<BubbleXmlEntity> { - val bubbles = mutableListOf<BubbleXmlEntity>() +fun readXml(stream: InputStream): List<BubbleEntity> { + val bubbles = mutableListOf<BubbleEntity>() val parser: XmlPullParser = Xml.newPullParser() parser.setInput(stream, StandardCharsets.UTF_8.name()) XmlUtils.beginDocument(parser, TAG_BUBBLES) @@ -78,9 +78,9 @@ fun readXml(stream: InputStream): List<BubbleXmlEntity> { return bubbles } -private fun readXmlEntry(parser: XmlPullParser): BubbleXmlEntity? { +private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? { while (parser.eventType != XmlPullParser.START_TAG) { parser.next() } - return BubbleXmlEntity( + return BubbleEntity( parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_PACKAGE) ?: return null, parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null |