1c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal/*
2c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * Copyright (C) 2015 The Android Open Source Project
3c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal *
4c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * Licensed under the Apache License, Version 2.0 (the "License");
5c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * you may not use this file except in compliance with the License.
6c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * You may obtain a copy of the License at
7c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal *
8c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal *      http://www.apache.org/licenses/LICENSE-2.0
9c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal *
10c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * Unless required by applicable law or agreed to in writing, software
11c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * distributed under the License is distributed on an "AS IS" BASIS,
12c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * See the License for the specific language governing permissions and
14c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal * limitations under the License.
15c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal */
16c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.app;
18c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal
19c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysalimport android.os.Build;
20c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysalimport android.os.Bundle;
21c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysalimport android.os.IBinder;
229dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.util.Log;
239dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikas
24ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
25ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
26eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
27eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikasimport java.lang.reflect.InvocationTargetException;
28eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikasimport java.lang.reflect.Method;
29c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal
30c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal/**
31645e5c8aa6b31961c5f73f3d30bb5261d5e04aebKirill Grouchnikov * Helper for accessing features in {@link Bundle}.
32c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal */
33c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banespublic final class BundleCompat {
34c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banes
35eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas    static class BundleCompatBaseImpl {
36eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        private static final String TAG = "BundleCompatBaseImpl";
37eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
38eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        private static Method sGetIBinderMethod;
39eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        private static boolean sGetIBinderMethodFetched;
40eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
41eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        private static Method sPutIBinderMethod;
42eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        private static boolean sPutIBinderMethodFetched;
43eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
440f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton        private BundleCompatBaseImpl() {
450f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton        }
460f4ca634bbc43ddff900c35f7d2a43b55d8c830dJake Wharton
47eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        public static IBinder getBinder(Bundle bundle, String key) {
48eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            if (!sGetIBinderMethodFetched) {
49eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                try {
50eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sGetIBinderMethod = Bundle.class.getMethod("getIBinder", String.class);
51eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sGetIBinderMethod.setAccessible(true);
52eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                } catch (NoSuchMethodException e) {
53eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    Log.i(TAG, "Failed to retrieve getIBinder method", e);
54eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                }
55eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                sGetIBinderMethodFetched = true;
56eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            }
57eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
58eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            if (sGetIBinderMethod != null) {
59eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                try {
60eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    return (IBinder) sGetIBinderMethod.invoke(bundle, key);
61eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                } catch (InvocationTargetException | IllegalAccessException
62eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                        | IllegalArgumentException e) {
63eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    Log.i(TAG, "Failed to invoke getIBinder via reflection", e);
64eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sGetIBinderMethod = null;
65eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                }
66eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            }
67eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            return null;
68eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        }
69eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
70eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        public static void putBinder(Bundle bundle, String key, IBinder binder) {
71eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            if (!sPutIBinderMethodFetched) {
72eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                try {
73eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sPutIBinderMethod =
74eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                            Bundle.class.getMethod("putIBinder", String.class, IBinder.class);
75eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sPutIBinderMethod.setAccessible(true);
76eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                } catch (NoSuchMethodException e) {
77eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    Log.i(TAG, "Failed to retrieve putIBinder method", e);
78eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                }
79eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                sPutIBinderMethodFetched = true;
80eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            }
81eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
82eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            if (sPutIBinderMethod != null) {
83eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                try {
84eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sPutIBinderMethod.invoke(bundle, key, binder);
85eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                } catch (InvocationTargetException | IllegalAccessException
86eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                        | IllegalArgumentException e) {
87eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    Log.i(TAG, "Failed to invoke putIBinder via reflection", e);
88eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                    sPutIBinderMethod = null;
89eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas                }
90eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            }
91eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas        }
92eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas    }
93eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas
94c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banes    private BundleCompat() {}
95c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banes
96c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal    /**
97c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * A convenience method to handle getting an {@link IBinder} inside a {@link Bundle} for all
98c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * Android versions.
99c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @param bundle The bundle to get the {@link IBinder}.
100c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @param key    The key to use while getting the {@link IBinder}.
101c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @return       The {@link IBinder} that was obtained.
102c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     */
103cbfc663268973c9541708d3c4321e5fb906a3586Jake Wharton    @Nullable
104cbfc663268973c9541708d3c4321e5fb906a3586Jake Wharton    public static IBinder getBinder(@NonNull Bundle bundle, @Nullable String key) {
105c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        if (Build.VERSION.SDK_INT >= 18) {
106eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            return bundle.getBinder(key);
107c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        } else {
108eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            return BundleCompatBaseImpl.getBinder(bundle, key);
109c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        }
110c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal    }
111c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal
112c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal    /**
113c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * A convenience method to handle putting an {@link IBinder} inside a {@link Bundle} for all
114c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * Android versions.
115c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @param bundle The bundle to insert the {@link IBinder}.
116c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @param key    The key to use while putting the {@link IBinder}.
117c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     * @param binder The {@link IBinder} to put.
118c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal     */
119cbfc663268973c9541708d3c4321e5fb906a3586Jake Wharton    public static void putBinder(@NonNull Bundle bundle, @Nullable String key,
120cbfc663268973c9541708d3c4321e5fb906a3586Jake Wharton            @Nullable IBinder binder) {
121c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        if (Build.VERSION.SDK_INT >= 18) {
122eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            bundle.putBinder(key, binder);
123c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        } else {
124eedd63f194a4bf7de284e3771fea451f1724bf26Aurimas Liutikas            BundleCompatBaseImpl.putBinder(bundle, key, binder);
125c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal        }
126c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal    }
127c5c0045de7c8848144a570665e0d3c950816f314Yusuf Ozuysal}
128