1 /* 2 * Copyright 2024 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 androidx.camera.core.impl; 18 19 import static java.util.Collections.emptySet; 20 import static java.util.Collections.unmodifiableSet; 21 22 import org.jspecify.annotations.NonNull; 23 import org.jspecify.annotations.Nullable; 24 25 import java.util.HashSet; 26 import java.util.Objects; 27 import java.util.Set; 28 29 /** 30 * Manages device/camera-specific quirks (workarounds or customizations) for CameraX. 31 * 32 * <p>{@link Quirk}s are used to handle variations in device behavior or capabilities that may 33 * affect CameraX functionality. This class allows for fine-grained control over which quirks are 34 * enabled or disabled. 35 * 36 * <p>Key Features 37 * <ul> 38 * <li>Default Behavior: Configure whether quirks should be enabled by default if the 39 * device natively exhibits them.</li> 40 * <li>Force Enable/Disable: Explicitly force specific quirks to be enabled or disabled, 41 * overriding the default behavior.</li> 42 * </ul> 43 */ 44 public class QuirkSettings { 45 46 private final boolean mEnabledWhenDeviceHasQuirk; 47 private final Set<Class<? extends Quirk>> mForceEnabledQuirks; 48 private final Set<Class<? extends Quirk>> mForceDisabledQuirks; 49 50 /** 51 * Private constructor for building `QuirkSettings` instances. 52 * 53 * @param enabledWhenDeviceHasQuirk Whether to enable quirks if the device natively exhibits 54 * the quirk. 55 * @param forceEnabledQuirks The set of quirks to be force-enabled. 56 * @param forceDisabledQuirks The set of quirks to be force-disabled. 57 */ QuirkSettings(boolean enabledWhenDeviceHasQuirk, @Nullable Set<Class<? extends Quirk>> forceEnabledQuirks, @Nullable Set<Class<? extends Quirk>> forceDisabledQuirks)58 private QuirkSettings(boolean enabledWhenDeviceHasQuirk, 59 @Nullable Set<Class<? extends Quirk>> forceEnabledQuirks, 60 @Nullable Set<Class<? extends Quirk>> forceDisabledQuirks) { 61 mEnabledWhenDeviceHasQuirk = enabledWhenDeviceHasQuirk; 62 mForceEnabledQuirks = forceEnabledQuirks == null ? emptySet() : new HashSet<>( 63 forceEnabledQuirks); 64 mForceDisabledQuirks = forceDisabledQuirks == null ? emptySet() : new HashSet<>( 65 forceDisabledQuirks); 66 } 67 68 /** 69 * Creates a QuirkSettings instance with default behavior, enabling all quirks if the device 70 * natively exhibits the quirk. 71 * 72 * @return A QuirkSettings instance with default behavior, enabling all quirks if the device 73 * natively exhibits the quirk. 74 */ withDefaultBehavior()75 public static @NonNull QuirkSettings withDefaultBehavior() { 76 return new QuirkSettings.Builder().setEnabledWhenDeviceHasQuirk(true).build(); 77 } 78 79 /** 80 * Creates a QuirkSettings instance with all quirks disabled. 81 * 82 * @return A QuirkSettings instance with all quirks disabled. 83 */ withAllQuirksDisabled()84 public static @NonNull QuirkSettings withAllQuirksDisabled() { 85 return new QuirkSettings.Builder().setEnabledWhenDeviceHasQuirk(false).build(); 86 } 87 88 /** 89 * Creates a QuirkSettings instance with specific quirks force-enabled. 90 * 91 * @param quirks The quirks to force-enable. 92 * @return A new QuirkSettings instance with the specified quirks force-enabled. 93 */ withQuirksForceEnabled( @onNull Set<Class<? extends Quirk>> quirks)94 public static @NonNull QuirkSettings withQuirksForceEnabled( 95 @NonNull Set<Class<? extends Quirk>> quirks) { 96 return new QuirkSettings.Builder().forceEnableQuirks(quirks).build(); 97 } 98 99 /** 100 * Creates a QuirkSettings instance with specific quirks force-disabled. 101 * 102 * @param quirks The quirks to force-disable. 103 * @return A new QuirkSettings instance with the specified quirks force-disabled. 104 */ withQuirksForceDisabled( @onNull Set<Class<? extends Quirk>> quirks)105 public static @NonNull QuirkSettings withQuirksForceDisabled( 106 @NonNull Set<Class<? extends Quirk>> quirks) { 107 return new QuirkSettings.Builder().forceDisableQuirks(quirks).build(); 108 } 109 110 /** 111 * Gets whether quirks should be enabled if the device natively exhibits the quirk. 112 * 113 * @return {@code true} if quirks should be enabled, {@code false} otherwise. 114 */ isEnabledWhenDeviceHasQuirk()115 public boolean isEnabledWhenDeviceHasQuirk() { 116 return mEnabledWhenDeviceHasQuirk; 117 } 118 119 /** 120 * Gets the set of quirks that are force-enabled, regardless of device behavior. 121 * 122 * @return An unmodifiable set containing the names of force-enabled quirks. 123 */ getForceEnabledQuirks()124 public @NonNull Set<Class<? extends Quirk>> getForceEnabledQuirks() { 125 return unmodifiableSet(mForceEnabledQuirks); 126 } 127 128 /** 129 * Gets the set of quirks that are force-disabled, regardless of device behavior. 130 * 131 * @return An unmodifiable set containing the names of force-disabled quirks. 132 */ getForceDisabledQuirks()133 public @NonNull Set<Class<? extends Quirk>> getForceDisabledQuirks() { 134 return unmodifiableSet(mForceDisabledQuirks); 135 } 136 137 /** 138 * Determines whether a specific quirk should be enabled based on these settings and whether 139 * the device natively exhibits the quirk. 140 * 141 * <p>If a quirk is in both the force-enabled and force-disabled sets, it will be enabled. 142 * 143 * @param quirk The quirk class to check. 144 * @param deviceHasQuirk Whether the device natively exhibits the quirk. 145 * @return true if the quirk should be enabled, false otherwise. 146 */ shouldEnableQuirk(@onNull Class<? extends Quirk> quirk, boolean deviceHasQuirk)147 public boolean shouldEnableQuirk(@NonNull Class<? extends Quirk> quirk, 148 boolean deviceHasQuirk) { 149 if (mForceEnabledQuirks.contains(quirk)) { 150 return true; 151 } else if (mForceDisabledQuirks.contains(quirk)) { 152 return false; 153 } else { 154 return mEnabledWhenDeviceHasQuirk && deviceHasQuirk; 155 } 156 } 157 158 @Override equals(@ullable Object obj)159 public boolean equals(@Nullable Object obj) { 160 if (!(obj instanceof QuirkSettings)) { 161 return false; 162 } 163 if (this == obj) { 164 return true; 165 } 166 QuirkSettings other = (QuirkSettings) obj; 167 return mEnabledWhenDeviceHasQuirk == other.mEnabledWhenDeviceHasQuirk 168 && Objects.equals(mForceEnabledQuirks, other.mForceEnabledQuirks) 169 && Objects.equals(mForceDisabledQuirks, other.mForceDisabledQuirks); 170 } 171 172 @Override hashCode()173 public int hashCode() { 174 return Objects.hash(mEnabledWhenDeviceHasQuirk, mForceEnabledQuirks, mForceDisabledQuirks); 175 } 176 177 @Override toString()178 public @NonNull String toString() { 179 return "QuirkSettings{" 180 + "enabledWhenDeviceHasQuirk=" + mEnabledWhenDeviceHasQuirk 181 + ", forceEnabledQuirks=" + mForceEnabledQuirks 182 + ", forceDisabledQuirks=" + mForceDisabledQuirks 183 + '}'; 184 } 185 186 /** 187 * Builder class for constructing {@link QuirkSettings} instances. 188 */ 189 public static class Builder { 190 private boolean mEnabledWhenDeviceHasQuirk = true; 191 private Set<Class<? extends Quirk>> mForceEnabledQuirks; 192 private Set<Class<? extends Quirk>> mForceDisabledQuirks; 193 194 /** 195 * Sets whether to enable quirks if the device natively exhibits the quirk. 196 */ setEnabledWhenDeviceHasQuirk(boolean enabled)197 public @NonNull Builder setEnabledWhenDeviceHasQuirk(boolean enabled) { 198 mEnabledWhenDeviceHasQuirk = enabled; 199 return this; 200 } 201 202 /** 203 * Forces the specified quirks to be enabled, regardless of other settings. 204 */ forceEnableQuirks(@onNull Set<Class<? extends Quirk>> quirks)205 public @NonNull Builder forceEnableQuirks(@NonNull Set<Class<? extends Quirk>> quirks) { 206 mForceEnabledQuirks = new HashSet<>(quirks); 207 return this; 208 } 209 210 /** 211 * Forces the specified quirks to be disabled, regardless of other settings. 212 */ forceDisableQuirks(@onNull Set<Class<? extends Quirk>> quirks)213 public @NonNull Builder forceDisableQuirks(@NonNull Set<Class<? extends Quirk>> quirks) { 214 mForceDisabledQuirks = new HashSet<>(quirks); 215 return this; 216 } 217 218 /** 219 * Builds a new {@link QuirkSettings} instance with the configured options. 220 * 221 * @return A new `QuirkSettings` instance. 222 */ build()223 public @NonNull QuirkSettings build() { 224 return new QuirkSettings(mEnabledWhenDeviceHasQuirk, mForceEnabledQuirks, 225 mForceDisabledQuirks); 226 } 227 } 228 } 229