1 /*
2  * Copyright 2018 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 package com.android.systemui.statusbar;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.app.Notification;
21 import android.app.RemoteInput;
22 import android.graphics.drawable.Icon;
23 import android.text.TextUtils;
24 
25 import androidx.annotation.VisibleForTesting;
26 
27 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
28 
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Objects;
34 
35 /**
36  * By diffing two entries, determines is view reinflation needed.
37  */
38 public class NotificationUiAdjustment {
39 
40     public final String key;
41     public final List<Notification.Action> smartActions;
42     public final CharSequence[] smartReplies;
43 
44     @VisibleForTesting
NotificationUiAdjustment( String key, List<Notification.Action> smartActions, CharSequence[] smartReplies)45     NotificationUiAdjustment(
46             String key, List<Notification.Action> smartActions, CharSequence[] smartReplies) {
47         this.key = key;
48         this.smartActions = smartActions == null
49                 ? Collections.emptyList()
50                 : new ArrayList<>(smartActions);
51         this.smartReplies = smartReplies == null ? new CharSequence[0] : smartReplies.clone();
52     }
53 
extractFromNotificationEntry( NotificationEntry entry)54     public static NotificationUiAdjustment extractFromNotificationEntry(
55             NotificationEntry entry) {
56         return new NotificationUiAdjustment(
57                 entry.key, entry.systemGeneratedSmartActions, entry.systemGeneratedSmartReplies);
58     }
59 
needReinflate( @onNull NotificationUiAdjustment oldAdjustment, @NonNull NotificationUiAdjustment newAdjustment)60     public static boolean needReinflate(
61             @NonNull NotificationUiAdjustment oldAdjustment,
62             @NonNull NotificationUiAdjustment newAdjustment) {
63         if (oldAdjustment == newAdjustment) {
64             return false;
65         }
66         if (areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions)) {
67             return true;
68         }
69         if (!Arrays.equals(oldAdjustment.smartReplies, newAdjustment.smartReplies)) {
70             return true;
71         }
72         return false;
73     }
74 
areDifferent( @onNull List<Notification.Action> first, @NonNull List<Notification.Action> second)75     public static boolean areDifferent(
76             @NonNull List<Notification.Action> first, @NonNull List<Notification.Action> second) {
77         if (first == second) {
78             return false;
79         }
80         if (first == null || second == null) {
81             return true;
82         }
83         if (first.size() != second.size()) {
84             return true;
85         }
86         for (int i = 0; i < first.size(); i++) {
87             Notification.Action firstAction = first.get(i);
88             Notification.Action secondAction = second.get(i);
89 
90             if (!TextUtils.equals(firstAction.title, secondAction.title)) {
91                 return true;
92             }
93 
94             if (areDifferent(firstAction.getIcon(), secondAction.getIcon())) {
95                 return true;
96             }
97 
98             if (!Objects.equals(firstAction.actionIntent, secondAction.actionIntent)) {
99                 return true;
100             }
101 
102             if (areDifferent(firstAction.getRemoteInputs(), secondAction.getRemoteInputs())) {
103                 return true;
104             }
105         }
106         return false;
107     }
108 
areDifferent(@ullable Icon first, @Nullable Icon second)109     private static boolean areDifferent(@Nullable Icon first, @Nullable Icon second) {
110         if (first == second) {
111             return false;
112         }
113         if (first == null || second == null) {
114             return true;
115         }
116         return !first.sameAs(second);
117     }
118 
areDifferent( @ullable RemoteInput[] first, @Nullable RemoteInput[] second)119     private static boolean areDifferent(
120             @Nullable RemoteInput[] first, @Nullable RemoteInput[] second) {
121         if (first == second) {
122             return false;
123         }
124         if (first == null || second == null) {
125             return true;
126         }
127         if (first.length != second.length) {
128             return true;
129         }
130         for (int i = 0; i < first.length; i++) {
131             RemoteInput firstRemoteInput = first[i];
132             RemoteInput secondRemoteInput = second[i];
133 
134             if (!TextUtils.equals(firstRemoteInput.getLabel(), secondRemoteInput.getLabel())) {
135                 return true;
136             }
137             if (areDifferent(firstRemoteInput.getChoices(), secondRemoteInput.getChoices())) {
138                 return true;
139             }
140         }
141         return false;
142     }
143 
areDifferent( @ullable CharSequence[] first, @Nullable CharSequence[] second)144     private static boolean areDifferent(
145             @Nullable CharSequence[] first, @Nullable CharSequence[] second) {
146         if (first == second) {
147             return false;
148         }
149         if (first == null || second == null) {
150             return true;
151         }
152         if (first.length != second.length) {
153             return true;
154         }
155         for (int i = 0; i < first.length; i++) {
156             CharSequence firstCharSequence = first[i];
157             CharSequence secondCharSequence = second[i];
158             if (!TextUtils.equals(firstCharSequence, secondCharSequence)) {
159                 return true;
160             }
161         }
162         return false;
163     }
164 }
165