crossbow_permissions/lib.rs
1// TODO: Add enum with all android permissions
2// TODO: Add JNI calls to request permissions
3
4#[cfg(target_os = "android")]
5pub fn request_permission() {}
6
7/*
8/**
9 * \brief Gets the internal name for an android permission.
10 * \param[in] lJNIEnv a pointer to the JNI environment
11 * \param[in] perm_name the name of the permission, e.g.,
12 * "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE".
13 * \return a jstring with the internal name of the permission,
14 * to be used with android Java functions
15 * Context.checkSelfPermission() or Activity.requestPermissions()
16 */
17 jstring android_permission_name(JNIEnv* lJNIEnv, const char* perm_name) {
18 // nested class permission in class android.Manifest,
19 // hence android 'slash' Manifest 'dollar' permission
20 jclass ClassManifestpermission = lJNIEnv->FindClass(
21 "android/Manifest$permission"
22 );
23 jfieldID lid_PERM = lJNIEnv->GetStaticFieldID(
24 ClassManifestpermission, perm_name, "Ljava/lang/String;"
25 );
26 jstring ls_PERM = (jstring)(lJNIEnv->GetStaticObjectField(
27 ClassManifestpermission, lid_PERM
28 ));
29 return ls_PERM;
30}
31
32/**
33 * \brief Tests whether a permission is granted.
34 * \param[in] app a pointer to the android app.
35 * \param[in] perm_name the name of the permission, e.g.,
36 * "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE".
37 * \retval true if the permission is granted.
38 * \retval false otherwise.
39 * \note Requires Android API level 23 (Marshmallow, May 2015)
40 */
41bool android_has_permission(struct android_app* app, const char* perm_name) {
42 JavaVM* lJavaVM = app->activity->vm;
43 JNIEnv* lJNIEnv = nullptr;
44 bool lThreadAttached = false;
45
46 // Get JNIEnv from lJavaVM using GetEnv to test whether
47 // thread is attached or not to the VM. If not, attach it
48 // (and note that it will need to be detached at the end
49 // of the function).
50 switch (lJavaVM->GetEnv((void**)&lJNIEnv, JNI_VERSION_1_6)) {
51 case JNI_OK:
52 break;
53 case JNI_EDETACHED: {
54 jint lResult = lJavaVM->AttachCurrentThread(&lJNIEnv, nullptr);
55 if(lResult == JNI_ERR) {
56 throw std::runtime_error("Could not attach current thread");
57 }
58 lThreadAttached = true;
59 } break;
60 case JNI_EVERSION:
61 throw std::runtime_error("Invalid java version");
62 }
63
64 bool result = false;
65
66 jstring ls_PERM = android_permission_name(lJNIEnv, perm_name);
67
68 jint PERMISSION_GRANTED = jint(-1);
69 {
70 jclass ClassPackageManager = lJNIEnv->FindClass(
71 "android/content/pm/PackageManager"
72 );
73 jfieldID lid_PERMISSION_GRANTED = lJNIEnv->GetStaticFieldID(
74 ClassPackageManager, "PERMISSION_GRANTED", "I"
75 );
76 PERMISSION_GRANTED = lJNIEnv->GetStaticIntField(
77 ClassPackageManager, lid_PERMISSION_GRANTED
78 );
79 }
80 {
81 jobject activity = app->activity->clazz;
82 jclass ClassContext = lJNIEnv->FindClass(
83 "android/content/Context"
84 );
85 jmethodID MethodcheckSelfPermission = lJNIEnv->GetMethodID(
86 ClassContext, "checkSelfPermission", "(Ljava/lang/String;)I"
87 );
88 jint int_result = lJNIEnv->CallIntMethod(
89 activity, MethodcheckSelfPermission, ls_PERM
90 );
91 result = (int_result == PERMISSION_GRANTED);
92 }
93
94 if(lThreadAttached) {
95 lJavaVM->DetachCurrentThread();
96 }
97
98 return result;
99}
100
101/**
102 * \brief Query file permissions.
103 * \details This opens the system dialog that lets the user
104 * grant (or deny) the permission.
105 * \param[in] app a pointer to the android app.
106 * \note Requires Android API level 23 (Marshmallow, May 2015)
107 */
108void android_request_file_permissions(struct android_app* app) {
109 JavaVM* lJavaVM = app->activity->vm;
110 JNIEnv* lJNIEnv = nullptr;
111 bool lThreadAttached = false;
112
113 // Get JNIEnv from lJavaVM using GetEnv to test whether
114 // thread is attached or not to the VM. If not, attach it
115 // (and note that it will need to be detached at the end
116 // of the function).
117 switch (lJavaVM->GetEnv((void**)&lJNIEnv, JNI_VERSION_1_6)) {
118 case JNI_OK:
119 break;
120 case JNI_EDETACHED: {
121 jint lResult = lJavaVM->AttachCurrentThread(&lJNIEnv, nullptr);
122 if(lResult == JNI_ERR) {
123 throw std::runtime_error("Could not attach current thread");
124 }
125 lThreadAttached = true;
126 } break;
127 case JNI_EVERSION:
128 throw std::runtime_error("Invalid java version");
129 }
130
131 jobjectArray perm_array = lJNIEnv->NewObjectArray(
132 2,
133 lJNIEnv->FindClass("java/lang/String"),
134 lJNIEnv->NewStringUTF("")
135 );
136
137 lJNIEnv->SetObjectArrayElement(
138 perm_array, 0,
139 android_permission_name(lJNIEnv, "READ_EXTERNAL_STORAGE")
140 );
141
142 lJNIEnv->SetObjectArrayElement(
143 perm_array, 1,
144 android_permission_name(lJNIEnv, "WRITE_EXTERNAL_STORAGE")
145 );
146
147 jobject activity = app->activity->clazz;
148
149 jclass ClassActivity = lJNIEnv->FindClass(
150 "android/app/Activity"
151 );
152
153 jmethodID MethodrequestPermissions = lJNIEnv->GetMethodID(
154 ClassActivity, "requestPermissions", "([Ljava/lang/String;I)V"
155 );
156
157 // Last arg (0) is just for the callback (that I do not use)
158 lJNIEnv->CallVoidMethod(
159 activity, MethodrequestPermissions, perm_array, 0
160 );
161
162 if(lThreadAttached) {
163 lJavaVM->DetachCurrentThread();
164 }
165}
166
167void check_android_permissions(struct android_app* app) {
168 bool OK = android_has_permission(
169 app, "READ_EXTERNAL_STORAGE"
170 ) && android_has_permission(
171 app, "WRITE_EXTERNAL_STORAGE"
172 );
173 if(!OK) {
174 android_request_file_permissions(app);
175 }
176}
177*/