1 /* 2 * Copyright (C) 2015 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 package com.android.dialer.compat; 17 18 import android.os.Build; 19 import android.support.annotation.Nullable; 20 import android.text.TextUtils; 21 import android.util.Log; 22 import java.lang.reflect.InvocationTargetException; 23 24 public final class CompatUtils { 25 26 private static final String TAG = CompatUtils.class.getSimpleName(); 27 28 /** PrioritizedMimeType is added in API level 23. */ hasPrioritizedMimeType()29 public static boolean hasPrioritizedMimeType() { 30 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M; 31 } 32 33 /** 34 * Determines if this version is compatible with multi-SIM and the phone account APIs. Can also 35 * force the version to be lower through SdkVersionOverride. 36 * 37 * @return {@code true} if multi-SIM capability is available, {@code false} otherwise. 38 */ isMSIMCompatible()39 public static boolean isMSIMCompatible() { 40 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) 41 >= Build.VERSION_CODES.LOLLIPOP_MR1; 42 } 43 44 /** 45 * Determines if this version is compatible with video calling. Can also force the version to be 46 * lower through SdkVersionOverride. 47 * 48 * @return {@code true} if video calling is allowed, {@code false} otherwise. 49 */ isVideoCompatible()50 public static boolean isVideoCompatible() { 51 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M; 52 } 53 54 /** 55 * Determines if this version is capable of using presence checking for video calling. Support for 56 * video call presence indication is added in SDK 24. 57 * 58 * @return {@code true} if video presence checking is allowed, {@code false} otherwise. 59 */ isVideoPresenceCompatible()60 public static boolean isVideoPresenceCompatible() { 61 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) > Build.VERSION_CODES.M; 62 } 63 64 /** 65 * Determines if this version is compatible with call subject. Can also force the version to be 66 * lower through SdkVersionOverride. 67 * 68 * @return {@code true} if call subject is a feature on this device, {@code false} otherwise. 69 */ isCallSubjectCompatible()70 public static boolean isCallSubjectCompatible() { 71 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M; 72 } 73 74 /** 75 * Determines if this version is compatible with a default dialer. Can also force the version to 76 * be lower through {@link SdkVersionOverride}. 77 * 78 * @return {@code true} if default dialer is a feature on this device, {@code false} otherwise. 79 */ isDefaultDialerCompatible()80 public static boolean isDefaultDialerCompatible() { 81 return isMarshmallowCompatible(); 82 } 83 84 /** 85 * Determines if this version is compatible with Lollipop Mr1-specific APIs. Can also force the 86 * version to be lower through SdkVersionOverride. 87 * 88 * @return {@code true} if runtime sdk is compatible with Lollipop MR1, {@code false} otherwise. 89 */ isLollipopMr1Compatible()90 public static boolean isLollipopMr1Compatible() { 91 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP_MR1) 92 >= Build.VERSION_CODES.LOLLIPOP_MR1; 93 } 94 95 /** 96 * Determines if this version is compatible with Marshmallow-specific APIs. Can also force the 97 * version to be lower through SdkVersionOverride. 98 * 99 * @return {@code true} if runtime sdk is compatible with Marshmallow, {@code false} otherwise. 100 */ isMarshmallowCompatible()101 public static boolean isMarshmallowCompatible() { 102 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) >= Build.VERSION_CODES.M; 103 } 104 105 /** 106 * Determines if the given class is available. Can be used to check if system apis exist at 107 * runtime. 108 * 109 * @param className the name of the class to look for. 110 * @return {@code true} if the given class is available, {@code false} otherwise or if className 111 * is empty. 112 */ isClassAvailable(@ullable String className)113 public static boolean isClassAvailable(@Nullable String className) { 114 if (TextUtils.isEmpty(className)) { 115 return false; 116 } 117 try { 118 Class.forName(className); 119 return true; 120 } catch (ClassNotFoundException e) { 121 return false; 122 } catch (Throwable t) { 123 Log.e( 124 TAG, 125 "Unexpected exception when checking if class:" + className + " exists at " + "runtime", 126 t); 127 return false; 128 } 129 } 130 131 /** 132 * Determines if the given class's method is available to call. Can be used to check if system 133 * apis exist at runtime. 134 * 135 * @param className the name of the class to look for 136 * @param methodName the name of the method to look for 137 * @param parameterTypes the needed parameter types for the method to look for 138 * @return {@code true} if the given class is available, {@code false} otherwise or if className 139 * or methodName are empty. 140 */ isMethodAvailable( @ullable String className, @Nullable String methodName, Class<?>... parameterTypes)141 public static boolean isMethodAvailable( 142 @Nullable String className, @Nullable String methodName, Class<?>... parameterTypes) { 143 if (TextUtils.isEmpty(className) || TextUtils.isEmpty(methodName)) { 144 return false; 145 } 146 147 try { 148 Class.forName(className).getMethod(methodName, parameterTypes); 149 return true; 150 } catch (ClassNotFoundException | NoSuchMethodException e) { 151 Log.v(TAG, "Could not find method: " + className + "#" + methodName); 152 return false; 153 } catch (Throwable t) { 154 Log.e( 155 TAG, 156 "Unexpected exception when checking if method: " 157 + className 158 + "#" 159 + methodName 160 + " exists at runtime", 161 t); 162 return false; 163 } 164 } 165 166 /** 167 * Invokes a given class's method using reflection. Can be used to call system apis that exist at 168 * runtime but not in the SDK. 169 * 170 * @param instance The instance of the class to invoke the method on. 171 * @param methodName The name of the method to invoke. 172 * @param parameterTypes The needed parameter types for the method. 173 * @param parameters The parameter values to pass into the method. 174 * @return The result of the invocation or {@code null} if instance or methodName are empty, or if 175 * the reflection fails. 176 */ 177 @Nullable invokeMethod( @ullable Object instance, @Nullable String methodName, Class<?>[] parameterTypes, Object[] parameters)178 public static Object invokeMethod( 179 @Nullable Object instance, 180 @Nullable String methodName, 181 Class<?>[] parameterTypes, 182 Object[] parameters) { 183 if (instance == null || TextUtils.isEmpty(methodName)) { 184 return null; 185 } 186 187 String className = instance.getClass().getName(); 188 try { 189 return Class.forName(className) 190 .getMethod(methodName, parameterTypes) 191 .invoke(instance, parameters); 192 } catch (ClassNotFoundException 193 | NoSuchMethodException 194 | IllegalArgumentException 195 | IllegalAccessException 196 | InvocationTargetException e) { 197 Log.v(TAG, "Could not invoke method: " + className + "#" + methodName); 198 return null; 199 } catch (Throwable t) { 200 Log.e( 201 TAG, 202 "Unexpected exception when invoking method: " 203 + className 204 + "#" 205 + methodName 206 + " at runtime", 207 t); 208 return null; 209 } 210 } 211 212 /** 213 * Determines if this version is compatible with Lollipop-specific APIs. Can also force the 214 * version to be lower through SdkVersionOverride. 215 * 216 * @return {@code true} if call subject is a feature on this device, {@code false} otherwise. 217 */ isLollipopCompatible()218 public static boolean isLollipopCompatible() { 219 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP) 220 >= Build.VERSION_CODES.LOLLIPOP; 221 } 222 } 223