1 /* 2 * Copyright 2023 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.window 18 19 import androidx.annotation.IntRange 20 import androidx.annotation.RestrictTo 21 import androidx.window.core.ExtensionsUtil 22 23 /** 24 * This class provides information about the extension SDK versions for window features present on 25 * this device. Use [extensionVersion] to get the version of the extension. The extension version 26 * advances as the platform evolves and new APIs are added, so is suitable to use for determining 27 * API availability at runtime. 28 * 29 * Window Manager Jetpack APIs that require window SDK extensions support are denoted with 30 * [RequiresWindowSdkExtension]. The caller must check whether the device's extension version is 31 * greater than or equal to the minimum level reported in [RequiresWindowSdkExtension]. 32 * 33 * @sample androidx.window.samples.checkWindowSdkExtensionsVersion 34 */ 35 abstract class WindowSdkExtensions @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) constructor() { 36 37 /** 38 * Reports the device's extension version 39 * 40 * When Window SDK Extensions is not present on the device, the extension version will be 0. 41 */ 42 @get:IntRange(from = 0) open val extensionVersion: Int = ExtensionsUtil.safeVendorApiLevel 43 44 /** 45 * Checks the [extensionVersion] and throws [UnsupportedOperationException] if the minimum 46 * [version] is not satisfied. 47 * 48 * @param version The minimum required extension version of the targeting API. 49 * @throws UnsupportedOperationException if the minimum [version] is not satisfied. 50 */ requireExtensionVersionnull51 internal fun requireExtensionVersion(@IntRange(from = 1) version: Int) { 52 if (extensionVersion < version) { 53 throw UnsupportedOperationException( 54 "This API requires extension version " + 55 "$version, but the device is on $extensionVersion" 56 ) 57 } 58 } 59 60 /** 61 * Checks the [extensionVersion] and throws [UnsupportedOperationException] if the version is 62 * not in the [range]. 63 * 64 * This is useful to provide compatibility for APIs updated in 2+ but deprecated in latest 65 * version. 66 * 67 * @param range the required extension range of the targeting API. 68 * @throws UnsupportedOperationException if the required [range] is not satisfied. 69 */ requireExtensionVersionnull70 internal fun requireExtensionVersion(range: kotlin.ranges.IntRange) { 71 if (extensionVersion !in range) { 72 throw UnsupportedOperationException( 73 "This API requires extension version " + 74 "$range, but the device is on $extensionVersion" 75 ) 76 } 77 } 78 79 companion object { 80 /** Returns a [WindowSdkExtensions] instance. */ 81 @JvmStatic getInstancenull82 fun getInstance(): WindowSdkExtensions { 83 return decorator.decorate(object : WindowSdkExtensions() {}) 84 } 85 86 private var decorator: WindowSdkExtensionsDecorator = EmptyDecoratorWindowSdk 87 88 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) overrideDecoratornull89 fun overrideDecorator(overridingDecorator: WindowSdkExtensionsDecorator) { 90 decorator = overridingDecorator 91 } 92 93 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) resetnull94 fun reset() { 95 decorator = EmptyDecoratorWindowSdk 96 } 97 } 98 } 99 100 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 101 interface WindowSdkExtensionsDecorator { 102 /** Returns a [WindowSdkExtensions] instance. */ decoratenull103 fun decorate(windowSdkExtensions: WindowSdkExtensions): WindowSdkExtensions 104 } 105 106 private object EmptyDecoratorWindowSdk : WindowSdkExtensionsDecorator { 107 override fun decorate(windowSdkExtensions: WindowSdkExtensions): WindowSdkExtensions = 108 windowSdkExtensions 109 } 110