[go: nahoru, domu]

1/*
2 * Copyright (C) 2011 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
17package android.support.v13.app;
18
19import android.app.Fragment;
20import android.content.Context;
21import android.content.pm.PackageManager;
22import android.os.Build;
23import android.os.Handler;
24import android.os.Looper;
25import android.support.annotation.NonNull;
26import android.support.v4.os.BuildCompat;
27
28import java.util.Arrays;
29
30/**
31 * Helper for accessing features in {@link Fragment} introduced after
32 * API level 13 in a backwards compatible fashion.
33 */
34public class FragmentCompat {
35    interface FragmentCompatImpl {
36        void setMenuVisibility(Fragment f, boolean visible);
37        void setUserVisibleHint(Fragment f, boolean deferStart);
38        void requestPermissions(Fragment fragment, String[] permissions, int requestCode);
39        boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission);
40    }
41
42    static class BaseFragmentCompatImpl implements FragmentCompatImpl {
43        public void setMenuVisibility(Fragment f, boolean visible) {
44        }
45        public void setUserVisibleHint(Fragment f, boolean deferStart) {
46        }
47        public void requestPermissions(final Fragment fragment, final String[] permissions,
48                final int requestCode) {
49            Handler handler = new Handler(Looper.getMainLooper());
50            handler.post(new Runnable() {
51                @Override
52                public void run() {
53                    final int[] grantResults = new int[permissions.length];
54
55                    Context context = fragment.getActivity();
56                    if (context != null) {
57                        PackageManager packageManager = context.getPackageManager();
58                        String packageName = context.getPackageName();
59
60                        final int permissionCount = permissions.length;
61                        for (int i = 0; i < permissionCount; i++) {
62                            grantResults[i] = packageManager.checkPermission(
63                                    permissions[i], packageName);
64                        }
65                    } else {
66                        Arrays.fill(grantResults, PackageManager.PERMISSION_DENIED);
67                    }
68
69                    ((OnRequestPermissionsResultCallback) fragment).onRequestPermissionsResult(
70                            requestCode, permissions, grantResults);
71                }
72            });
73        }
74        public boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) {
75            return false;
76        }
77    }
78
79    static class ICSFragmentCompatImpl extends BaseFragmentCompatImpl {
80        @Override
81        public void setMenuVisibility(Fragment f, boolean visible) {
82            FragmentCompatICS.setMenuVisibility(f, visible);
83        }
84    }
85
86    static class ICSMR1FragmentCompatImpl extends ICSFragmentCompatImpl {
87        @Override
88        public void setUserVisibleHint(Fragment f, boolean deferStart) {
89            FragmentCompatICSMR1.setUserVisibleHint(f, deferStart);
90        }
91    }
92
93    static class MncFragmentCompatImpl extends ICSMR1FragmentCompatImpl {
94        @Override
95        public void requestPermissions(Fragment fragment, String[] permissions, int requestCode) {
96            FragmentCompat23.requestPermissions(fragment, permissions, requestCode);
97        }
98
99        @Override
100        public boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) {
101            return FragmentCompat23.shouldShowRequestPermissionRationale(fragment, permission);
102        }
103    }
104
105    static class NFragmentCompatImpl extends MncFragmentCompatImpl {
106        @Override
107        public void setUserVisibleHint(Fragment f, boolean deferStart) {
108            FragmentCompatApi24.setUserVisibleHint(f, deferStart);
109        }
110    }
111
112    static final FragmentCompatImpl IMPL;
113    static {
114        if (BuildCompat.isAtLeastN()) {
115            IMPL = new NFragmentCompatImpl();
116        } else if (Build.VERSION.SDK_INT >= 23) {
117            IMPL = new MncFragmentCompatImpl();
118        } else if (android.os.Build.VERSION.SDK_INT >= 15) {
119            IMPL = new ICSMR1FragmentCompatImpl();
120        } else if (android.os.Build.VERSION.SDK_INT >= 14) {
121            IMPL = new ICSFragmentCompatImpl();
122        } else {
123            IMPL = new BaseFragmentCompatImpl();
124        }
125    }
126
127    /**
128     * This interface is the contract for receiving the results for permission requests.
129     */
130    public interface OnRequestPermissionsResultCallback {
131
132        /**
133         * Callback for the result from requesting permissions. This method
134         * is invoked for every call on {@link #requestPermissions(android.app.Fragment,
135         * String[], int)}
136         *
137         * @param requestCode The request code passed in {@link #requestPermissions(
138         *     android.app.Fragment, String[], int)}
139         * @param permissions The requested permissions. Never null.
140         * @param grantResults The grant results for the corresponding permissions
141         *     which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
142         *     or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
143         *
144         * @see #requestPermissions(android.app.Fragment, String[], int)
145         */
146        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
147                @NonNull int[] grantResults);
148    }
149
150    /**
151     * Call {@link Fragment#setMenuVisibility(boolean) Fragment.setMenuVisibility(boolean)}
152     * if running on an appropriate version of the platform.
153     */
154    public static void setMenuVisibility(Fragment f, boolean visible) {
155        IMPL.setMenuVisibility(f, visible);
156    }
157
158    /**
159     * Call {@link Fragment#setUserVisibleHint(boolean) setUserVisibleHint(boolean)}
160     * if running on an appropriate version of the platform.
161     */
162    public static void setUserVisibleHint(Fragment f, boolean deferStart) {
163        IMPL.setUserVisibleHint(f, deferStart);
164    }
165
166    /**
167     * Requests permissions to be granted to this application. These permissions
168     * must be requested in your manifest, they should not be granted to your app,
169     * and they should have protection level {@link android.content.pm.PermissionInfo
170     * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
171     * the platform or a third-party app.
172     * <p>
173     * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
174     * are granted at install time if requested in the manifest. Signature permissions
175     * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
176     * install time if requested in the manifest and the signature of your app matches
177     * the signature of the app declaring the permissions.
178     * </p>
179     * <p>
180     * If your app does not have the requested permissions the user will be presented
181     * with UI for accepting them. After the user has accepted or rejected the
182     * requested permissions you will receive a callback reporting whether the
183     * permissions were granted or not. Your fragment has to implement {@link
184     * OnRequestPermissionsResultCallback}
185     * and the results of permission requests will be delivered to its
186     * {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
187     * int, String[], int[])}.
188     * </p>
189     * <p>
190     * Note that requesting a permission does not guarantee it will be granted and
191     * your app should be able to run without having this permission.
192     * </p>
193     * <p>
194     * This method may start an activity allowing the user to choose which permissions
195     * to grant and which to reject. Hence, you should be prepared that your activity
196     * may be paused and resumed. Further, granting some permissions may require
197     * a restart of you application. In such a case, the system will recreate the
198     * activity stack before delivering the result to your onRequestPermissionsResult(
199     * int, String[], int[]).
200     * </p>
201     * <p>
202     * When checking whether you have a permission you should use {@link
203     * android.support.v4.content.ContextCompat#checkSelfPermission(
204     * android.content.Context, String)}.
205     * </p>
206     *
207     * @param fragment The target fragment.
208     * @param permissions The requested permissions.
209     * @param requestCode Application specific request code to match with a result
210     *    reported to {@link OnRequestPermissionsResultCallback#onRequestPermissionsResult(
211     *    int, String[], int[])}.
212     *
213     * @see android.support.v4.content.ContextCompat#checkSelfPermission(
214     *     android.content.Context, String)
215     * @see #shouldShowRequestPermissionRationale(android.app.Fragment, String)
216     */
217    public static void requestPermissions(@NonNull Fragment fragment,
218            @NonNull String[] permissions, int requestCode) {
219        IMPL.requestPermissions(fragment, permissions, requestCode);
220    }
221
222    /**
223     * Gets whether you should show UI with rationale for requesting a permission.
224     * You should do this only if you do not have the permission and the context in
225     * which the permission is requested does not clearly communicate to the user
226     * what would be the benefit from granting this permission.
227     * <p>
228     * For example, if you write a camera app, requesting the camera permission
229     * would be expected by the user and no rationale for why it is requested is
230     * needed. If however, the app needs location for tagging photos then a non-tech
231     * savvy user may wonder how location is related to taking photos. In this case
232     * you may choose to show UI with rationale of requesting this permission.
233     * </p>
234     *
235     * @param fragment The target fragment.
236     * @param permission A permission your app wants to request.
237     * @return Whether you can show permission rationale UI.
238     *
239     * @see android.support.v4.content.ContextCompat#checkSelfPermission(
240     *     android.content.Context, String)
241     * @see #requestPermissions(android.app.Fragment, String[], int)
242     */
243    public static boolean shouldShowRequestPermissionRationale(@NonNull Fragment fragment,
244            @NonNull String permission) {
245        return IMPL.shouldShowRequestPermissionRationale(fragment, permission);
246    }
247}
248