• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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