Merge "Persists bubbles to disk (part 1)" into rvc-dev am: 92703c0e2a
Change-Id: I6ef9f144e1d6bed2ec0a0442e088058239ee85f9
This commit is contained in:
@@ -129,6 +129,8 @@ android_library {
|
|||||||
"androidx.lifecycle_lifecycle-extensions",
|
"androidx.lifecycle_lifecycle-extensions",
|
||||||
"androidx.dynamicanimation_dynamicanimation",
|
"androidx.dynamicanimation_dynamicanimation",
|
||||||
"androidx-constraintlayout_constraintlayout",
|
"androidx-constraintlayout_constraintlayout",
|
||||||
|
"kotlinx-coroutines-android",
|
||||||
|
"kotlinx-coroutines-core",
|
||||||
"iconloader_base",
|
"iconloader_base",
|
||||||
"SystemUI-tags",
|
"SystemUI-tags",
|
||||||
"SystemUI-proto",
|
"SystemUI-proto",
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
private final NotificationGroupManager mNotificationGroupManager;
|
private final NotificationGroupManager mNotificationGroupManager;
|
||||||
private final ShadeController mShadeController;
|
private final ShadeController mShadeController;
|
||||||
private final FloatingContentCoordinator mFloatingContentCoordinator;
|
private final FloatingContentCoordinator mFloatingContentCoordinator;
|
||||||
|
private final BubbleDataRepository mDataRepository;
|
||||||
|
|
||||||
private BubbleData mBubbleData;
|
private BubbleData mBubbleData;
|
||||||
private ScrimView mBubbleScrim;
|
private ScrimView mBubbleScrim;
|
||||||
@@ -294,13 +295,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
FloatingContentCoordinator floatingContentCoordinator,
|
FloatingContentCoordinator floatingContentCoordinator,
|
||||||
|
BubbleDataRepository dataRepository,
|
||||||
SysUiState sysUiState,
|
SysUiState sysUiState,
|
||||||
INotificationManager notificationManager) {
|
INotificationManager notificationManager) {
|
||||||
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
|
this(context, notificationShadeWindowController, statusBarStateController, shadeController,
|
||||||
data, null /* synchronizer */, configurationController, interruptionStateProvider,
|
data, null /* synchronizer */, configurationController, interruptionStateProvider,
|
||||||
zenModeController, notifUserManager, groupManager, entryManager,
|
zenModeController, notifUserManager, groupManager, entryManager,
|
||||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
|
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
|
||||||
notificationManager);
|
dataRepository, sysUiState, notificationManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -322,6 +324,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
FloatingContentCoordinator floatingContentCoordinator,
|
FloatingContentCoordinator floatingContentCoordinator,
|
||||||
|
BubbleDataRepository dataRepository,
|
||||||
SysUiState sysUiState,
|
SysUiState sysUiState,
|
||||||
INotificationManager notificationManager) {
|
INotificationManager notificationManager) {
|
||||||
dumpManager.registerDumpable(TAG, this);
|
dumpManager.registerDumpable(TAG, this);
|
||||||
@@ -331,6 +334,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
mNotifUserManager = notifUserManager;
|
mNotifUserManager = notifUserManager;
|
||||||
mZenModeController = zenModeController;
|
mZenModeController = zenModeController;
|
||||||
mFloatingContentCoordinator = floatingContentCoordinator;
|
mFloatingContentCoordinator = floatingContentCoordinator;
|
||||||
|
mDataRepository = dataRepository;
|
||||||
mINotificationManager = notificationManager;
|
mINotificationManager = notificationManager;
|
||||||
mZenModeController.addCallback(new ZenModeController.Callback() {
|
mZenModeController.addCallback(new ZenModeController.Callback() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1018,6 +1022,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
// Do removals, if any.
|
// Do removals, if any.
|
||||||
ArrayList<Pair<Bubble, Integer>> removedBubbles =
|
ArrayList<Pair<Bubble, Integer>> removedBubbles =
|
||||||
new ArrayList<>(update.removedBubbles);
|
new ArrayList<>(update.removedBubbles);
|
||||||
|
ArrayList<Bubble> bubblesToBeRemovedFromRepository = new ArrayList<>();
|
||||||
for (Pair<Bubble, Integer> removed : removedBubbles) {
|
for (Pair<Bubble, Integer> removed : removedBubbles) {
|
||||||
final Bubble bubble = removed.first;
|
final Bubble bubble = removed.first;
|
||||||
@DismissReason final int reason = removed.second;
|
@DismissReason final int reason = removed.second;
|
||||||
@@ -1027,6 +1032,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
if (reason == DISMISS_USER_CHANGED) {
|
if (reason == DISMISS_USER_CHANGED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (reason == DISMISS_NOTIF_CANCEL) {
|
||||||
|
bubblesToBeRemovedFromRepository.add(bubble);
|
||||||
|
}
|
||||||
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
||||||
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
|
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
|
||||||
&& (!bubble.showInShade()
|
&& (!bubble.showInShade()
|
||||||
@@ -1056,9 +1064,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
|
||||||
|
|
||||||
if (update.addedBubble != null) {
|
if (update.addedBubble != null) {
|
||||||
|
mDataRepository.addBubble(mCurrentUserId, update.addedBubble);
|
||||||
mStackView.addBubble(update.addedBubble);
|
mStackView.addBubble(update.addedBubble);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update.updatedBubble != null) {
|
if (update.updatedBubble != null) {
|
||||||
@@ -1068,6 +1079,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
// At this point, the correct bubbles are inflated in the stack.
|
// At this point, the correct bubbles are inflated in the stack.
|
||||||
// Make sure the order in bubble data is reflected in bubble row.
|
// Make sure the order in bubble data is reflected in bubble row.
|
||||||
if (update.orderChanged) {
|
if (update.orderChanged) {
|
||||||
|
mDataRepository.addBubbles(mCurrentUserId, update.bubbles);
|
||||||
mStackView.updateBubbleOrder(update.bubbles);
|
mStackView.updateBubbleOrder(update.bubbles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.bubbles
|
||||||
|
|
||||||
|
import android.annotation.UserIdInt
|
||||||
|
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 ioScope = CoroutineScope(Dispatchers.IO)
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the bubbles to disk. When being called multiple times, it waits for first ongoing
|
||||||
|
* write operation to finish then run another write operation exactly once.
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* Job A started -> blocking I/O
|
||||||
|
* Job B started, cancels A, wait for blocking I/O in A finishes
|
||||||
|
* Job C started, cancels B, wait for job B to finish
|
||||||
|
* Job D started, cancels C, wait for job C to finish
|
||||||
|
* Job A completed
|
||||||
|
* Job B resumes and reaches yield() and is then cancelled
|
||||||
|
* Job C resumes and reaches yield() and is then cancelled
|
||||||
|
* Job D resumes and performs another blocking I/O
|
||||||
|
*/
|
||||||
|
private fun persistToDisk() {
|
||||||
|
val prev = job
|
||||||
|
job = ioScope.launch {
|
||||||
|
// if there was an ongoing disk I/O operation, they can be cancelled
|
||||||
|
prev?.cancelAndJoin()
|
||||||
|
// check for cancellation before disk I/O
|
||||||
|
yield()
|
||||||
|
// save to disk
|
||||||
|
persistentRepository.persistsToDisk(volatileRepository.bubbles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
|||||||
|
|
||||||
import com.android.systemui.bubbles.BubbleController;
|
import com.android.systemui.bubbles.BubbleController;
|
||||||
import com.android.systemui.bubbles.BubbleData;
|
import com.android.systemui.bubbles.BubbleData;
|
||||||
|
import com.android.systemui.bubbles.BubbleDataRepository;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.model.SysUiState;
|
import com.android.systemui.model.SysUiState;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
@@ -65,6 +66,7 @@ public interface BubbleModule {
|
|||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
FloatingContentCoordinator floatingContentCoordinator,
|
FloatingContentCoordinator floatingContentCoordinator,
|
||||||
|
BubbleDataRepository bubbleDataRepository,
|
||||||
SysUiState sysUiState,
|
SysUiState sysUiState,
|
||||||
INotificationManager notifManager) {
|
INotificationManager notifManager) {
|
||||||
return new BubbleController(
|
return new BubbleController(
|
||||||
@@ -84,6 +86,7 @@ public interface BubbleModule {
|
|||||||
featureFlags,
|
featureFlags,
|
||||||
dumpManager,
|
dumpManager,
|
||||||
floatingContentCoordinator,
|
floatingContentCoordinator,
|
||||||
|
bubbleDataRepository,
|
||||||
sysUiState,
|
sysUiState,
|
||||||
notifManager);
|
notifManager);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.bubbles.storage
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AtomicFile
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class BubblePersistentRepository @Inject constructor(
|
||||||
|
context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir,
|
||||||
|
"overflow_bubbles.xml"), "overflow-bubbles")
|
||||||
|
|
||||||
|
fun persistsToDisk(bubbles: List<BubbleXmlEntity>): Boolean {
|
||||||
|
synchronized(bubbleFile) {
|
||||||
|
val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) {
|
||||||
|
Log.e(TAG, "Failed to save bubble file", e)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writeXml(stream, bubbles)
|
||||||
|
bubbleFile.finishWrite(stream)
|
||||||
|
return true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to save bubble file, restoring backup", e)
|
||||||
|
bubbleFile.failWrite(stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val TAG = "BubblePersistentRepository"
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.bubbles.storage
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
private const val CAPACITY = 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BubbleVolatileRepository holds the most updated snapshot of list of bubbles for in-memory
|
||||||
|
* manipulation.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class BubbleVolatileRepository @Inject constructor() {
|
||||||
|
/**
|
||||||
|
* An ordered set of bubbles based on their natural ordering.
|
||||||
|
*/
|
||||||
|
private val entities = mutableSetOf<BubbleXmlEntity>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a snapshot of all the bubbles.
|
||||||
|
*/
|
||||||
|
val bubbles: List<BubbleXmlEntity>
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
fun addBubbles(bubbles: List<BubbleXmlEntity>) {
|
||||||
|
if (bubbles.isEmpty()) return
|
||||||
|
bubbles.forEach { entities.remove(it) }
|
||||||
|
if (entities.size + bubbles.size >= CAPACITY) {
|
||||||
|
entities.drop(entities.size + bubbles.size - CAPACITY)
|
||||||
|
}
|
||||||
|
entities.addAll(bubbles.reversed())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun removeBubbles(bubbles: List<BubbleXmlEntity>) {
|
||||||
|
bubbles.forEach { entities.remove(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.bubbles.storage
|
||||||
|
|
||||||
|
import android.annotation.UserIdInt
|
||||||
|
|
||||||
|
data class BubbleXmlEntity(
|
||||||
|
@UserIdInt val userId: Int,
|
||||||
|
val packageName: String,
|
||||||
|
val shortcutId: String
|
||||||
|
)
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.android.systemui.bubbles.storage
|
||||||
|
|
||||||
|
import com.android.internal.util.FastXmlSerializer
|
||||||
|
import org.xmlpull.v1.XmlSerializer
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
|
private const val TAG_BUBBLES = "bs"
|
||||||
|
private const val TAG_BUBBLE = "bb"
|
||||||
|
private const val ATTR_USER_ID = "uid"
|
||||||
|
private const val ATTR_PACKAGE = "pkg"
|
||||||
|
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>) {
|
||||||
|
val serializer: XmlSerializer = FastXmlSerializer()
|
||||||
|
serializer.setOutput(stream, StandardCharsets.UTF_8.name())
|
||||||
|
serializer.startDocument(null, true)
|
||||||
|
serializer.startTag(null, TAG_BUBBLES)
|
||||||
|
bubbles.forEach { b -> writeXmlEntry(serializer, b) }
|
||||||
|
serializer.endTag(null, TAG_BUBBLES)
|
||||||
|
serializer.endDocument()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a xml entry for given bubble in following format:
|
||||||
|
* ```
|
||||||
|
* <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleXmlEntity) {
|
||||||
|
try {
|
||||||
|
serializer.startTag(null, TAG_BUBBLE)
|
||||||
|
serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString())
|
||||||
|
serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
|
||||||
|
serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
|
||||||
|
serializer.endTag(null, TAG_BUBBLE)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,6 +140,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
private KeyguardBypassController mKeyguardBypassController;
|
private KeyguardBypassController mKeyguardBypassController;
|
||||||
@Mock
|
@Mock
|
||||||
private FloatingContentCoordinator mFloatingContentCoordinator;
|
private FloatingContentCoordinator mFloatingContentCoordinator;
|
||||||
|
@Mock
|
||||||
|
private BubbleDataRepository mDataRepository;
|
||||||
|
|
||||||
private SysUiState mSysUiState;
|
private SysUiState mSysUiState;
|
||||||
private boolean mSysUiStateBubblesExpanded;
|
private boolean mSysUiStateBubblesExpanded;
|
||||||
@@ -275,6 +277,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
mFeatureFlagsOldPipeline,
|
mFeatureFlagsOldPipeline,
|
||||||
mDumpManager,
|
mDumpManager,
|
||||||
mFloatingContentCoordinator,
|
mFloatingContentCoordinator,
|
||||||
|
mDataRepository,
|
||||||
mSysUiState,
|
mSysUiState,
|
||||||
mock(INotificationManager.class));
|
mock(INotificationManager.class));
|
||||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private FloatingContentCoordinator mFloatingContentCoordinator;
|
private FloatingContentCoordinator mFloatingContentCoordinator;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BubbleDataRepository mDataRepository;
|
||||||
|
@Mock
|
||||||
private NotificationShadeWindowView mNotificationShadeWindowView;
|
private NotificationShadeWindowView mNotificationShadeWindowView;
|
||||||
|
|
||||||
private SysUiState mSysUiState = new SysUiState();
|
private SysUiState mSysUiState = new SysUiState();
|
||||||
@@ -250,6 +252,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
mFeatureFlagsNewPipeline,
|
mFeatureFlagsNewPipeline,
|
||||||
mDumpManager,
|
mDumpManager,
|
||||||
mFloatingContentCoordinator,
|
mFloatingContentCoordinator,
|
||||||
|
mDataRepository,
|
||||||
mSysUiState,
|
mSysUiState,
|
||||||
mock(INotificationManager.class));
|
mock(INotificationManager.class));
|
||||||
mBubbleController.addNotifCallback(mNotifCallback);
|
mBubbleController.addNotifCallback(mNotifCallback);
|
||||||
|
|||||||
@@ -55,14 +55,15 @@ public class TestableBubbleController extends BubbleController {
|
|||||||
FeatureFlags featureFlags,
|
FeatureFlags featureFlags,
|
||||||
DumpManager dumpManager,
|
DumpManager dumpManager,
|
||||||
FloatingContentCoordinator floatingContentCoordinator,
|
FloatingContentCoordinator floatingContentCoordinator,
|
||||||
|
BubbleDataRepository dataRepository,
|
||||||
SysUiState sysUiState,
|
SysUiState sysUiState,
|
||||||
INotificationManager notificationManager) {
|
INotificationManager notificationManager) {
|
||||||
super(context,
|
super(context,
|
||||||
notificationShadeWindowController, statusBarStateController, shadeController,
|
notificationShadeWindowController, statusBarStateController, shadeController,
|
||||||
data, Runnable::run, configurationController, interruptionStateProvider,
|
data, Runnable::run, configurationController, interruptionStateProvider,
|
||||||
zenModeController, lockscreenUserManager, groupManager, entryManager,
|
zenModeController, lockscreenUserManager, groupManager, entryManager,
|
||||||
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState,
|
notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
|
||||||
notificationManager);
|
dataRepository, sysUiState, notificationManager);
|
||||||
setInflateSynchronously(true);
|
setInflateSynchronously(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user