1 /* 2 * Copyright 2021 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.extensions.internal; 18 19 import androidx.annotation.VisibleForTesting; 20 import androidx.camera.core.Logger; 21 import androidx.camera.extensions.impl.ExtensionVersionImpl; 22 23 import org.jspecify.annotations.NonNull; 24 import org.jspecify.annotations.Nullable; 25 26 /** 27 * Provides interfaces to check the extension version. 28 */ 29 public abstract class ExtensionVersion { 30 private static final String TAG = "ExtenderVersion"; 31 32 private static volatile ExtensionVersion sExtensionVersion; 33 34 /** 35 * For testing only. Inject a fake {@link ExtensionVersion}. Set it to {@code null} to unset 36 * it. 37 */ 38 @VisibleForTesting injectInstance(@ullable ExtensionVersion extensionVersion)39 public static void injectInstance(@Nullable ExtensionVersion extensionVersion) { 40 sExtensionVersion = extensionVersion; 41 } 42 getInstance()43 private static ExtensionVersion getInstance() { 44 if (sExtensionVersion != null) { 45 return sExtensionVersion; 46 } 47 synchronized (ExtensionVersion.class) { 48 if (sExtensionVersion == null) { 49 try { 50 sExtensionVersion = new VendorExtenderVersioning(); 51 } catch (NoClassDefFoundError e) { 52 Logger.d(TAG, "No versioning extender found. Falling back to default."); 53 sExtensionVersion = new DefaultExtenderVersioning(); 54 } 55 } 56 } 57 58 return sExtensionVersion; 59 } 60 61 /** 62 * Indicate the compatibility of CameraX and OEM library. 63 * 64 * @return true if OEM returned a major version is matched with the current version, false 65 * otherwise. 66 */ isExtensionVersionSupported()67 public static boolean isExtensionVersionSupported() { 68 return getInstance().getVersionObject() != null; 69 } 70 71 /** 72 * Return the Version object of the OEM library if the version is compatible with CameraX. 73 * 74 * @return a Version object which composed of the version number string that's returned from 75 * {@link ExtensionVersionImpl#checkApiVersion(String)}. 76 * <tt>null</tt> if the OEM library didn't implement the version checking method or the 77 * version is not compatible with CameraX. 78 */ getRuntimeVersion()79 public static @Nullable Version getRuntimeVersion() { 80 return getInstance().getVersionObject(); 81 } 82 isAdvancedExtenderSupported()83 public static boolean isAdvancedExtenderSupported() { 84 return getInstance().isAdvancedExtenderSupportedInternal(); 85 } 86 87 /** 88 * Check if the Runtime Version meets the minimum compatible version requirement. This implies 89 * that the runtime version is equal to or newer than the version. 90 * 91 * <p> The compatible version is comprised of the major and minor version numbers. The patch 92 * number is ignored. 93 * 94 * @param version The minimum compatible version required 95 * @return True if the Runtime version meets the minimum version requirement and False 96 * otherwise. 97 */ isMinimumCompatibleVersion(@onNull Version version)98 public static boolean isMinimumCompatibleVersion(@NonNull Version version) { 99 return ExtensionVersion.getRuntimeVersion() 100 .compareTo(version.getMajor(), version.getMinor()) >= 0; 101 } 102 103 /** 104 * Check if the Runtime Version meets the maximum compatible version requirement. This implies 105 * that the runtime version is equal to or older than the version. 106 * 107 * <p> The compatible version is comprised of the major and minor version numbers. The patch 108 * number is ignored. 109 * 110 * @param version The maximum compatible version required 111 * @return True if the Runtime version meets the maximum version requirement and False 112 * otherwise. 113 */ isMaximumCompatibleVersion(@onNull Version version)114 public static boolean isMaximumCompatibleVersion(@NonNull Version version) { 115 return ExtensionVersion.getRuntimeVersion() 116 .compareTo(version.getMajor(), version.getMinor()) <= 0; 117 } 118 isAdvancedExtenderSupportedInternal()119 abstract boolean isAdvancedExtenderSupportedInternal(); 120 121 /** 122 * @return a Version object returned from the extension implementation. 123 */ getVersionObject()124 abstract Version getVersionObject(); 125 126 /** An implementation that calls into the vendor provided implementation. */ 127 private static class VendorExtenderVersioning extends ExtensionVersion { 128 private static ExtensionVersionImpl sImpl; 129 private Version mRuntimeVersion; 130 VendorExtenderVersioning()131 VendorExtenderVersioning() { 132 if (sImpl == null) { 133 sImpl = new ExtensionVersionImpl(); 134 } 135 136 String vendorVersion = sImpl.checkApiVersion( 137 ClientVersion.getCurrentVersion().toVersionString()); 138 Version vendorVersionObj = Version.parse(vendorVersion); 139 if (vendorVersionObj != null 140 && ClientVersion.getCurrentVersion().getVersion().getMajor() 141 == vendorVersionObj.getMajor()) { 142 mRuntimeVersion = vendorVersionObj; 143 } 144 145 Logger.d(TAG, "Selected vendor runtime: " + mRuntimeVersion); 146 } 147 148 @Override getVersionObject()149 Version getVersionObject() { 150 return mRuntimeVersion; 151 } 152 153 @Override isAdvancedExtenderSupportedInternal()154 boolean isAdvancedExtenderSupportedInternal() { 155 try { 156 return sImpl.isAdvancedExtenderImplemented(); 157 } catch (NoSuchMethodError e) { 158 return false; 159 } 160 } 161 } 162 163 /** Empty implementation of ExtensionVersion which does nothing. */ 164 private static class DefaultExtenderVersioning extends ExtensionVersion { DefaultExtenderVersioning()165 DefaultExtenderVersioning() { 166 } 167 168 @Override getVersionObject()169 Version getVersionObject() { 170 return null; 171 } 172 173 @Override isAdvancedExtenderSupportedInternal()174 boolean isAdvancedExtenderSupportedInternal() { 175 return false; 176 } 177 } 178 } 179