1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.Manifest;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Build;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.UserHandle;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.UserManager;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Hashtable;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Set;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Android OS version utilities
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class OsUtil {
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastICS_MR1;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastJB;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastJB_MR1;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastJB_MR2;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastKLP;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastL;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastL_MR1;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean sIsAtLeastM;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static Boolean sIsSecondaryUser = null;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static {
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int v = getApiVersion();
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastICS_MR1 = v >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastJB = v >= android.os.Build.VERSION_CODES.JELLY_BEAN;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastJB_MR1 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastJB_MR2 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastKLP = v >= android.os.Build.VERSION_CODES.KITKAT;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastL = v >= android.os.Build.VERSION_CODES.LOLLIPOP;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastL_MR1 = v >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        sIsAtLeastM = v >= android.os.Build.VERSION_CODES.M;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least Ice Cream Sandwich
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  MR1 (API level 15).
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastICS_MR1() {
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastICS_MR1;
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least Jelly Bean
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 16).
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastJB() {
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastJB;
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least Jelly Bean MR1
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 17).
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastJB_MR1() {
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastJB_MR1;
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least Jelly Bean MR2
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 18).
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastJB_MR2() {
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastJB_MR2;
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least KLP
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 19).
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastKLP() {
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastKLP;
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least L
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 21).
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastL() {
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastL;
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least L MR1
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 22).
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastL_MR1() {
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastL_MR1;
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return True if the version of Android that we're running on is at least M
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *  (API level 23).
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isAtLeastM() {
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsAtLeastM;
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return The Android API version of the OS that we're currently running on.
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static int getApiVersion() {
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return android.os.Build.VERSION.SDK_INT;
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean isSecondaryUser() {
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (sIsSecondaryUser == null) {
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Context context = Factory.get().getApplicationContext();
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean isSecondaryUser = false;
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Only check for newer devices (but not the nexus 10)
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (OsUtil.sIsAtLeastJB_MR1 && !"Nexus 10".equals(Build.MODEL)) {
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final UserHandle uh = android.os.Process.myUserHandle();
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final UserManager userManager =
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        (UserManager) context.getSystemService(Context.USER_SERVICE);
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (userManager != null) {
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final long userSerialNumber = userManager.getSerialNumberForUser(uh);
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    isSecondaryUser = (0 != userSerialNumber);
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sIsSecondaryUser = isSecondaryUser;
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sIsSecondaryUser;
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Creates a joined string from a Set<String> using the given delimiter.
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param values
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param delimiter
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String joinFromSetWithDelimiter(
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Set<String> values, final String delimiter) {
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (values != null) {
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final StringBuilder joinedStringBuilder = new StringBuilder();
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean firstValue = true;
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final String value : values) {
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (firstValue) {
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    firstValue = false;
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    joinedStringBuilder.append(delimiter);
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                joinedStringBuilder.append(value);
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return joinedStringBuilder.toString();
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static Hashtable<String, Integer> sPermissions = new Hashtable<String, Integer>();
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check if the app has the specified permission. If it does not, the app needs to use
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * {@link android.app.Activity#requestPermission}. Note that if it
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * returns true, it cannot return false in the same process as the OS kills the process when
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * any permission is revoked.
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param permission A permission from {@link android.Manifest.permission}
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasPermission(final String permission) {
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastM()) {
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // It is safe to cache the PERMISSION_GRANTED result as the process gets killed if the
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // user revokes the permission setting. However, PERMISSION_DENIED should not be
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // cached as the process does not get killed if the user enables the permission setting.
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!sPermissions.containsKey(permission)
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    || sPermissions.get(permission) == PackageManager.PERMISSION_DENIED) {
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Context context = Factory.get().getApplicationContext();
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int permissionState = context.checkSelfPermission(permission);
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sPermissions.put(permission, permissionState);
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return sPermissions.get(permission) == PackageManager.PERMISSION_GRANTED;
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /** Does the app have all the specified permissions */
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasPermissions(final String[] permissions) {
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final String permission : permissions) {
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!hasPermission(permission)) {
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return false;
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return true;
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasPhonePermission() {
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return hasPermission(Manifest.permission.READ_PHONE_STATE);
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasSmsPermission() {
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return hasPermission(Manifest.permission.READ_SMS);
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasLocationPermission() {
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return OsUtil.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION);
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasStoragePermission() {
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Note that READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are granted or denied
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // together.
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return OsUtil.hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasRecordAudioPermission() {
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return OsUtil.hasPermission(Manifest.permission.RECORD_AUDIO);
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns array with the set of permissions that have not been granted from the given set.
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * The array will be empty if the app has all of the specified permissions. Note that calling
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * {@link Activity#requestPermissions} for an already granted permission can prompt the user
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * again, and its up to the app to only request permissions that are missing.
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String[] getMissingPermissions(final String[] permissions) {
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayList<String> missingList = new ArrayList<String>();
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final String permission : permissions) {
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!hasPermission(permission)) {
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                missingList.add(permission);
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String[] missingArray = new String[missingList.size()];
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        missingList.toArray(missingArray);
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return missingArray;
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String[] sRequiredPermissions = new String[] {
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Required to read existing SMS threads
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Manifest.permission.READ_SMS,
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Required for knowing the phone number, number of SIMs, etc.
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Manifest.permission.READ_PHONE_STATE,
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // This is not strictly required, but simplifies the contact picker scenarios
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Manifest.permission.READ_CONTACTS,
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /** Does the app have the minimum set of permissions required to operate. */
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static boolean hasRequiredPermissions() {
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return hasPermissions(sRequiredPermissions);
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String[] getMissingRequiredPermissions() {
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return getMissingPermissions(sRequiredPermissions);
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
270