1 /* 2 * Copyright (C) 2022 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 android.safetycenter.config; 18 19 import static android.os.Build.VERSION_CODES.TIRAMISU; 20 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; 21 22 import static java.util.Collections.unmodifiableList; 23 import static java.util.Objects.requireNonNull; 24 25 import android.annotation.NonNull; 26 import android.annotation.SystemApi; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 30 import androidx.annotation.RequiresApi; 31 32 import com.android.modules.utils.build.SdkLevel; 33 34 import java.util.ArrayList; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Objects; 38 import java.util.Set; 39 40 /** 41 * Data class used to represent the initial configuration of the Safety Center. 42 * 43 * @hide 44 */ 45 @SystemApi 46 @RequiresApi(TIRAMISU) 47 public final class SafetyCenterConfig implements Parcelable { 48 49 @NonNull 50 public static final Creator<SafetyCenterConfig> CREATOR = 51 new Creator<SafetyCenterConfig>() { 52 @Override 53 public SafetyCenterConfig createFromParcel(Parcel in) { 54 List<SafetySourcesGroup> safetySourcesGroups = 55 requireNonNull(in.createTypedArrayList(SafetySourcesGroup.CREATOR)); 56 Builder builder = new Builder(); 57 for (int i = 0; i < safetySourcesGroups.size(); i++) { 58 builder.addSafetySourcesGroup(safetySourcesGroups.get(i)); 59 } 60 return builder.build(); 61 } 62 63 @Override 64 public SafetyCenterConfig[] newArray(int size) { 65 return new SafetyCenterConfig[size]; 66 } 67 }; 68 69 @NonNull private final List<SafetySourcesGroup> mSafetySourcesGroups; 70 SafetyCenterConfig(@onNull List<SafetySourcesGroup> safetySourcesGroups)71 private SafetyCenterConfig(@NonNull List<SafetySourcesGroup> safetySourcesGroups) { 72 mSafetySourcesGroups = safetySourcesGroups; 73 } 74 75 /** 76 * Returns the list of {@link SafetySourcesGroup}s in the Safety Center configuration. 77 * 78 * <p>A Safety Center configuration contains at least one {@link SafetySourcesGroup}. 79 */ 80 @NonNull getSafetySourcesGroups()81 public List<SafetySourcesGroup> getSafetySourcesGroups() { 82 return mSafetySourcesGroups; 83 } 84 85 @Override equals(Object o)86 public boolean equals(Object o) { 87 if (this == o) return true; 88 if (!(o instanceof SafetyCenterConfig)) return false; 89 SafetyCenterConfig that = (SafetyCenterConfig) o; 90 return Objects.equals(mSafetySourcesGroups, that.mSafetySourcesGroups); 91 } 92 93 @Override hashCode()94 public int hashCode() { 95 return Objects.hash(mSafetySourcesGroups); 96 } 97 98 @Override toString()99 public String toString() { 100 return "SafetyCenterConfig{" + "mSafetySourcesGroups=" + mSafetySourcesGroups + '}'; 101 } 102 103 @Override describeContents()104 public int describeContents() { 105 return 0; 106 } 107 108 @Override writeToParcel(@onNull Parcel dest, int flags)109 public void writeToParcel(@NonNull Parcel dest, int flags) { 110 dest.writeTypedList(mSafetySourcesGroups); 111 } 112 113 /** Builder class for {@link SafetyCenterConfig}. */ 114 public static final class Builder { 115 116 private final List<SafetySourcesGroup> mSafetySourcesGroups = new ArrayList<>(); 117 118 /** Creates a {@link Builder} for a {@link SafetyCenterConfig}. */ Builder()119 public Builder() {} 120 121 /** Creates a {@link Builder} with the values from the given {@link SafetyCenterConfig}. */ 122 @RequiresApi(UPSIDE_DOWN_CAKE) Builder(@onNull SafetyCenterConfig safetyCenterConfig)123 public Builder(@NonNull SafetyCenterConfig safetyCenterConfig) { 124 if (!SdkLevel.isAtLeastU()) { 125 throw new UnsupportedOperationException( 126 "Method not supported on versions lower than UPSIDE_DOWN_CAKE"); 127 } 128 requireNonNull(safetyCenterConfig); 129 mSafetySourcesGroups.addAll(safetyCenterConfig.mSafetySourcesGroups); 130 } 131 132 /** 133 * Adds a {@link SafetySourcesGroup} to the Safety Center configuration. 134 * 135 * <p>A Safety Center configuration must contain at least one {@link SafetySourcesGroup}. 136 */ 137 @NonNull addSafetySourcesGroup(@onNull SafetySourcesGroup safetySourcesGroup)138 public Builder addSafetySourcesGroup(@NonNull SafetySourcesGroup safetySourcesGroup) { 139 mSafetySourcesGroups.add(requireNonNull(safetySourcesGroup)); 140 return this; 141 } 142 143 /** 144 * Creates the {@link SafetyCenterConfig} defined by this {@link Builder}. 145 * 146 * @throws IllegalStateException if any constraint on the Safety Center configuration is 147 * violated 148 */ 149 @NonNull build()150 public SafetyCenterConfig build() { 151 List<SafetySourcesGroup> safetySourcesGroups = 152 unmodifiableList(new ArrayList<>(mSafetySourcesGroups)); 153 if (safetySourcesGroups.isEmpty()) { 154 throw new IllegalStateException("No safety sources groups present"); 155 } 156 Set<String> safetySourceIds = new HashSet<>(); 157 Set<String> safetySourcesGroupsIds = new HashSet<>(); 158 int safetySourcesGroupsSize = safetySourcesGroups.size(); 159 for (int i = 0; i < safetySourcesGroupsSize; i++) { 160 SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i); 161 String groupId = safetySourcesGroup.getId(); 162 if (safetySourcesGroupsIds.contains(groupId)) { 163 throw new IllegalStateException( 164 "Duplicate id " + groupId + " among safety sources groups"); 165 } 166 safetySourcesGroupsIds.add(groupId); 167 List<SafetySource> safetySources = safetySourcesGroup.getSafetySources(); 168 int safetySourcesSize = safetySources.size(); 169 for (int j = 0; j < safetySourcesSize; j++) { 170 SafetySource staticSafetySource = safetySources.get(j); 171 String sourceId = staticSafetySource.getId(); 172 if (safetySourceIds.contains(sourceId)) { 173 throw new IllegalStateException( 174 "Duplicate id " + sourceId + " among safety sources"); 175 } 176 safetySourceIds.add(sourceId); 177 } 178 } 179 return new SafetyCenterConfig(safetySourcesGroups); 180 } 181 } 182 } 183