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; 18 19 import static android.os.Build.VERSION_CODES.TIRAMISU; 20 21 import static java.util.Objects.requireNonNull; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.SystemApi; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.text.TextUtils; 29 30 import androidx.annotation.RequiresApi; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.Objects; 35 36 /** 37 * The overall status of the Safety Center. 38 * 39 * @hide 40 */ 41 @SystemApi 42 @RequiresApi(TIRAMISU) 43 public final class SafetyCenterStatus implements Parcelable { 44 45 /** Indicates the overall severity level of the Safety Center is not currently known. */ 46 public static final int OVERALL_SEVERITY_LEVEL_UNKNOWN = 1000; 47 48 /** 49 * Indicates the overall safety status of the device is OK and there are no actionable issues. 50 */ 51 public static final int OVERALL_SEVERITY_LEVEL_OK = 1100; 52 53 /** Indicates the presence of safety recommendations which the user is encouraged to act on. */ 54 public static final int OVERALL_SEVERITY_LEVEL_RECOMMENDATION = 1200; 55 56 /** Indicates the presence of critical safety warnings on the device. */ 57 public static final int OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING = 1300; 58 59 /** 60 * All possible overall severity levels for the Safety Center. 61 * 62 * <p>The overall severity level is calculated from the severity level and statuses of all 63 * issues and entries in the Safety Center. 64 * 65 * @hide 66 * @see #getSeverityLevel() 67 * @see Builder#setSeverityLevel(int) 68 */ 69 @Retention(RetentionPolicy.SOURCE) 70 @IntDef( 71 prefix = "OVERALL_SEVERITY_LEVEL_", 72 value = { 73 OVERALL_SEVERITY_LEVEL_UNKNOWN, 74 OVERALL_SEVERITY_LEVEL_OK, 75 OVERALL_SEVERITY_LEVEL_RECOMMENDATION, 76 OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING, 77 }) 78 public @interface OverallSeverityLevel {} 79 80 /** Indicates that no refresh is ongoing. */ 81 public static final int REFRESH_STATUS_NONE = 0; 82 83 /** 84 * Indicates that a data fetch is ongoing, and Safety Sources are being asked for their current 85 * safety state. 86 * 87 * <p>If sources already have their safety data cached, they may provide it without triggering a 88 * process to fetch or recompute state which may be expensive and/or slow. 89 */ 90 public static final int REFRESH_STATUS_DATA_FETCH_IN_PROGRESS = 10100; 91 92 /** 93 * Indicates that a full rescan is ongoing, and Safety Sources are being asked to fetch fresh 94 * data for their safety state. 95 * 96 * <p>The term "fresh" here means that the sources should ensure that the safety data is 97 * accurate as possible at the time of providing it to Safety Center, even if it involves 98 * performing an expensive and/or slow process. 99 */ 100 public static final int REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS = 10200; 101 102 /** 103 * All possible refresh states for the Safety Center. 104 * 105 * @hide 106 * @see #getRefreshStatus() 107 * @see Builder#setRefreshStatus(int) 108 */ 109 @Retention(RetentionPolicy.SOURCE) 110 @IntDef( 111 prefix = "REFRESH_STATUS_", 112 value = { 113 REFRESH_STATUS_NONE, 114 REFRESH_STATUS_DATA_FETCH_IN_PROGRESS, 115 REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS, 116 }) 117 public @interface RefreshStatus {} 118 119 @NonNull 120 public static final Creator<SafetyCenterStatus> CREATOR = 121 new Creator<SafetyCenterStatus>() { 122 @Override 123 public SafetyCenterStatus createFromParcel(Parcel in) { 124 CharSequence title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 125 CharSequence summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 126 return new Builder(title, summary) 127 .setSeverityLevel(in.readInt()) 128 .setRefreshStatus(in.readInt()) 129 .build(); 130 } 131 132 @Override 133 public SafetyCenterStatus[] newArray(int size) { 134 return new SafetyCenterStatus[size]; 135 } 136 }; 137 138 @NonNull private final CharSequence mTitle; 139 @NonNull private final CharSequence mSummary; 140 @OverallSeverityLevel private final int mSeverityLevel; 141 @RefreshStatus private final int mRefreshStatus; 142 SafetyCenterStatus( @onNull CharSequence title, @NonNull CharSequence summary, @OverallSeverityLevel int severityLevel, @RefreshStatus int refreshStatus)143 private SafetyCenterStatus( 144 @NonNull CharSequence title, 145 @NonNull CharSequence summary, 146 @OverallSeverityLevel int severityLevel, 147 @RefreshStatus int refreshStatus) { 148 mTitle = title; 149 mSummary = summary; 150 mSeverityLevel = severityLevel; 151 mRefreshStatus = refreshStatus; 152 } 153 154 /** Returns the title which describes the overall safety state of the device. */ 155 @NonNull getTitle()156 public CharSequence getTitle() { 157 return mTitle; 158 } 159 160 /** Returns the summary text which adds detail to the overall safety state of the device. */ 161 @NonNull getSummary()162 public CharSequence getSummary() { 163 return mSummary; 164 } 165 166 /** Returns the current {@link OverallSeverityLevel} of the Safety Center. */ 167 @OverallSeverityLevel getSeverityLevel()168 public int getSeverityLevel() { 169 return mSeverityLevel; 170 } 171 172 /** Returns the current {@link RefreshStatus} of the Safety Center */ 173 @RefreshStatus getRefreshStatus()174 public int getRefreshStatus() { 175 return mRefreshStatus; 176 } 177 178 @Override equals(Object o)179 public boolean equals(Object o) { 180 if (this == o) return true; 181 if (!(o instanceof SafetyCenterStatus)) return false; 182 SafetyCenterStatus that = (SafetyCenterStatus) o; 183 return mSeverityLevel == that.mSeverityLevel 184 && mRefreshStatus == that.mRefreshStatus 185 && TextUtils.equals(mTitle, that.mTitle) 186 && TextUtils.equals(mSummary, that.mSummary); 187 } 188 189 @Override hashCode()190 public int hashCode() { 191 return Objects.hash(mTitle, mSummary, mSeverityLevel, mRefreshStatus); 192 } 193 194 @Override toString()195 public String toString() { 196 return "SafetyCenterStatus{" 197 + "mTitle=" 198 + mTitle 199 + ", mSummary=" 200 + mSummary 201 + ", mSeverityLevel=" 202 + mSeverityLevel 203 + ", mRefreshStatus=" 204 + mRefreshStatus 205 + '}'; 206 } 207 208 @Override describeContents()209 public int describeContents() { 210 return 0; 211 } 212 213 @Override writeToParcel(@onNull Parcel dest, int flags)214 public void writeToParcel(@NonNull Parcel dest, int flags) { 215 TextUtils.writeToParcel(mTitle, dest, flags); 216 TextUtils.writeToParcel(mSummary, dest, flags); 217 dest.writeInt(mSeverityLevel); 218 dest.writeInt(mRefreshStatus); 219 } 220 221 /** Builder class for {@link SafetyCenterStatus}. */ 222 public static final class Builder { 223 224 @NonNull private CharSequence mTitle; 225 @NonNull private CharSequence mSummary; 226 @OverallSeverityLevel private int mSeverityLevel = OVERALL_SEVERITY_LEVEL_UNKNOWN; 227 @RefreshStatus private int mRefreshStatus = REFRESH_STATUS_NONE; 228 229 /** 230 * Creates a new {@link Builder} for a {@link SafetyCenterStatus}. 231 * 232 * @param title an overall title for the status 233 * @param summary a summary for the status 234 */ Builder(@onNull CharSequence title, @NonNull CharSequence summary)235 public Builder(@NonNull CharSequence title, @NonNull CharSequence summary) { 236 mTitle = requireNonNull(title); 237 mSummary = requireNonNull(summary); 238 } 239 240 /** Creates a {@link Builder} with the values from the given {@link SafetyCenterStatus}. */ Builder(@onNull SafetyCenterStatus safetyCenterStatus)241 public Builder(@NonNull SafetyCenterStatus safetyCenterStatus) { 242 mTitle = safetyCenterStatus.mTitle; 243 mSummary = safetyCenterStatus.mSummary; 244 mSeverityLevel = safetyCenterStatus.mSeverityLevel; 245 mRefreshStatus = safetyCenterStatus.mRefreshStatus; 246 } 247 248 /** Sets the title for this status. */ 249 @NonNull setTitle(@onNull CharSequence title)250 public Builder setTitle(@NonNull CharSequence title) { 251 mTitle = requireNonNull(title); 252 return this; 253 } 254 255 /** Sets the summary text for this status. */ 256 @NonNull setSummary(@onNull CharSequence summary)257 public Builder setSummary(@NonNull CharSequence summary) { 258 mSummary = requireNonNull(summary); 259 return this; 260 } 261 262 /** 263 * Sets the {@link OverallSeverityLevel} of this status. Defaults to {@link 264 * #OVERALL_SEVERITY_LEVEL_UNKNOWN}. 265 */ 266 @NonNull setSeverityLevel(@verallSeverityLevel int severityLevel)267 public Builder setSeverityLevel(@OverallSeverityLevel int severityLevel) { 268 mSeverityLevel = validateOverallSeverityLevel(severityLevel); 269 return this; 270 } 271 272 /** 273 * Sets the {@link RefreshStatus} of this status. Defaults to {@link #REFRESH_STATUS_NONE}. 274 */ 275 @NonNull setRefreshStatus(@efreshStatus int refreshStatus)276 public Builder setRefreshStatus(@RefreshStatus int refreshStatus) { 277 mRefreshStatus = validateRefreshStatus(refreshStatus); 278 return this; 279 } 280 281 /** Creates the {@link SafetyCenterStatus} defined by this {@link Builder}. */ 282 @NonNull build()283 public SafetyCenterStatus build() { 284 return new SafetyCenterStatus(mTitle, mSummary, mSeverityLevel, mRefreshStatus); 285 } 286 } 287 288 @OverallSeverityLevel validateOverallSeverityLevel(int value)289 private static int validateOverallSeverityLevel(int value) { 290 switch (value) { 291 case OVERALL_SEVERITY_LEVEL_UNKNOWN: 292 case OVERALL_SEVERITY_LEVEL_OK: 293 case OVERALL_SEVERITY_LEVEL_RECOMMENDATION: 294 case OVERALL_SEVERITY_LEVEL_CRITICAL_WARNING: 295 return value; 296 default: 297 } 298 throw new IllegalArgumentException( 299 "Unexpected OverallSeverityLevel for SafetyCenterStatus: " + value); 300 } 301 302 @RefreshStatus validateRefreshStatus(int value)303 private static int validateRefreshStatus(int value) { 304 switch (value) { 305 case REFRESH_STATUS_NONE: 306 case REFRESH_STATUS_DATA_FETCH_IN_PROGRESS: 307 case REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS: 308 return value; 309 default: 310 } 311 throw new IllegalArgumentException( 312 "Unexpected RefreshStatus for SafetyCenterStatus: " + value); 313 } 314 } 315