1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.inflation 18 19 import android.app.Notification 20 import android.app.RemoteInput 21 import android.graphics.drawable.Icon 22 import android.text.TextUtils 23 import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType 24 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation 25 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation 26 27 /** 28 * An immutable object which contains minimal state extracted from an entry that represents state 29 * which can change without a direct app update (e.g. with a ranking update). Diffing two entries 30 * determines if view re-inflation is needed. 31 */ 32 class NotifUiAdjustment 33 internal constructor( 34 val key: String, 35 val smartActions: List<Notification.Action>, 36 val smartReplies: List<CharSequence>, 37 val isConversation: Boolean, 38 val isSnoozeEnabled: Boolean, 39 val isMinimized: Boolean, 40 @RedactionType val redactionType: Int, 41 val isChildInGroup: Boolean, 42 val isGroupSummary: Boolean, 43 val summarization: String?, 44 ) { 45 companion object { 46 @JvmStatic needReinflatenull47 fun needReinflate( 48 oldAdjustment: NotifUiAdjustment, 49 newAdjustment: NotifUiAdjustment, 50 ): Boolean = 51 when { 52 oldAdjustment === newAdjustment -> false 53 oldAdjustment.isConversation != newAdjustment.isConversation -> true 54 oldAdjustment.isSnoozeEnabled != newAdjustment.isSnoozeEnabled -> true 55 oldAdjustment.isMinimized != newAdjustment.isMinimized -> true 56 oldAdjustment.redactionType != newAdjustment.redactionType -> true 57 areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions) -> true 58 newAdjustment.smartReplies != oldAdjustment.smartReplies -> true 59 AsyncHybridViewInflation.isEnabled && 60 !oldAdjustment.isChildInGroup && 61 newAdjustment.isChildInGroup -> true 62 AsyncGroupHeaderViewInflation.isEnabled && 63 !oldAdjustment.isGroupSummary && 64 newAdjustment.isGroupSummary -> true 65 oldAdjustment.summarization != newAdjustment.summarization -> true 66 else -> false 67 } 68 areDifferentnull69 private fun areDifferent( 70 first: List<Notification.Action>, 71 second: List<Notification.Action>, 72 ): Boolean = 73 when { 74 first === second -> false 75 first.size != second.size -> true 76 else -> 77 first.asSequence().zip(second.asSequence()).any { 78 (!TextUtils.equals(it.first.title, it.second.title)) || 79 (areDifferent(it.first.getIcon(), it.second.getIcon())) || 80 (it.first.actionIntent != it.second.actionIntent) || 81 (areDifferent(it.first.remoteInputs, it.second.remoteInputs)) 82 } 83 } 84 areDifferentnull85 private fun areDifferent(first: Icon?, second: Icon?): Boolean = 86 when { 87 first === second -> false 88 first == null || second == null -> true 89 else -> !first.sameAs(second) 90 } 91 areDifferentnull92 private fun areDifferent(first: Array<RemoteInput>?, second: Array<RemoteInput>?): Boolean = 93 when { 94 first === second -> false 95 first == null || second == null -> true 96 first.size != second.size -> true 97 else -> 98 first.asSequence().zip(second.asSequence()).any { 99 (!TextUtils.equals(it.first.label, it.second.label)) || 100 (areDifferent(it.first.choices, it.second.choices)) 101 } 102 } 103 areDifferentnull104 private fun areDifferent( 105 first: Array<CharSequence>?, 106 second: Array<CharSequence>?, 107 ): Boolean = 108 when { 109 first === second -> false 110 first == null || second == null -> true 111 first.size != second.size -> true 112 else -> 113 first.asSequence().zip(second.asSequence()).any { 114 !TextUtils.equals(it.first, it.second) 115 } 116 } 117 } 118 } 119