650 lines
25 KiB
Java
650 lines
25 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2023 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 android.service.notification;
|
||
|
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.app.Flags;
|
||
|
import android.util.ArrayMap;
|
||
|
import android.util.ArraySet;
|
||
|
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.util.Objects;
|
||
|
import java.util.Set;
|
||
|
|
||
|
/**
|
||
|
* ZenModeDiff is a utility class meant to encapsulate the diff between ZenModeConfigs and their
|
||
|
* subcomponents (automatic and manual ZenRules).
|
||
|
*
|
||
|
* <p>Note that this class is intended to detect <em>meaningful</em> differences, so objects that
|
||
|
* are not identical (as per their {@code equals()} implementation) can still produce an empty diff
|
||
|
* if only "metadata" fields are updated.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
public class ZenModeDiff {
|
||
|
/**
|
||
|
* Enum representing whether the existence of a config or rule has changed (added or removed,
|
||
|
* or "none" meaning there is no change, which may either mean both null, or there exists a
|
||
|
* diff in fields rather than add/remove).
|
||
|
*/
|
||
|
@IntDef(value = {
|
||
|
NONE,
|
||
|
ADDED,
|
||
|
REMOVED,
|
||
|
})
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
public @interface ExistenceChange{}
|
||
|
|
||
|
public static final int NONE = 0;
|
||
|
public static final int ADDED = 1;
|
||
|
public static final int REMOVED = 2;
|
||
|
|
||
|
/**
|
||
|
* Diff class representing an individual field diff.
|
||
|
* @param <T> The type of the field.
|
||
|
*/
|
||
|
public static class FieldDiff<T> {
|
||
|
private final T mFrom;
|
||
|
private final T mTo;
|
||
|
|
||
|
/**
|
||
|
* Constructor to create a FieldDiff object with the given values.
|
||
|
* @param from from (old) value
|
||
|
* @param to to (new) value
|
||
|
*/
|
||
|
public FieldDiff(@Nullable T from, @Nullable T to) {
|
||
|
mFrom = from;
|
||
|
mTo = to;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the "from" value
|
||
|
*/
|
||
|
public T from() {
|
||
|
return mFrom;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the "to" value
|
||
|
*/
|
||
|
public T to() {
|
||
|
return mTo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the string representation of this field diff, in the form of "from->to".
|
||
|
*/
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return mFrom + "->" + mTo;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this represents an actual diff.
|
||
|
*/
|
||
|
public boolean hasDiff() {
|
||
|
// note that Objects.equals handles null values gracefully.
|
||
|
return !Objects.equals(mFrom, mTo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Base diff class that contains info about whether something was added, and a set of named
|
||
|
* fields that changed.
|
||
|
* Extend for diffs of specific types of objects.
|
||
|
*/
|
||
|
private abstract static class BaseDiff {
|
||
|
// Whether the diff was added or removed
|
||
|
@ExistenceChange private int mExists = NONE;
|
||
|
|
||
|
// Map from field name to diffs for any standalone fields in the object.
|
||
|
private ArrayMap<String, FieldDiff> mFields = new ArrayMap<>();
|
||
|
|
||
|
// Functions for actually diffing objects and string representations have to be implemented
|
||
|
// by subclasses.
|
||
|
|
||
|
/**
|
||
|
* Return whether this diff represents any changes.
|
||
|
*/
|
||
|
public abstract boolean hasDiff();
|
||
|
|
||
|
/**
|
||
|
* Return a string representation of the diff.
|
||
|
*/
|
||
|
public abstract String toString();
|
||
|
|
||
|
/**
|
||
|
* Constructor that takes the two objects meant to be compared. This constructor sets
|
||
|
* whether there is an existence change (added or removed).
|
||
|
* @param from previous Object
|
||
|
* @param to new Object
|
||
|
*/
|
||
|
BaseDiff(Object from, Object to) {
|
||
|
if (from == null) {
|
||
|
if (to != null) {
|
||
|
mExists = ADDED;
|
||
|
}
|
||
|
// If both are null, there isn't an existence change; callers/inheritors must handle
|
||
|
// the both null case.
|
||
|
} else if (to == null) {
|
||
|
// in this case, we know that from != null
|
||
|
mExists = REMOVED;
|
||
|
}
|
||
|
|
||
|
// Subclasses should implement the actual diffing functionality in their own
|
||
|
// constructors.
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a diff for a specific field to the map.
|
||
|
* @param name field name
|
||
|
* @param diff FieldDiff object representing the diff
|
||
|
*/
|
||
|
final void addField(String name, FieldDiff diff) {
|
||
|
mFields.put(name, diff);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff represents a config being newly added.
|
||
|
*/
|
||
|
public final boolean wasAdded() {
|
||
|
return mExists == ADDED;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff represents a config being removed.
|
||
|
*/
|
||
|
public final boolean wasRemoved() {
|
||
|
return mExists == REMOVED;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff represents an object being either added or removed.
|
||
|
*/
|
||
|
public final boolean hasExistenceChange() {
|
||
|
return mExists != NONE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether there are any individual field diffs.
|
||
|
*/
|
||
|
public final boolean hasFieldDiffs() {
|
||
|
return mFields.size() > 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the diff for the specific named field if it exists
|
||
|
*/
|
||
|
public final FieldDiff getDiffForField(String name) {
|
||
|
return mFields.getOrDefault(name, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the set of all field names with some diff.
|
||
|
*/
|
||
|
public final Set<String> fieldNamesWithDiff() {
|
||
|
return mFields.keySet();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Diff class representing a diff between two ZenModeConfigs.
|
||
|
*/
|
||
|
public static class ConfigDiff extends BaseDiff {
|
||
|
// Rules. Automatic rule map is keyed by the rule name.
|
||
|
private final ArrayMap<String, RuleDiff> mAutomaticRulesDiff = new ArrayMap<>();
|
||
|
private RuleDiff mManualRuleDiff;
|
||
|
|
||
|
// Field name constants
|
||
|
public static final String FIELD_USER = "user";
|
||
|
public static final String FIELD_ALLOW_ALARMS = "allowAlarms";
|
||
|
public static final String FIELD_ALLOW_MEDIA = "allowMedia";
|
||
|
public static final String FIELD_ALLOW_SYSTEM = "allowSystem";
|
||
|
public static final String FIELD_ALLOW_CALLS = "allowCalls";
|
||
|
public static final String FIELD_ALLOW_REMINDERS = "allowReminders";
|
||
|
public static final String FIELD_ALLOW_EVENTS = "allowEvents";
|
||
|
public static final String FIELD_ALLOW_REPEAT_CALLERS = "allowRepeatCallers";
|
||
|
public static final String FIELD_ALLOW_MESSAGES = "allowMessages";
|
||
|
public static final String FIELD_ALLOW_CONVERSATIONS = "allowConversations";
|
||
|
public static final String FIELD_ALLOW_CALLS_FROM = "allowCallsFrom";
|
||
|
public static final String FIELD_ALLOW_MESSAGES_FROM = "allowMessagesFrom";
|
||
|
public static final String FIELD_ALLOW_CONVERSATIONS_FROM = "allowConversationsFrom";
|
||
|
public static final String FIELD_SUPPRESSED_VISUAL_EFFECTS = "suppressedVisualEffects";
|
||
|
public static final String FIELD_ARE_CHANNELS_BYPASSING_DND = "areChannelsBypassingDnd";
|
||
|
public static final String FIELD_ALLOW_PRIORITY_CHANNELS = "allowPriorityChannels";
|
||
|
private static final Set<String> PEOPLE_TYPE_FIELDS =
|
||
|
Set.of(FIELD_ALLOW_CALLS_FROM, FIELD_ALLOW_MESSAGES_FROM);
|
||
|
|
||
|
/**
|
||
|
* Create a diff that contains diffs between the "from" and "to" ZenModeConfigs.
|
||
|
*
|
||
|
* @param from previous ZenModeConfig
|
||
|
* @param to new ZenModeConfig
|
||
|
*/
|
||
|
public ConfigDiff(ZenModeConfig from, ZenModeConfig to) {
|
||
|
super(from, to);
|
||
|
// If both are null skip
|
||
|
if (from == null && to == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (hasExistenceChange()) {
|
||
|
// either added or removed; return here. otherwise (they're not both null) there's
|
||
|
// field diffs.
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Now we compare all the fields, knowing there's a diff and that neither is null
|
||
|
if (from.user != to.user) {
|
||
|
addField(FIELD_USER, new FieldDiff<>(from.user, to.user));
|
||
|
}
|
||
|
if (from.allowAlarms != to.allowAlarms) {
|
||
|
addField(FIELD_ALLOW_ALARMS, new FieldDiff<>(from.allowAlarms, to.allowAlarms));
|
||
|
}
|
||
|
if (from.allowMedia != to.allowMedia) {
|
||
|
addField(FIELD_ALLOW_MEDIA, new FieldDiff<>(from.allowMedia, to.allowMedia));
|
||
|
}
|
||
|
if (from.allowSystem != to.allowSystem) {
|
||
|
addField(FIELD_ALLOW_SYSTEM, new FieldDiff<>(from.allowSystem, to.allowSystem));
|
||
|
}
|
||
|
if (from.allowCalls != to.allowCalls) {
|
||
|
addField(FIELD_ALLOW_CALLS, new FieldDiff<>(from.allowCalls, to.allowCalls));
|
||
|
}
|
||
|
if (from.allowReminders != to.allowReminders) {
|
||
|
addField(FIELD_ALLOW_REMINDERS,
|
||
|
new FieldDiff<>(from.allowReminders, to.allowReminders));
|
||
|
}
|
||
|
if (from.allowEvents != to.allowEvents) {
|
||
|
addField(FIELD_ALLOW_EVENTS, new FieldDiff<>(from.allowEvents, to.allowEvents));
|
||
|
}
|
||
|
if (from.allowRepeatCallers != to.allowRepeatCallers) {
|
||
|
addField(FIELD_ALLOW_REPEAT_CALLERS,
|
||
|
new FieldDiff<>(from.allowRepeatCallers, to.allowRepeatCallers));
|
||
|
}
|
||
|
if (from.allowMessages != to.allowMessages) {
|
||
|
addField(FIELD_ALLOW_MESSAGES,
|
||
|
new FieldDiff<>(from.allowMessages, to.allowMessages));
|
||
|
}
|
||
|
if (from.allowConversations != to.allowConversations) {
|
||
|
addField(FIELD_ALLOW_CONVERSATIONS,
|
||
|
new FieldDiff<>(from.allowConversations, to.allowConversations));
|
||
|
}
|
||
|
if (from.allowCallsFrom != to.allowCallsFrom) {
|
||
|
addField(FIELD_ALLOW_CALLS_FROM,
|
||
|
new FieldDiff<>(from.allowCallsFrom, to.allowCallsFrom));
|
||
|
}
|
||
|
if (from.allowMessagesFrom != to.allowMessagesFrom) {
|
||
|
addField(FIELD_ALLOW_MESSAGES_FROM,
|
||
|
new FieldDiff<>(from.allowMessagesFrom, to.allowMessagesFrom));
|
||
|
}
|
||
|
if (from.allowConversationsFrom != to.allowConversationsFrom) {
|
||
|
addField(FIELD_ALLOW_CONVERSATIONS_FROM,
|
||
|
new FieldDiff<>(from.allowConversationsFrom, to.allowConversationsFrom));
|
||
|
}
|
||
|
if (from.suppressedVisualEffects != to.suppressedVisualEffects) {
|
||
|
addField(FIELD_SUPPRESSED_VISUAL_EFFECTS,
|
||
|
new FieldDiff<>(from.suppressedVisualEffects, to.suppressedVisualEffects));
|
||
|
}
|
||
|
if (from.areChannelsBypassingDnd != to.areChannelsBypassingDnd) {
|
||
|
addField(FIELD_ARE_CHANNELS_BYPASSING_DND,
|
||
|
new FieldDiff<>(from.areChannelsBypassingDnd, to.areChannelsBypassingDnd));
|
||
|
}
|
||
|
if (Flags.modesApi()) {
|
||
|
if (from.allowPriorityChannels != to.allowPriorityChannels) {
|
||
|
addField(FIELD_ALLOW_PRIORITY_CHANNELS,
|
||
|
new FieldDiff<>(from.allowPriorityChannels, to.allowPriorityChannels));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Compare automatic and manual rules
|
||
|
final ArraySet<String> allRules = new ArraySet<>();
|
||
|
addKeys(allRules, from.automaticRules);
|
||
|
addKeys(allRules, to.automaticRules);
|
||
|
final int num = allRules.size();
|
||
|
for (int i = 0; i < num; i++) {
|
||
|
final String rule = allRules.valueAt(i);
|
||
|
final ZenModeConfig.ZenRule
|
||
|
fromRule = from.automaticRules != null ? from.automaticRules.get(rule)
|
||
|
: null;
|
||
|
final ZenModeConfig.ZenRule
|
||
|
toRule = to.automaticRules != null ? to.automaticRules.get(rule) : null;
|
||
|
RuleDiff ruleDiff = new RuleDiff(fromRule, toRule);
|
||
|
if (ruleDiff.hasDiff()) {
|
||
|
mAutomaticRulesDiff.put(rule, ruleDiff);
|
||
|
}
|
||
|
}
|
||
|
// If there's no diff this may turn out to be null, but that's also fine
|
||
|
RuleDiff manualRuleDiff = new RuleDiff(from.manualRule, to.manualRule);
|
||
|
if (manualRuleDiff.hasDiff()) {
|
||
|
mManualRuleDiff = manualRuleDiff;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) {
|
||
|
if (map != null) {
|
||
|
for (int i = 0; i < map.size(); i++) {
|
||
|
set.add(map.keyAt(i));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff object contains any diffs in any field.
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean hasDiff() {
|
||
|
return hasExistenceChange()
|
||
|
|| hasFieldDiffs()
|
||
|
|| mManualRuleDiff != null
|
||
|
|| mAutomaticRulesDiff.size() > 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
final StringBuilder sb = new StringBuilder("Diff[");
|
||
|
if (!hasDiff()) {
|
||
|
sb.append("no changes");
|
||
|
}
|
||
|
|
||
|
// If added or deleted, then that's just the end of it
|
||
|
if (hasExistenceChange()) {
|
||
|
if (wasAdded()) {
|
||
|
sb.append("added");
|
||
|
} else if (wasRemoved()) {
|
||
|
sb.append("removed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handle top-level field change
|
||
|
boolean first = true;
|
||
|
for (String key : fieldNamesWithDiff()) {
|
||
|
FieldDiff diff = getDiffForField(key);
|
||
|
if (diff == null) {
|
||
|
// this shouldn't happen, but
|
||
|
continue;
|
||
|
}
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
sb.append(",\n");
|
||
|
}
|
||
|
|
||
|
// Some special handling for people- and conversation-type fields for readability
|
||
|
if (PEOPLE_TYPE_FIELDS.contains(key)) {
|
||
|
sb.append(key);
|
||
|
sb.append(":");
|
||
|
sb.append(ZenModeConfig.sourceToString((int) diff.from()));
|
||
|
sb.append("->");
|
||
|
sb.append(ZenModeConfig.sourceToString((int) diff.to()));
|
||
|
} else if (key.equals(FIELD_ALLOW_CONVERSATIONS_FROM)) {
|
||
|
sb.append(key);
|
||
|
sb.append(":");
|
||
|
sb.append(ZenPolicy.conversationTypeToString((int) diff.from()));
|
||
|
sb.append("->");
|
||
|
sb.append(ZenPolicy.conversationTypeToString((int) diff.to()));
|
||
|
} else {
|
||
|
sb.append(key);
|
||
|
sb.append(":");
|
||
|
sb.append(diff);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// manual rule
|
||
|
if (mManualRuleDiff != null && mManualRuleDiff.hasDiff()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
sb.append(",\n");
|
||
|
}
|
||
|
sb.append("manualRule:");
|
||
|
sb.append(mManualRuleDiff);
|
||
|
}
|
||
|
|
||
|
// automatic rules
|
||
|
for (String rule : mAutomaticRulesDiff.keySet()) {
|
||
|
RuleDiff diff = mAutomaticRulesDiff.get(rule);
|
||
|
if (diff != null && diff.hasDiff()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
sb.append(",\n");
|
||
|
}
|
||
|
sb.append("automaticRule[");
|
||
|
sb.append(rule);
|
||
|
sb.append("]:");
|
||
|
sb.append(diff);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sb.append(']').toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the diff in manual rule, if it exists.
|
||
|
*/
|
||
|
public RuleDiff getManualRuleDiff() {
|
||
|
return mManualRuleDiff;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the full map of automatic rule diffs, or null if there are no diffs.
|
||
|
*/
|
||
|
public ArrayMap<String, RuleDiff> getAllAutomaticRuleDiffs() {
|
||
|
return (mAutomaticRulesDiff.size() > 0) ? mAutomaticRulesDiff : null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Diff class representing a change between two ZenRules.
|
||
|
*/
|
||
|
public static class RuleDiff extends BaseDiff {
|
||
|
public static final String FIELD_ENABLED = "enabled";
|
||
|
public static final String FIELD_SNOOZING = "snoozing";
|
||
|
public static final String FIELD_NAME = "name";
|
||
|
public static final String FIELD_ZEN_MODE = "zenMode";
|
||
|
public static final String FIELD_CONDITION_ID = "conditionId";
|
||
|
public static final String FIELD_CONDITION = "condition";
|
||
|
public static final String FIELD_COMPONENT = "component";
|
||
|
public static final String FIELD_CONFIGURATION_ACTIVITY = "configurationActivity";
|
||
|
public static final String FIELD_ID = "id";
|
||
|
public static final String FIELD_CREATION_TIME = "creationTime";
|
||
|
public static final String FIELD_ENABLER = "enabler";
|
||
|
public static final String FIELD_ZEN_POLICY = "zenPolicy";
|
||
|
public static final String FIELD_ZEN_DEVICE_EFFECTS = "zenDeviceEffects";
|
||
|
public static final String FIELD_MODIFIED = "modified";
|
||
|
public static final String FIELD_PKG = "pkg";
|
||
|
public static final String FIELD_ALLOW_MANUAL = "allowManualInvocation";
|
||
|
public static final String FIELD_ICON_RES = "iconResName";
|
||
|
public static final String FIELD_TRIGGER_DESCRIPTION = "triggerDescription";
|
||
|
public static final String FIELD_TYPE = "type";
|
||
|
// NOTE: new field strings must match the variable names in ZenModeConfig.ZenRule
|
||
|
|
||
|
// Special field to track whether this rule became active or inactive
|
||
|
FieldDiff<Boolean> mActiveDiff;
|
||
|
|
||
|
/**
|
||
|
* Create a RuleDiff representing the difference between two ZenRule objects.
|
||
|
* @param from previous ZenRule
|
||
|
* @param to new ZenRule
|
||
|
* @return The diff between the two given ZenRules
|
||
|
*/
|
||
|
public RuleDiff(ZenModeConfig.ZenRule from, ZenModeConfig.ZenRule to) {
|
||
|
super(from, to);
|
||
|
// Short-circuit the both-null case
|
||
|
if (from == null && to == null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Even if added or removed, there may be a change in whether or not it was active.
|
||
|
// This only applies to automatic rules.
|
||
|
boolean fromActive = from != null ? from.isAutomaticActive() : false;
|
||
|
boolean toActive = to != null ? to.isAutomaticActive() : false;
|
||
|
if (fromActive != toActive) {
|
||
|
mActiveDiff = new FieldDiff<>(fromActive, toActive);
|
||
|
}
|
||
|
|
||
|
// Return if the diff was added or removed
|
||
|
if (hasExistenceChange()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (from.enabled != to.enabled) {
|
||
|
addField(FIELD_ENABLED, new FieldDiff<>(from.enabled, to.enabled));
|
||
|
}
|
||
|
if (from.snoozing != to.snoozing) {
|
||
|
addField(FIELD_SNOOZING, new FieldDiff<>(from.snoozing, to.snoozing));
|
||
|
}
|
||
|
if (!Objects.equals(from.name, to.name)) {
|
||
|
addField(FIELD_NAME, new FieldDiff<>(from.name, to.name));
|
||
|
}
|
||
|
if (from.zenMode != to.zenMode) {
|
||
|
addField(FIELD_ZEN_MODE, new FieldDiff<>(from.zenMode, to.zenMode));
|
||
|
}
|
||
|
if (!Objects.equals(from.conditionId, to.conditionId)) {
|
||
|
addField(FIELD_CONDITION_ID, new FieldDiff<>(from.conditionId,
|
||
|
to.conditionId));
|
||
|
}
|
||
|
if (!Objects.equals(from.condition, to.condition)) {
|
||
|
addField(FIELD_CONDITION, new FieldDiff<>(from.condition, to.condition));
|
||
|
}
|
||
|
if (!Objects.equals(from.component, to.component)) {
|
||
|
addField(FIELD_COMPONENT, new FieldDiff<>(from.component, to.component));
|
||
|
}
|
||
|
if (!Objects.equals(from.configurationActivity, to.configurationActivity)) {
|
||
|
addField(FIELD_CONFIGURATION_ACTIVITY, new FieldDiff<>(
|
||
|
from.configurationActivity, to.configurationActivity));
|
||
|
}
|
||
|
if (!Objects.equals(from.id, to.id)) {
|
||
|
addField(FIELD_ID, new FieldDiff<>(from.id, to.id));
|
||
|
}
|
||
|
if (from.creationTime != to.creationTime) {
|
||
|
addField(FIELD_CREATION_TIME,
|
||
|
new FieldDiff<>(from.creationTime, to.creationTime));
|
||
|
}
|
||
|
if (!Objects.equals(from.enabler, to.enabler)) {
|
||
|
addField(FIELD_ENABLER, new FieldDiff<>(from.enabler, to.enabler));
|
||
|
}
|
||
|
if (!Objects.equals(from.zenPolicy, to.zenPolicy)) {
|
||
|
addField(FIELD_ZEN_POLICY, new FieldDiff<>(from.zenPolicy, to.zenPolicy));
|
||
|
}
|
||
|
if (from.modified != to.modified) {
|
||
|
addField(FIELD_MODIFIED, new FieldDiff<>(from.modified, to.modified));
|
||
|
}
|
||
|
if (!Objects.equals(from.pkg, to.pkg)) {
|
||
|
addField(FIELD_PKG, new FieldDiff<>(from.pkg, to.pkg));
|
||
|
}
|
||
|
if (android.app.Flags.modesApi()) {
|
||
|
if (!Objects.equals(from.zenDeviceEffects, to.zenDeviceEffects)) {
|
||
|
addField(FIELD_ZEN_DEVICE_EFFECTS,
|
||
|
new FieldDiff<>(from.zenDeviceEffects, to.zenDeviceEffects));
|
||
|
}
|
||
|
if (!Objects.equals(from.triggerDescription, to.triggerDescription)) {
|
||
|
addField(FIELD_TRIGGER_DESCRIPTION,
|
||
|
new FieldDiff<>(from.triggerDescription, to.triggerDescription));
|
||
|
}
|
||
|
if (from.type != to.type) {
|
||
|
addField(FIELD_TYPE, new FieldDiff<>(from.type, to.type));
|
||
|
}
|
||
|
if (from.allowManualInvocation != to.allowManualInvocation) {
|
||
|
addField(FIELD_ALLOW_MANUAL,
|
||
|
new FieldDiff<>(from.allowManualInvocation, to.allowManualInvocation));
|
||
|
}
|
||
|
if (!Objects.equals(from.iconResName, to.iconResName)) {
|
||
|
addField(FIELD_ICON_RES, new FieldDiff<>(from.iconResName, to.iconResName));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this object represents an actual diff.
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean hasDiff() {
|
||
|
return hasExistenceChange() || hasFieldDiffs();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
final StringBuilder sb = new StringBuilder("ZenRuleDiff{");
|
||
|
// If there's no diff, probably we haven't actually let this object continue existing
|
||
|
// but might as well handle this case.
|
||
|
if (!hasDiff()) {
|
||
|
sb.append("no changes");
|
||
|
}
|
||
|
|
||
|
// If added or deleted, then that's just the end of it
|
||
|
if (hasExistenceChange()) {
|
||
|
if (wasAdded()) {
|
||
|
sb.append("added");
|
||
|
} else if (wasRemoved()) {
|
||
|
sb.append("removed");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Go through all of the individual fields
|
||
|
boolean first = true;
|
||
|
for (String key : fieldNamesWithDiff()) {
|
||
|
FieldDiff diff = getDiffForField(key);
|
||
|
if (diff == null) {
|
||
|
// this shouldn't happen, but
|
||
|
continue;
|
||
|
}
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
sb.append(", ");
|
||
|
}
|
||
|
|
||
|
sb.append(key);
|
||
|
sb.append(":");
|
||
|
sb.append(diff);
|
||
|
}
|
||
|
|
||
|
if (becameActive()) {
|
||
|
if (!first) {
|
||
|
sb.append(", ");
|
||
|
}
|
||
|
sb.append("(->active)");
|
||
|
} else if (becameInactive()) {
|
||
|
if (!first) {
|
||
|
sb.append(", ");
|
||
|
}
|
||
|
sb.append("(->inactive)");
|
||
|
}
|
||
|
|
||
|
return sb.append("}").toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff indicates that this (automatic) rule became active.
|
||
|
*/
|
||
|
public boolean becameActive() {
|
||
|
// if the "to" side is true, then it became active
|
||
|
return mActiveDiff != null && mActiveDiff.to();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether this diff indicates that this (automatic) rule became inactive.
|
||
|
*/
|
||
|
public boolean becameInactive() {
|
||
|
// if the "to" side is false, then it became inactive
|
||
|
return mActiveDiff != null && !mActiveDiff.to();
|
||
|
}
|
||
|
}
|
||
|
}
|