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