blob: a394093fbabcacdbfff71eb800602e88ef682719 [file] [log] [blame]
Wenyi Wang6fa570f2015-11-24 15:44:11 -08001/*
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 */
16package com.android.contacts.common.compat;
17
18import android.os.Build;
Ta-wei Yen24c93612016-01-15 18:14:59 -080019import android.os.Build.VERSION;
Brandon Maxwell973c0e12015-12-15 17:09:14 -080020import android.support.annotation.Nullable;
Brandon Maxwell6edc0e62015-12-21 12:15:09 -080021import android.text.TextUtils;
Brandon Maxwell973c0e12015-12-15 17:09:14 -080022import android.util.Log;
Wenyi Wang6fa570f2015-11-24 15:44:11 -080023
Wenyi Wang93fdd482015-12-07 14:26:54 -080024import com.android.contacts.common.model.CPOWrapper;
Wenyi Wang6fa570f2015-11-24 15:44:11 -080025
Nancy Chen78384182015-12-22 17:21:13 -080026import java.lang.reflect.InvocationTargetException;
Nancy Chen78384182015-12-22 17:21:13 -080027
Wenyi Wang6fa570f2015-11-24 15:44:11 -080028public final class CompatUtils {
Brandon Maxwell973c0e12015-12-15 17:09:14 -080029
30 private static final String TAG = CompatUtils.class.getSimpleName();
31
Wenyi Wang6fa570f2015-11-24 15:44:11 -080032 /**
Wenyi Wang93fdd482015-12-07 14:26:54 -080033 * These 4 variables are copied from ContentProviderOperation for compatibility.
34 */
35 public final static int TYPE_INSERT = 1;
36
37 public final static int TYPE_UPDATE = 2;
38
39 public final static int TYPE_DELETE = 3;
40
41 public final static int TYPE_ASSERT = 4;
42
43 /**
44 * Returns whether the operation in CPOWrapper is of TYPE_INSERT;
45 */
46 public static boolean isInsertCompat(CPOWrapper cpoWrapper) {
47 if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
48 return cpoWrapper.getOperation().isInsert();
Wenyi Wang93fdd482015-12-07 14:26:54 -080049 }
Wenyi Wangf46a6192016-02-18 16:34:37 -080050 return (cpoWrapper.getType() == TYPE_INSERT);
51 }
52
53 /**
54 * Returns whether the operation in CPOWrapper is of TYPE_UPDATE;
55 */
56 public static boolean isUpdateCompat(CPOWrapper cpoWrapper) {
57 if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
58 return cpoWrapper.getOperation().isUpdate();
59 }
60 return (cpoWrapper.getType() == TYPE_UPDATE);
61 }
62
63 /**
64 * Returns whether the operation in CPOWrapper is of TYPE_DELETE;
65 */
66 public static boolean isDeleteCompat(CPOWrapper cpoWrapper) {
67 if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
68 return cpoWrapper.getOperation().isDelete();
69 }
70 return (cpoWrapper.getType() == TYPE_DELETE);
Wenyi Wang93fdd482015-12-07 14:26:54 -080071 }
Wenyi Wang009d63c2016-02-18 16:45:08 -080072 /**
73 * Returns whether the operation in CPOWrapper is of TYPE_ASSERT;
74 */
75 public static boolean isAssertQueryCompat(CPOWrapper cpoWrapper) {
76 if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
77 return cpoWrapper.getOperation().isAssertQuery();
78 }
79 return (cpoWrapper.getType() == TYPE_ASSERT);
80 }
Wenyi Wang93fdd482015-12-07 14:26:54 -080081
82 /**
Wenyi Wang6fa570f2015-11-24 15:44:11 -080083 * PrioritizedMimeType is added in API level 23.
84 */
85 public static boolean hasPrioritizedMimeType() {
86 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
87 >= Build.VERSION_CODES.M;
88 }
Nancy Cheneab0b822015-11-25 15:44:48 -080089
90 /**
Ta-wei Yen24c93612016-01-15 18:14:59 -080091 * Determines if this version is compatible with multi-SIM and the phone account APIs. Can also
92 * force the version to be lower through SdkVersionOverride.
Nancy Cheneab0b822015-11-25 15:44:48 -080093 *
94 * @return {@code true} if multi-SIM capability is available, {@code false} otherwise.
95 */
96 public static boolean isMSIMCompatible() {
97 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
98 >= Build.VERSION_CODES.LOLLIPOP_MR1;
99 }
Nancy Chen5fe647d2015-12-08 16:57:48 -0800100
101 /**
102 * Determines if this version is compatible with video calling. Can also force the version to be
103 * lower through SdkVersionOverride.
104 *
105 * @return {@code true} if video calling is allowed, {@code false} otherwise.
106 */
107 public static boolean isVideoCompatible() {
108 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
109 >= Build.VERSION_CODES.M;
110 }
111
112 /**
Ta-wei Yen24c93612016-01-15 18:14:59 -0800113 * Determines if this version is capable of using presence checking for video calling. Support
114 * for video call presence indication is added in SDK 24.
Tyler Gunn001d9742015-12-18 13:57:02 -0800115 *
116 * @return {@code true} if video presence checking is allowed, {@code false} otherwise.
117 */
118 public static boolean isVideoPresenceCompatible() {
119 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
120 > Build.VERSION_CODES.M;
121 }
122
123 /**
Ta-wei Yen24c93612016-01-15 18:14:59 -0800124 * Determines if this version is compatible with call subject. Can also force the version to be
125 * lower through SdkVersionOverride.
Nancy Chen5fe647d2015-12-08 16:57:48 -0800126 *
127 * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
128 */
129 public static boolean isCallSubjectCompatible() {
130 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
131 >= Build.VERSION_CODES.M;
132 }
Nancy Chen04538af2015-12-15 11:58:36 -0800133
134 /**
Nancy Chen78384182015-12-22 17:21:13 -0800135 * Determines if this version is compatible with a default dialer. Can also force the version to
136 * be lower through {@link SdkVersionOverride}.
137 *
138 * @return {@code true} if default dialer is a feature on this device, {@code false} otherwise.
139 */
140 public static boolean isDefaultDialerCompatible() {
141 return isMarshmallowCompatible();
142 }
143
144 /**
Brandon Maxwelle4688f02015-12-18 10:46:27 -0800145 * Determines if this version is compatible with Lollipop Mr1-specific APIs. Can also force the
146 * version to be lower through SdkVersionOverride.
147 *
Ta-wei Yen24c93612016-01-15 18:14:59 -0800148 * @return {@code true} if runtime sdk is compatible with Lollipop MR1, {@code false} otherwise.
Brandon Maxwelle4688f02015-12-18 10:46:27 -0800149 */
150 public static boolean isLollipopMr1Compatible() {
151 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP_MR1)
152 >= Build.VERSION_CODES.LOLLIPOP_MR1;
153 }
154
155 /**
Nancy Chen04538af2015-12-15 11:58:36 -0800156 * Determines if this version is compatible with Marshmallow-specific APIs. Can also force the
157 * version to be lower through SdkVersionOverride.
158 *
Ta-wei Yen24c93612016-01-15 18:14:59 -0800159 * @return {@code true} if runtime sdk is compatible with Marshmallow, {@code false} otherwise.
Nancy Chen04538af2015-12-15 11:58:36 -0800160 */
161 public static boolean isMarshmallowCompatible() {
162 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
163 >= Build.VERSION_CODES.M;
164 }
Brandon Maxwell973c0e12015-12-15 17:09:14 -0800165
166 /**
Ta-wei Yen24c93612016-01-15 18:14:59 -0800167 * Determines if this version is compatible with N-specific APIs.
168 *
169 * @return {@code true} if runtime sdk is compatible with N and the app is built with N, {@code
170 * false} otherwise.
171 */
172 public static boolean isNCompatible() {
Tingting Wang159b1c32016-06-07 16:50:11 -0700173 return VERSION.SDK_INT >= 24;
Ta-wei Yen24c93612016-01-15 18:14:59 -0800174 }
175
Marcus Hagerottd105c1e2016-09-30 14:28:00 -0700176
177 public static boolean isNougatMr1Compatible() {
178 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.N_MR1)
179 >= Build.VERSION_CODES.N_MR1;
180 }
181
182 public static boolean isLauncherShortcutCompatible() {
183 return isNougatMr1Compatible();
184 }
185
Ta-wei Yen24c93612016-01-15 18:14:59 -0800186 /**
Brandon Maxwell973c0e12015-12-15 17:09:14 -0800187 * Determines if the given class is available. Can be used to check if system apis exist at
188 * runtime.
189 *
190 * @param className the name of the class to look for.
191 * @return {@code true} if the given class is available, {@code false} otherwise or if className
Ta-wei Yen24c93612016-01-15 18:14:59 -0800192 * is empty.
Brandon Maxwell973c0e12015-12-15 17:09:14 -0800193 */
194 public static boolean isClassAvailable(@Nullable String className) {
Brandon Maxwell6edc0e62015-12-21 12:15:09 -0800195 if (TextUtils.isEmpty(className)) {
Brandon Maxwell973c0e12015-12-15 17:09:14 -0800196 return false;
197 }
198 try {
199 Class.forName(className);
200 return true;
201 } catch (ClassNotFoundException e) {
202 return false;
203 } catch (Throwable t) {
Brandon Maxwell6edc0e62015-12-21 12:15:09 -0800204 Log.e(TAG, "Unexpected exception when checking if class:" + className + " exists at "
205 + "runtime", t);
206 return false;
207 }
208 }
209
210 /**
211 * Determines if the given class's method is available to call. Can be used to check if system
212 * apis exist at runtime.
213 *
214 * @param className the name of the class to look for
215 * @param methodName the name of the method to look for
216 * @param parameterTypes the needed parameter types for the method to look for
217 * @return {@code true} if the given class is available, {@code false} otherwise or if className
Ta-wei Yen24c93612016-01-15 18:14:59 -0800218 * or methodName are empty.
Brandon Maxwell6edc0e62015-12-21 12:15:09 -0800219 */
220 public static boolean isMethodAvailable(@Nullable String className, @Nullable String methodName,
221 Class<?>... parameterTypes) {
222 if (TextUtils.isEmpty(className) || TextUtils.isEmpty(methodName)) {
223 return false;
224 }
225
226 try {
227 Class.forName(className).getMethod(methodName, parameterTypes);
228 return true;
229 } catch (ClassNotFoundException | NoSuchMethodException e) {
Nancy Chen78384182015-12-22 17:21:13 -0800230 Log.v(TAG, "Could not find method: " + className + "#" + methodName);
Brandon Maxwell6edc0e62015-12-21 12:15:09 -0800231 return false;
232 } catch (Throwable t) {
233 Log.e(TAG, "Unexpected exception when checking if method: " + className + "#"
234 + methodName + " exists at runtime", t);
Brandon Maxwell973c0e12015-12-15 17:09:14 -0800235 return false;
236 }
237 }
Wenyi Wang54ea4b12015-12-16 14:18:59 -0800238
239 /**
Nancy Chen78384182015-12-22 17:21:13 -0800240 * Invokes a given class's method using reflection. Can be used to call system apis that exist
241 * at runtime but not in the SDK.
242 *
243 * @param instance The instance of the class to invoke the method on.
244 * @param methodName The name of the method to invoke.
245 * @param parameterTypes The needed parameter types for the method.
246 * @param parameters The parameter values to pass into the method.
Ta-wei Yen24c93612016-01-15 18:14:59 -0800247 * @return The result of the invocation or {@code null} if instance or methodName are empty, or
248 * if the reflection fails.
Nancy Chen78384182015-12-22 17:21:13 -0800249 */
250 @Nullable
251 public static Object invokeMethod(@Nullable Object instance, @Nullable String methodName,
252 Class<?>[] parameterTypes, Object[] parameters) {
253 if (instance == null || TextUtils.isEmpty(methodName)) {
254 return null;
255 }
256
257 String className = instance.getClass().getName();
258 try {
259 return Class.forName(className).getMethod(methodName, parameterTypes)
260 .invoke(instance, parameters);
261 } catch (ClassNotFoundException | NoSuchMethodException | IllegalArgumentException
262 | IllegalAccessException | InvocationTargetException e) {
263 Log.v(TAG, "Could not invoke method: " + className + "#" + methodName);
264 return null;
265 } catch (Throwable t) {
266 Log.e(TAG, "Unexpected exception when invoking method: " + className
267 + "#" + methodName + " at runtime", t);
268 return null;
269 }
270 }
271
272 /**
Wenyi Wang54ea4b12015-12-16 14:18:59 -0800273 * Determines if this version is compatible with Lollipop-specific APIs. Can also force the
274 * version to be lower through SdkVersionOverride.
275 *
276 * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
277 */
278 public static boolean isLollipopCompatible() {
279 return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
280 >= Build.VERSION_CODES.LOLLIPOP;
281 }
Wenyi Wang6fa570f2015-11-24 15:44:11 -0800282}