Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt +34 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.bubbles import android.annotation.UserIdInt import android.util.Log import com.android.systemui.bubbles.storage.BubblePersistentRepository import com.android.systemui.bubbles.storage.BubbleVolatileRepository import com.android.systemui.bubbles.storage.BubbleXmlEntity Loading @@ -35,36 +36,39 @@ internal class BubbleDataRepository @Inject constructor( ) { private val ioScope = CoroutineScope(Dispatchers.IO) private val uiScope = CoroutineScope(Dispatchers.Main) private var job: Job? = null /** * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk * asynchronously. */ fun addBubble(@UserIdInt userId: Int, bubble: Bubble) { volatileRepository.addBubble( BubbleXmlEntity(userId, bubble.packageName, bubble.shortcutInfo?.id ?: return)) persistToDisk() } fun addBubble(@UserIdInt userId: Int, bubble: Bubble) = addBubbles(userId, listOf(bubble)) /** * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk * asynchronously. */ fun addBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) { volatileRepository.addBubbles(bubbles.mapNotNull { val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, it.packageName, shortcutId) }) persistToDisk() if (DEBUG) Log.d(TAG, "adding ${bubbles.size} bubbles") val entities = transform(userId, bubbles).also(volatileRepository::addBubbles) if (entities.isNotEmpty()) persistToDisk() } /** * Removes the bubbles from memory, then persists the snapshot to disk asynchronously. */ fun removeBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) { volatileRepository.removeBubbles(bubbles.mapNotNull { val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, it.packageName, shortcutId) }) persistToDisk() if (DEBUG) Log.d(TAG, "removing ${bubbles.size} bubbles") val entities = transform(userId, bubbles).also(volatileRepository::removeBubbles) if (entities.isNotEmpty()) persistToDisk() } private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleXmlEntity> { return bubbles.mapNotNull { b -> val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, b.packageName, shortcutId) } } /** Loading Loading @@ -92,4 +96,19 @@ internal class BubbleDataRepository @Inject constructor( persistentRepository.persistsToDisk(volatileRepository.bubbles) } } /** * Load bubbles from disk. */ fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch { val bubbleXmlEntities = persistentRepository.readFromDisk() volatileRepository.addBubbles(bubbleXmlEntities) uiScope.launch { // TODO: transform bubbleXmlEntities into bubbles // cb(bubbles) } } } private const val TAG = "BubbleDataRepository" private const val DEBUG = false packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt +12 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ class BubblePersistentRepository @Inject constructor( "overflow_bubbles.xml"), "overflow-bubbles") fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean { if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles") synchronized(bubbleFile) { val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) { Log.e(TAG, "Failed to save bubble file", e) Loading @@ -41,6 +42,7 @@ class BubblePersistentRepository @Inject constructor( try { writeXml(stream, bubbles) bubbleFile.finishWrite(stream) if (DEBUG) Log.d(TAG, "persisted ${bubbles.size} bubbles") return true } catch (e: Exception) { Log.e(TAG, "Failed to save bubble file, restoring backup", e) Loading @@ -49,6 +51,16 @@ class BubblePersistentRepository @Inject constructor( } return false } fun readFromDisk(): List<BubbleXmlEntity> { synchronized(bubbleFile) { try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) { Log.e(TAG, "Failed to open bubble file", e) } return emptyList() } } } private const val TAG = "BubblePersistentRepository" private const val DEBUG = false packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt +1 −7 Original line number Diff line number Diff line Loading @@ -38,12 +38,6 @@ class BubbleVolatileRepository @Inject constructor() { @Synchronized get() = entities.toList() /** * Add the bubble to memory and perform a de-duplication. In case the bubble already exists, * the bubble will be moved to the last. */ fun addBubble(bubble: BubbleXmlEntity) = addBubbles(listOf(bubble)) /** * Add the bubbles to memory and perform a de-duplication. In case a bubble already exists, * it will be moved to the last. Loading @@ -55,7 +49,7 @@ class BubbleVolatileRepository @Inject constructor() { if (entities.size + bubbles.size >= CAPACITY) { entities.drop(entities.size + bubbles.size - CAPACITY) } entities.addAll(bubbles.reversed()) entities.addAll(bubbles) } @Synchronized Loading packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt +35 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.systemui.bubbles.storage import com.android.internal.util.FastXmlSerializer import org.xmlpull.v1.XmlSerializer import java.io.IOException import android.util.Xml import com.android.internal.util.XmlUtils import org.xmlpull.v1.XmlPullParser import java.io.InputStream import java.io.OutputStream import java.nio.charset.StandardCharsets Loading Loading @@ -58,3 +62,34 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) { throw RuntimeException(e) } } /** * Reads the bubbles from xml file. */ fun readXml(stream: InputStream): List<BubbleXmlEntity> { val bubbles = mutableListOf<BubbleXmlEntity>() val parser: XmlPullParser = Xml.newPullParser() parser.setInput(stream, StandardCharsets.UTF_8.name()) XmlUtils.beginDocument(parser, TAG_BUBBLES) val outerDepth = parser.depth while (XmlUtils.nextElementWithin(parser, outerDepth)) { bubbles.add(readXmlEntry(parser) ?: continue) } return bubbles } private fun readXmlEntry(parser: XmlPullParser): BubbleXmlEntity? { while (parser.eventType != XmlPullParser.START_TAG) { parser.next() } return BubbleXmlEntity( parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_PACKAGE) ?: return null, parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null ) } private fun XmlPullParser.getAttributeWithName(name: String): String? { for (i in 0 until attributeCount) { if (getAttributeName(i) == name) return getAttributeValue(i) } return null } No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt +34 −15 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.bubbles import android.annotation.UserIdInt import android.util.Log import com.android.systemui.bubbles.storage.BubblePersistentRepository import com.android.systemui.bubbles.storage.BubbleVolatileRepository import com.android.systemui.bubbles.storage.BubbleXmlEntity Loading @@ -35,36 +36,39 @@ internal class BubbleDataRepository @Inject constructor( ) { private val ioScope = CoroutineScope(Dispatchers.IO) private val uiScope = CoroutineScope(Dispatchers.Main) private var job: Job? = null /** * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk * asynchronously. */ fun addBubble(@UserIdInt userId: Int, bubble: Bubble) { volatileRepository.addBubble( BubbleXmlEntity(userId, bubble.packageName, bubble.shortcutInfo?.id ?: return)) persistToDisk() } fun addBubble(@UserIdInt userId: Int, bubble: Bubble) = addBubbles(userId, listOf(bubble)) /** * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk * asynchronously. */ fun addBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) { volatileRepository.addBubbles(bubbles.mapNotNull { val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, it.packageName, shortcutId) }) persistToDisk() if (DEBUG) Log.d(TAG, "adding ${bubbles.size} bubbles") val entities = transform(userId, bubbles).also(volatileRepository::addBubbles) if (entities.isNotEmpty()) persistToDisk() } /** * Removes the bubbles from memory, then persists the snapshot to disk asynchronously. */ fun removeBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) { volatileRepository.removeBubbles(bubbles.mapNotNull { val shortcutId = it.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, it.packageName, shortcutId) }) persistToDisk() if (DEBUG) Log.d(TAG, "removing ${bubbles.size} bubbles") val entities = transform(userId, bubbles).also(volatileRepository::removeBubbles) if (entities.isNotEmpty()) persistToDisk() } private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleXmlEntity> { return bubbles.mapNotNull { b -> val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null BubbleXmlEntity(userId, b.packageName, shortcutId) } } /** Loading Loading @@ -92,4 +96,19 @@ internal class BubbleDataRepository @Inject constructor( persistentRepository.persistsToDisk(volatileRepository.bubbles) } } /** * Load bubbles from disk. */ fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch { val bubbleXmlEntities = persistentRepository.readFromDisk() volatileRepository.addBubbles(bubbleXmlEntities) uiScope.launch { // TODO: transform bubbleXmlEntities into bubbles // cb(bubbles) } } } private const val TAG = "BubbleDataRepository" private const val DEBUG = false
packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt +12 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ class BubblePersistentRepository @Inject constructor( "overflow_bubbles.xml"), "overflow-bubbles") fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean { if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles") synchronized(bubbleFile) { val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) { Log.e(TAG, "Failed to save bubble file", e) Loading @@ -41,6 +42,7 @@ class BubblePersistentRepository @Inject constructor( try { writeXml(stream, bubbles) bubbleFile.finishWrite(stream) if (DEBUG) Log.d(TAG, "persisted ${bubbles.size} bubbles") return true } catch (e: Exception) { Log.e(TAG, "Failed to save bubble file, restoring backup", e) Loading @@ -49,6 +51,16 @@ class BubblePersistentRepository @Inject constructor( } return false } fun readFromDisk(): List<BubbleXmlEntity> { synchronized(bubbleFile) { try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) { Log.e(TAG, "Failed to open bubble file", e) } return emptyList() } } } private const val TAG = "BubblePersistentRepository" private const val DEBUG = false
packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt +1 −7 Original line number Diff line number Diff line Loading @@ -38,12 +38,6 @@ class BubbleVolatileRepository @Inject constructor() { @Synchronized get() = entities.toList() /** * Add the bubble to memory and perform a de-duplication. In case the bubble already exists, * the bubble will be moved to the last. */ fun addBubble(bubble: BubbleXmlEntity) = addBubbles(listOf(bubble)) /** * Add the bubbles to memory and perform a de-duplication. In case a bubble already exists, * it will be moved to the last. Loading @@ -55,7 +49,7 @@ class BubbleVolatileRepository @Inject constructor() { if (entities.size + bubbles.size >= CAPACITY) { entities.drop(entities.size + bubbles.size - CAPACITY) } entities.addAll(bubbles.reversed()) entities.addAll(bubbles) } @Synchronized Loading
packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt +35 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.systemui.bubbles.storage import com.android.internal.util.FastXmlSerializer import org.xmlpull.v1.XmlSerializer import java.io.IOException import android.util.Xml import com.android.internal.util.XmlUtils import org.xmlpull.v1.XmlPullParser import java.io.InputStream import java.io.OutputStream import java.nio.charset.StandardCharsets Loading Loading @@ -58,3 +62,34 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) { throw RuntimeException(e) } } /** * Reads the bubbles from xml file. */ fun readXml(stream: InputStream): List<BubbleXmlEntity> { val bubbles = mutableListOf<BubbleXmlEntity>() val parser: XmlPullParser = Xml.newPullParser() parser.setInput(stream, StandardCharsets.UTF_8.name()) XmlUtils.beginDocument(parser, TAG_BUBBLES) val outerDepth = parser.depth while (XmlUtils.nextElementWithin(parser, outerDepth)) { bubbles.add(readXmlEntry(parser) ?: continue) } return bubbles } private fun readXmlEntry(parser: XmlPullParser): BubbleXmlEntity? { while (parser.eventType != XmlPullParser.START_TAG) { parser.next() } return BubbleXmlEntity( parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_PACKAGE) ?: return null, parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null ) } private fun XmlPullParser.getAttributeWithName(name: String): String? { for (i in 0 until attributeCount) { if (getAttributeName(i) == name) return getAttributeValue(i) } return null } No newline at end of file