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

Commit 503c28e4 authored by Pinyao Ting's avatar Pinyao Ting Committed by Automerger Merge Worker
Browse files

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

Change-Id: I82cb35965b4e0b523a6d8ba99d22c5624e3ea366
parents ef2facf5 d0166e43
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