1 package org.robolectric.shadows; 2 3 import android.annotation.NonNull; 4 import android.annotation.Nullable; 5 import android.os.Build.VERSION_CODES; 6 import android.safetycenter.SafetyCenterManager; 7 import android.safetycenter.SafetyEvent; 8 import android.safetycenter.SafetySourceData; 9 import android.safetycenter.SafetySourceErrorDetails; 10 import com.google.errorprone.annotations.concurrent.GuardedBy; 11 import java.util.HashMap; 12 import java.util.HashSet; 13 import java.util.Map; 14 import java.util.Set; 15 import org.robolectric.annotation.Implementation; 16 import org.robolectric.annotation.Implements; 17 18 /** Shadow for {@link SafetyCenterManager}. */ 19 @Implements( 20 value = SafetyCenterManager.class, 21 minSdk = VERSION_CODES.TIRAMISU, 22 isInAndroidSdk = false) 23 public class ShadowSafetyCenterManager { 24 25 private final Object lock = new Object(); 26 27 @GuardedBy("lock") 28 private final Map<String, SafetySourceData> dataById = new HashMap<>(); 29 30 @GuardedBy("lock") 31 private final Map<String, SafetyEvent> eventsById = new HashMap<>(); 32 33 @GuardedBy("lock") 34 private final Map<String, SafetySourceErrorDetails> errorsById = new HashMap<>(); 35 36 @GuardedBy("lock") 37 private final Set<String> throwForId = new HashSet<>(); 38 39 @GuardedBy("lock") 40 private boolean enabled = false; 41 42 @Implementation isSafetyCenterEnabled()43 protected boolean isSafetyCenterEnabled() { 44 synchronized (lock) { 45 return enabled; 46 } 47 } 48 49 @Implementation setSafetySourceData( @onNull String safetySourceId, @Nullable SafetySourceData safetySourceData, @NonNull SafetyEvent safetyEvent)50 protected void setSafetySourceData( 51 @NonNull String safetySourceId, 52 @Nullable SafetySourceData safetySourceData, 53 @NonNull SafetyEvent safetyEvent) { 54 synchronized (lock) { 55 if (!isSafetyCenterEnabled()) { 56 return; 57 } 58 maybeThrowForId(safetySourceId); 59 dataById.put(safetySourceId, safetySourceData); 60 eventsById.put(safetySourceId, safetyEvent); 61 } 62 } 63 64 @Implementation getSafetySourceData(@onNull String safetySourceId)65 protected SafetySourceData getSafetySourceData(@NonNull String safetySourceId) { 66 synchronized (lock) { 67 if (!isSafetyCenterEnabled()) { 68 return null; 69 } 70 maybeThrowForId(safetySourceId); 71 return dataById.get(safetySourceId); 72 } 73 } 74 75 @Implementation reportSafetySourceError( @onNull String safetySourceId, @NonNull SafetySourceErrorDetails safetySourceErrorDetails)76 protected void reportSafetySourceError( 77 @NonNull String safetySourceId, @NonNull SafetySourceErrorDetails safetySourceErrorDetails) { 78 synchronized (lock) { 79 if (!isSafetyCenterEnabled()) { 80 return; 81 } 82 maybeThrowForId(safetySourceId); 83 errorsById.put(safetySourceId, safetySourceErrorDetails); 84 } 85 } 86 87 @GuardedBy("lock") maybeThrowForId(String safetySourceId)88 private void maybeThrowForId(String safetySourceId) { 89 if (throwForId.contains(safetySourceId)) { 90 throw new IllegalArgumentException(String.format("%s is invalid", safetySourceId)); 91 } 92 } 93 94 /** 95 * Sets the return value for {@link #isSafetyCenterEnabled} which also enables the {@link 96 * #setSafetySourceData} and {@link #getSafetySourceData} methods. 97 */ setSafetyCenterEnabled(boolean enabled)98 public void setSafetyCenterEnabled(boolean enabled) { 99 synchronized (lock) { 100 this.enabled = enabled; 101 } 102 } 103 104 /** 105 * Makes the APIs throw an {@link IllegalArgumentException} for the given {@code safetySourceId}. 106 */ throwOnSafetySourceId(@onNull String safetySourceId)107 public void throwOnSafetySourceId(@NonNull String safetySourceId) { 108 synchronized (lock) { 109 throwForId.add(safetySourceId); 110 } 111 } 112 113 /** 114 * Returns the {@link SafetyEvent} that was given to {@link SafetyCenterManager} the last time 115 * {@link #setSafetySourceData} was called with this {@code safetySourceId}. 116 */ getLastSafetyEvent(@onNull String safetySourceId)117 public SafetyEvent getLastSafetyEvent(@NonNull String safetySourceId) { 118 synchronized (lock) { 119 return eventsById.get(safetySourceId); 120 } 121 } 122 123 /** 124 * Returns the {@link SafetySourceErrorDetails} that was given to {@link SafetyCenterManager} the 125 * last time {@link #reportSafetySourceError} was called with this {@code safetySourceId}. 126 */ getLastSafetySourceError(@onNull String safetySourceId)127 public SafetySourceErrorDetails getLastSafetySourceError(@NonNull String safetySourceId) { 128 synchronized (lock) { 129 return errorsById.get(safetySourceId); 130 } 131 } 132 } 133