16fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang/*
26fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * Copyright (C) 2015 The Android Open Source Project
36fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang *
46fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * Licensed under the Apache License, Version 2.0 (the "License");
56fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * you may not use this file except in compliance with the License.
66fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * You may obtain a copy of the License at
76fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang *
86fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang *      http://www.apache.org/licenses/LICENSE-2.0
96fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang *
106fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * Unless required by applicable law or agreed to in writing, software
116fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * distributed under the License is distributed on an "AS IS" BASIS,
126fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * See the License for the specific language governing permissions and
146fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang * limitations under the License.
156fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang */
1669c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.compat;
176fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang
186fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wangimport android.os.Build;
1924c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yenimport android.os.Build.VERSION;
20973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwellimport android.support.annotation.Nullable;
216edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwellimport android.text.TextUtils;
22973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwellimport android.util.Log;
236fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang
2469c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.CPOWrapper;
256fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang
2678384189dc0d1e60379947ce9f878f80045f7e6cNancy Chenimport java.lang.reflect.InvocationTargetException;
2778384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen
286fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wangpublic final class CompatUtils {
29973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell
30973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell    private static final String TAG = CompatUtils.class.getSimpleName();
31973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell
326fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang    /**
3393fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang     * These 4 variables are copied from ContentProviderOperation for compatibility.
3493fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang     */
3593fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    public final static int TYPE_INSERT = 1;
3693fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang
3793fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    public final static int TYPE_UPDATE = 2;
3893fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang
3993fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    public final static int TYPE_DELETE = 3;
4093fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang
4193fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    public final static int TYPE_ASSERT = 4;
4293fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang
4393fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    /**
4493fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang     * Returns whether the operation in CPOWrapper is of TYPE_INSERT;
4593fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang     */
4693fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    public static boolean isInsertCompat(CPOWrapper cpoWrapper) {
4793fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
4893fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang            return cpoWrapper.getOperation().isInsert();
4993fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang        }
50f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        return (cpoWrapper.getType() == TYPE_INSERT);
51f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    }
52f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang
53f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    /**
54f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang     * Returns whether the operation in CPOWrapper is of TYPE_UPDATE;
55f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang     */
56f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    public static boolean isUpdateCompat(CPOWrapper cpoWrapper) {
57f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
58f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang            return cpoWrapper.getOperation().isUpdate();
59f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        }
60f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        return (cpoWrapper.getType() == TYPE_UPDATE);
61f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    }
62f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang
63f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    /**
64f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang     * Returns whether the operation in CPOWrapper is of TYPE_DELETE;
65f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang     */
66f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang    public static boolean isDeleteCompat(CPOWrapper cpoWrapper) {
67f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
68f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang            return cpoWrapper.getOperation().isDelete();
69f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        }
70f46a619e0126f3a2fd6048b5d6a07fcf26c3b38aWenyi Wang        return (cpoWrapper.getType() == TYPE_DELETE);
7193fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    }
72009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    /**
73009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang     * Returns whether the operation in CPOWrapper is of TYPE_ASSERT;
74009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang     */
75009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    public static boolean isAssertQueryCompat(CPOWrapper cpoWrapper) {
76009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        if (SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M) >= Build.VERSION_CODES.M) {
77009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang            return cpoWrapper.getOperation().isAssertQuery();
78009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        }
79009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang        return (cpoWrapper.getType() == TYPE_ASSERT);
80009d63c3d9c9dd372137c4954fb8562f5b132d60Wenyi Wang    }
8193fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang
8293fdd48dfe13a0066593b917cbd3babf68f79a2dWenyi Wang    /**
836fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang     * PrioritizedMimeType is added in API level 23.
846fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang     */
856fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang    public static boolean hasPrioritizedMimeType() {
866fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
876fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang                >= Build.VERSION_CODES.M;
886fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang    }
89eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen
90eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen    /**
9124c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * Determines if this version is compatible with multi-SIM and the phone account APIs. Can also
9224c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * force the version to be lower through SdkVersionOverride.
93eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen     *
94eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen     * @return {@code true} if multi-SIM capability is available, {@code false} otherwise.
95eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen     */
96eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen    public static boolean isMSIMCompatible() {
97eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
98eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen                >= Build.VERSION_CODES.LOLLIPOP_MR1;
99eab0b82ffcb89465e9781d6297161ca5416ca49eNancy Chen    }
1005fe647dc40b039501f52878607c418d807587bc6Nancy Chen
1015fe647dc40b039501f52878607c418d807587bc6Nancy Chen    /**
1025fe647dc40b039501f52878607c418d807587bc6Nancy Chen     * Determines if this version is compatible with video calling. Can also force the version to be
1035fe647dc40b039501f52878607c418d807587bc6Nancy Chen     * lower through SdkVersionOverride.
1045fe647dc40b039501f52878607c418d807587bc6Nancy Chen     *
1055fe647dc40b039501f52878607c418d807587bc6Nancy Chen     * @return {@code true} if video calling is allowed, {@code false} otherwise.
1065fe647dc40b039501f52878607c418d807587bc6Nancy Chen     */
1075fe647dc40b039501f52878607c418d807587bc6Nancy Chen    public static boolean isVideoCompatible() {
1085fe647dc40b039501f52878607c418d807587bc6Nancy Chen        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
1095fe647dc40b039501f52878607c418d807587bc6Nancy Chen                >= Build.VERSION_CODES.M;
1105fe647dc40b039501f52878607c418d807587bc6Nancy Chen    }
1115fe647dc40b039501f52878607c418d807587bc6Nancy Chen
1125fe647dc40b039501f52878607c418d807587bc6Nancy Chen    /**
11324c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * Determines if this version is capable of using presence checking for video calling. Support
11424c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * for video call presence indication is added in SDK 24.
115001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn     *
116001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn     * @return {@code true} if video presence checking is allowed, {@code false} otherwise.
117001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn     */
118001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn    public static boolean isVideoPresenceCompatible() {
119001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.M)
120001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn                > Build.VERSION_CODES.M;
121001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn    }
122001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn
123001d9740977421058daf3fca799e7bb8f1e7e58eTyler Gunn    /**
12424c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * Determines if this version is compatible with call subject. Can also force the version to be
12524c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * lower through SdkVersionOverride.
1265fe647dc40b039501f52878607c418d807587bc6Nancy Chen     *
1275fe647dc40b039501f52878607c418d807587bc6Nancy Chen     * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
1285fe647dc40b039501f52878607c418d807587bc6Nancy Chen     */
1295fe647dc40b039501f52878607c418d807587bc6Nancy Chen    public static boolean isCallSubjectCompatible() {
1305fe647dc40b039501f52878607c418d807587bc6Nancy Chen        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
1315fe647dc40b039501f52878607c418d807587bc6Nancy Chen                >= Build.VERSION_CODES.M;
1325fe647dc40b039501f52878607c418d807587bc6Nancy Chen    }
13304538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen
13404538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen    /**
13578384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * Determines if this version is compatible with a default dialer. Can also force the version to
13678384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * be lower through {@link SdkVersionOverride}.
13778384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     *
13878384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * @return {@code true} if default dialer is a feature on this device, {@code false} otherwise.
13978384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     */
14078384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    public static boolean isDefaultDialerCompatible() {
14178384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        return isMarshmallowCompatible();
14278384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    }
14378384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen
14478384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    /**
145e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell     * Determines if this version is compatible with Lollipop Mr1-specific APIs. Can also force the
146e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell     * version to be lower through SdkVersionOverride.
147e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell     *
14824c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * @return {@code true} if runtime sdk is compatible with Lollipop MR1, {@code false} otherwise.
149e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell     */
150e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell    public static boolean isLollipopMr1Compatible() {
151e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP_MR1)
152e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell                >= Build.VERSION_CODES.LOLLIPOP_MR1;
153e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell    }
154e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell
155e4688f075b35e0b15a42bb174ab736e9da33ec6bBrandon Maxwell    /**
15604538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen     * Determines if this version is compatible with Marshmallow-specific APIs. Can also force the
15704538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen     * version to be lower through SdkVersionOverride.
15804538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen     *
15924c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * @return {@code true} if runtime sdk is compatible with Marshmallow, {@code false} otherwise.
16004538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen     */
16104538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen    public static boolean isMarshmallowCompatible() {
16204538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
16304538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen                >= Build.VERSION_CODES.M;
16404538afa5f1e7968811ba014de0b9a39fa20d3f9Nancy Chen    }
165973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell
166973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell    /**
16724c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * Determines if this version is compatible with N-specific APIs.
16824c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     *
16924c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * @return {@code true} if runtime sdk is compatible with N and the app is built with N, {@code
17024c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * false} otherwise.
17124c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     */
17224c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen    public static boolean isNCompatible() {
173159b1c3c0194b4ee0c10355b74404457e51d7b3dTingting Wang        return VERSION.SDK_INT >= 24;
17424c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen    }
17524c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen
176d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott
177d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott    public static boolean isNougatMr1Compatible() {
178d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.N_MR1)
179d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott                >= Build.VERSION_CODES.N_MR1;
180d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott    }
181d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott
182d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott    public static boolean isLauncherShortcutCompatible() {
183d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott        return isNougatMr1Compatible();
184d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott    }
185d105c1e23485927b408ee6041d6fac8a71267768Marcus Hagerott
18624c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen    /**
187973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     * Determines if the given class is available. Can be used to check if system apis exist at
188973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     * runtime.
189973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     *
190973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     * @param className the name of the class to look for.
191973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     * @return {@code true} if the given class is available, {@code false} otherwise or if className
19224c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * is empty.
193973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell     */
194973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell    public static boolean isClassAvailable(@Nullable String className) {
1956edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        if (TextUtils.isEmpty(className)) {
196973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell            return false;
197973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell        }
198973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell        try {
199973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell            Class.forName(className);
200973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell            return true;
201973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell        } catch (ClassNotFoundException e) {
202973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell            return false;
203973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell        } catch (Throwable t) {
2046edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            Log.e(TAG, "Unexpected exception when checking if class:" + className + " exists at "
2056edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell                    + "runtime", t);
2066edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            return false;
2076edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        }
2086edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell    }
2096edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell
2106edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell    /**
2116edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * Determines if the given class's method is available to call. Can be used to check if system
2126edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * apis exist at runtime.
2136edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     *
2146edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * @param className the name of the class to look for
2156edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * @param methodName the name of the method to look for
2166edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * @param parameterTypes the needed parameter types for the method to look for
2176edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     * @return {@code true} if the given class is available, {@code false} otherwise or if className
21824c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * or methodName are empty.
2196edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell     */
2206edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell    public static boolean isMethodAvailable(@Nullable String className, @Nullable String methodName,
2216edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            Class<?>... parameterTypes) {
2226edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        if (TextUtils.isEmpty(className) || TextUtils.isEmpty(methodName)) {
2236edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            return false;
2246edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        }
2256edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell
2266edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        try {
2276edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            Class.forName(className).getMethod(methodName, parameterTypes);
2286edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            return true;
2296edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        } catch (ClassNotFoundException | NoSuchMethodException e) {
23057a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang            if (Log.isLoggable(TAG, Log.VERBOSE)) {
23157a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang                Log.v(TAG, "Could not find method: " + className + "#" + methodName);
23257a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang            }
2336edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            return false;
2346edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell        } catch (Throwable t) {
2356edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell            Log.e(TAG, "Unexpected exception when checking if method: " + className + "#"
2366edc0e6b863006b06b3245c8d5c18818f4a74c46Brandon Maxwell                    + methodName + " exists at runtime", t);
237973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell            return false;
238973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell        }
239973c0e1ad8ee05a112d6d06531ace0454ee0437cBrandon Maxwell    }
24054ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang
24154ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang    /**
24278384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * Invokes a given class's method using reflection. Can be used to call system apis that exist
24378384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * at runtime but not in the SDK.
24478384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     *
24578384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * @param instance The instance of the class to invoke the method on.
24678384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * @param methodName The name of the method to invoke.
24778384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * @param parameterTypes The needed parameter types for the method.
24878384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     * @param parameters The parameter values to pass into the method.
24924c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * @return The result of the invocation or {@code null} if instance or methodName are empty, or
25024c93615791c0c00613db12d27310f2d3b818d1eTa-wei Yen     * if the reflection fails.
25178384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen     */
25278384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    @Nullable
25378384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    public static Object invokeMethod(@Nullable Object instance, @Nullable String methodName,
25478384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            Class<?>[] parameterTypes, Object[] parameters) {
25578384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        if (instance == null || TextUtils.isEmpty(methodName)) {
25678384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            return null;
25778384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        }
25878384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen
25978384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        String className = instance.getClass().getName();
26078384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        try {
26178384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            return Class.forName(className).getMethod(methodName, parameterTypes)
26278384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen                    .invoke(instance, parameters);
26378384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        } catch (ClassNotFoundException | NoSuchMethodException | IllegalArgumentException
26478384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen                | IllegalAccessException | InvocationTargetException e) {
26557a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang            if (Log.isLoggable(TAG, Log.VERBOSE)) {
26657a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang                Log.v(TAG, "Could not invoke method: " + className + "#" + methodName);
26757a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang            }
26878384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            return null;
26978384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        } catch (Throwable t) {
27078384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            Log.e(TAG, "Unexpected exception when invoking method: " + className
27178384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen                    + "#" + methodName + " at runtime", t);
27278384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen            return null;
27378384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen        }
27478384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    }
27578384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen
27678384189dc0d1e60379947ce9f878f80045f7e6cNancy Chen    /**
27754ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang     * Determines if this version is compatible with Lollipop-specific APIs. Can also force the
27854ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang     * version to be lower through SdkVersionOverride.
27954ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang     *
28054ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang     * @return {@code true} if call subject is a feature on this device, {@code false} otherwise.
28154ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang     */
28254ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang    public static boolean isLollipopCompatible() {
28354ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang        return SdkVersionOverride.getSdkVersion(Build.VERSION_CODES.LOLLIPOP)
28454ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang                >= Build.VERSION_CODES.LOLLIPOP;
28554ea4b140d3e82ab5a061c0f1c8aff2933871714Wenyi Wang    }
2866fa570f28d8a9e4c12acc7436747f848382d44d2Wenyi Wang}
287