1/*
2 * Copyright (C) 2015 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.v4.app;
18
19import static android.os.Build.VERSION.SDK_INT;
20
21import android.app.AppOpsManager;
22import android.content.Context;
23import android.support.annotation.NonNull;
24
25/**
26 * Helper for accessing features in android.app.AppOpsManager
27 * introduced after API level 4 in a backwards compatible fashion.
28 */
29public final class AppOpsManagerCompat {
30
31    /**
32     * Result from {@link #noteOp}: the given caller is allowed to
33     * perform the given operation.
34     */
35    public static final int MODE_ALLOWED = 0;
36
37    /**
38     * Result from {@link #noteOp}: the given caller is not allowed to perform
39     * the given operation, and this attempt should <em>silently fail</em> (it
40     * should not cause the app to crash).
41     */
42    public static final int MODE_IGNORED = 1;
43
44    /**
45     * Result from {@link #noteOp}: the given caller should use its default
46     * security check.  This mode is not normally used; it should only be used
47     * with appop permissions, and callers must explicitly check for it and
48     * deal with it.
49     */
50    public static final int MODE_DEFAULT = 3;
51
52    private AppOpsManagerCompat() {}
53
54    /**
55     * Gets the app op name associated with a given permission.
56     *
57     * @param permission The permission.
58     * @return The app op associated with the permission or null.
59     */
60    public static String permissionToOp(@NonNull String permission) {
61        if (SDK_INT >= 23) {
62            return AppOpsManager.permissionToOp(permission);
63        } else {
64            return null;
65        }
66    }
67
68    /**
69     * Make note of an application performing an operation.  Note that you must pass
70     * in both the uid and name of the application to be checked; this function will verify
71     * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
72     * succeeds, the last execution time of the operation for this app will be updated to
73     * the current time.
74     * @param context Your context.
75     * @param op The operation to note.  One of the OPSTR_* constants.
76     * @param uid The user id of the application attempting to perform the operation.
77     * @param packageName The name of the application attempting to perform the operation.
78     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
79     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
80     * causing the app to crash).
81     * @throws SecurityException If the app has been configured to crash on this op.
82     */
83    public static int noteOp(@NonNull Context context, @NonNull String op, int uid,
84            @NonNull String packageName) {
85        if (SDK_INT >= 23) {
86            AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
87            return appOpsManager.noteOp(op, uid, packageName);
88        } else {
89            return MODE_IGNORED;
90        }
91    }
92
93    /**
94     * Make note of an application performing an operation on behalf of another
95     * application when handling an IPC. Note that you must pass the package name
96     * of the application that is being proxied while its UID will be inferred from
97     * the IPC state; this function will verify that the calling uid and proxied
98     * package name match, and if not, return {@link #MODE_IGNORED}. If this call
99     * succeeds, the last execution time of the operation for the proxied app and
100     * your app will be updated to the current time.
101     * @param context Your context.
102     * @param op The operation to note.  One of the OPSTR_* constants.
103     * @param proxiedPackageName The name of the application calling into the proxy application.
104     * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
105     * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
106     * causing the app to crash).
107     * @throws SecurityException If the app has been configured to crash on this op.
108     */
109    public static int noteProxyOp(@NonNull Context context, @NonNull String op,
110            @NonNull String proxiedPackageName) {
111        if (SDK_INT >= 23) {
112            AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
113            return appOpsManager.noteProxyOp(op, proxiedPackageName);
114        } else {
115            return MODE_IGNORED;
116        }
117    }
118}
119