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

Commit d0166e43 authored by Pinyao Ting's avatar Pinyao Ting Committed by Android (Google) Code Review
Browse files

Merge "Persists bubbles to disk (part 2)" into rvc-dev

parents 1876a797 76ed7ba8
Loading
Loading
Loading
Loading
+34 −15
Original line number Diff line number Diff line
@@ -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
@@ -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)
        }
    }

    /**
@@ -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
+12 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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)
@@ -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
+1 −7
Original line number Diff line number Diff line
@@ -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.
@@ -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
+35 −0
Original line number Diff line number Diff line
@@ -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

@@ -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