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.xr.runtime.internal 18 19 import androidx.annotation.IntDef 20 import androidx.annotation.RestrictTo 21 import java.util.Objects 22 import java.util.function.Consumer 23 24 /** 25 * Interface for updating the background image/geometry and passthrough settings. 26 * 27 * <p>The application can set either / both a skybox and a glTF for geometry, then toggle their 28 * visibility by enabling or disabling passthrough. The skybox and geometry will be remembered 29 * across passthrough mode changes. 30 */ 31 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) 32 public interface SpatialEnvironment { 33 /** 34 * Gets the current passthrough opacity value between 0 and 1 where 0.0f means no passthrough, 35 * and 1.0f means full passthrough. 36 * 37 * <p>This value can be overwritten by user-enabled or system-enabled passthrough and will not 38 * always match the opacity value returned by [getPassthroughOpacityPreference]. 39 */ 40 public val currentPassthroughOpacity: Float 41 42 /** 43 * Gets the preferred spatial environment for the application. 44 * 45 * <p>The returned value is always what was most recently supplied to 46 * [setSpatialEnvironmentPreference], or null if no preference has been set. 47 * 48 * <p>See [isSpatialEnvironmentPreferenceActive] or the [OnSpatialEnvironmentChangedListener] 49 * events to know when this preference becomes active. 50 */ 51 public val spatialEnvironmentPreference: SpatialEnvironmentPreference? 52 53 /** 54 * Gets the last passthrough opacity requested through [setPassthroughOpacityPreference]. 55 * 56 * <p>This may be different from the actual current state returned by 57 * [getCurrentPassthroughOpacity], but it should be applied as soon as the 58 * [SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL] capability is gained. Defaults 59 * to null, if [setPassthroughOpacityPreference] was never called. 60 * 61 * <p>If set to null, the passthrough opacity will default to the user preference managed 62 * through the system. 63 */ 64 public val passthroughOpacityPreference: Float? 65 66 /** 67 * Notifies an application when the passthrough state changes, such as when the application 68 * enters or exits passthrough or when the passthrough opacity changes. This [listener] will be 69 * called on the Application's UI thread. 70 */ addOnPassthroughOpacityChangedListenernull71 public fun addOnPassthroughOpacityChangedListener(listener: Consumer<Float>) 72 73 /** Remove a listener previously added by [addOnPassthroughOpacityChangedListener]. */ 74 public fun removeOnPassthroughOpacityChangedListener(listener: Consumer<Float>) 75 76 /** 77 * Returns true if the environment set by [setSpatialEnvironmentPreference] is active. 78 * 79 * <p>Spatial environment preference set through [setSpatialEnvironmentPreference] are shown 80 * when this is true, but passthrough or other objects in the scene could partially or totally 81 * occlude them. When this is false, the default system environment will be active instead. 82 */ 83 public fun isSpatialEnvironmentPreferenceActive(): Boolean 84 85 /** 86 * Sets the preferred spatial environment for the application. 87 * 88 * <p>Note that this method only sets a preference and does not cause an immediate change unless 89 * [isSpatialEnvironmentPreferenceActive] is already true. Once the device enters a state where 90 * the XR background can be changed and the 91 * [SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENTS] capability is available, the 92 * preferred spatial environment for the application will be automatically displayed. 93 * 94 * <p>Setting the preference to null will disable the preferred spatial environment for the 95 * application, meaning the default system environment will be displayed instead. 96 * 97 * <p>If the given [SpatialEnvironmentPreference] is not null, but all of its properties are 98 * null, then the spatial environment will consist of a black skybox and no geometry 99 * [isSpatialEnvironmentPreferenceActive] is true. 100 * 101 * <p>Changes to the Environment state will be notified via the 102 * [OnSpatialEnvironmentChangedListener]. 103 */ 104 public fun setSpatialEnvironmentPreference( 105 preference: SpatialEnvironmentPreference? 106 ): @SetSpatialEnvironmentPreferenceResult Int 107 108 /** 109 * Sets the preference for passthrough state by requesting a change in passthrough opacity. 110 * 111 * <p>Passthrough visibility cannot be set directly to on/off modes. Instead, a desired 112 * passthrough opacity value between 0.0f and 1.0f can be requested which will dictate which 113 * mode is used. A passthrough opacity within 0.01f of 0.0f will disable passthrough, and will 114 * be returned as 0.0f by [getPassthroughOpacityPreference]. An opacity value within 0.01f of 115 * 1.0f will enable full passthrough and it will be returned as 1.0f by 116 * [getPassthroughOpacityPreference]. Any other value in the range will result in a 117 * semi-transparent passthrough. 118 * 119 * <p>Requesting to set passthrough opacity to a value that is not in the range of 0.0f to 1.0f 120 * will result in the value getting clamped to 0.0f or 1.0f depending on which one is closer. 121 * 122 * <p>If the value is set to null, the opacity will be managed by the system. 123 * 124 * <p>Requests to change opacity are only immediately attempted to be honored if the activity 125 * has the [SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL] capability. When the 126 * request is honored, this returns [SetPassthroughOpacityPreferenceChangeApplied]. When the 127 * activity does not have the capability to control the passthrough state, this returns 128 * [SetPassthroughOpacityPreferenceChangePending] to indicate that the application passthrough 129 * opacity preference has been set and is pending to be automatically applied when the app 130 * regains capabilities to control passthrough state. 131 * 132 * <p>When passthrough state changes, whether due to this request succeeding or due to any other 133 * system or user initiated change, [OnPassthroughOpacityChangedListener] will be notified. 134 */ 135 public fun setPassthroughOpacityPreference( 136 passthroughOpacityPreference: Float? 137 ): @SetPassthroughOpacityPreferenceResult Int 138 139 /** 140 * Notifies an application whether or not the preferred spatial environment for the application 141 * is active. 142 * 143 * <p>The environment will try to transition to the application environment when a non-null 144 * preference is set through [setSpatialEnvironmentPreference] and the application has the 145 * [SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENTS] capability. The environment 146 * preferences will otherwise not be active. 147 * 148 * <p>The listener consumes a boolean value that is true if the environment preference is active 149 * when the listener is notified. 150 * 151 * <p>This listener will be invoked on the Application's UI thread. 152 */ 153 public fun addOnSpatialEnvironmentChangedListener(listener: Consumer<Boolean>) 154 155 /** Remove a listener previously added by [addOnSpatialEnvironmentChangedListener]. */ 156 public fun removeOnSpatialEnvironmentChangedListener(listener: Consumer<Boolean>) 157 158 /** Result values for calls to SpatialEnvironment.setPassthroughOpacityPreference */ 159 @IntDef( 160 SetPassthroughOpacityPreferenceResult.CHANGE_APPLIED, 161 SetPassthroughOpacityPreferenceResult.CHANGE_PENDING, 162 ) 163 @Target(AnnotationTarget.TYPE) 164 @Retention(AnnotationRetention.SOURCE) 165 @Suppress("PublicTypedef") 166 public annotation class SetPassthroughOpacityPreferenceResult { 167 public companion object { 168 /** 169 * The call to [setPassthroughOpacityPreference] succeeded and should now be visible. 170 */ 171 public const val CHANGE_APPLIED: Int = 0 172 /** 173 * The preference has been set, but will be applied only when the 174 * [SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL] is acquired 175 */ 176 public const val CHANGE_PENDING: Int = 1 177 } 178 } 179 180 /** Result values for calls to SpatialEnvironment.setSpatialEnvironmentPreference */ 181 @IntDef( 182 SetSpatialEnvironmentPreferenceResult.CHANGE_APPLIED, 183 SetSpatialEnvironmentPreferenceResult.CHANGE_PENDING, 184 ) 185 @Target(AnnotationTarget.TYPE) 186 @Retention(AnnotationRetention.SOURCE) 187 @Suppress("PublicTypedef") 188 public annotation class SetSpatialEnvironmentPreferenceResult { 189 public companion object { 190 /** 191 * The call to [setSpatialEnvironmentPreference] succeeded and should now be visible. 192 */ 193 public const val CHANGE_APPLIED: Int = 0 194 /** 195 * The call to [setSpatialEnvironmentPreference] successfully applied the preference, 196 * but it is not immediately visible due to requesting a state change while the activity 197 * does not have the [SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENTS] 198 * capability to control the app environment state. The preference was still set and 199 * will be applied when the capability is gained. 200 */ 201 public const val CHANGE_PENDING: Int = 1 202 } 203 } 204 205 /** 206 * A class that represents the user's preferred spatial environment. 207 * 208 * @param geometry the preferred geometry for the environment based on a pre-loaded glTF model. 209 * If null, there will be no geometry. 210 * @param skybox the preferred skybox for the environment based on a pre-loaded EXR Image. If 211 * null, it will be all black. 212 * @param geometryMaterial the material to override a given mesh in the geometry. If null, the 213 * material will not override any mesh. 214 * @param geometryMeshName the name of the mesh to override with the material. If null, the 215 * material will not override any mesh. 216 * @param geometryAnimationName the name of the animation to play on the geometry. If null, the 217 * geometry will not play any animation. Note that the animation will be played in loop. 218 */ 219 public class SpatialEnvironmentPreference 220 @JvmOverloads 221 constructor( 222 public val skybox: ExrImageResource?, 223 public val geometry: GltfModelResource?, 224 public val geometryMaterial: MaterialResource? = null, 225 public val geometryMeshName: String? = null, 226 public val geometryAnimationName: String? = null, 227 ) { equalsnull228 override fun equals(other: Any?): Boolean { 229 if (this === other) return true 230 if (other !is SpatialEnvironmentPreference) return false 231 232 return skybox == other.skybox && 233 geometry == other.geometry && 234 geometryMaterial == other.geometryMaterial && 235 geometryMeshName == other.geometryMeshName && 236 geometryAnimationName == other.geometryAnimationName 237 } 238 hashCodenull239 override fun hashCode(): Int { 240 return Objects.hash(skybox, geometry) 241 } 242 } 243 } 244