Skip to content

Commit

Permalink
feat(android): implement dialogs and permissions (#685)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog authored Sep 5, 2022
1 parent eb1b723 commit bf39d9d
Show file tree
Hide file tree
Showing 9 changed files with 774 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changes/android-file-chooser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Implement `<input type="file">` on Android.
5 changes: 5 additions & 0 deletions .changes/android-js-alerts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Enable JS alert, confirm, prompt on Android.
5 changes: 5 additions & 0 deletions .changes/android-permissions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Prompt for permissions on Android when needed.
8 changes: 5 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ fn main() {
let kotlin_out_dir = PathBuf::from(kotlin_out_dir)
.canonicalize()
.expect("Failed to canonicalize path");
let kotlin_files =
fs::read_dir(PathBuf::from(env_var("CARGO_MANIFEST_DIR")).join("src/webview/android/kotlin"))
.expect("failed to read kotlin directory");

let kotlin_files_path =
PathBuf::from(env_var("CARGO_MANIFEST_DIR")).join("src/webview/android/kotlin");
println!("cargo:rerun-if-changed={}", kotlin_files_path.display());
let kotlin_files = fs::read_dir(kotlin_files_path).expect("failed to read kotlin directory");

for file in kotlin_files {
let file = file.unwrap();
Expand Down
85 changes: 85 additions & 0 deletions src/webview/android/kotlin/Logger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2020-2022 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

package {{app-domain-reversed}}.{{app-name-snake-case}}

// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/Logger.java

import android.text.TextUtils;
import android.util.Log;

class Logger {
companion object {
private const val LOG_TAG_CORE = "Tauri"

fun tags(vararg subtags: String): String {
return if (subtags.isNotEmpty()) {
LOG_TAG_CORE + "/" + TextUtils.join("/", subtags)
} else LOG_TAG_CORE
}

fun verbose(message: String) {
verbose(LOG_TAG_CORE, message)
}

private fun verbose(tag: String, message: String) {
if (!shouldLog()) {
return
}
Log.v(tag, message)
}

fun debug(message: String) {
debug(LOG_TAG_CORE, message)
}

fun debug(tag: String, message: String) {
if (!shouldLog()) {
return
}
Log.d(tag, message)
}

fun info(message: String) {
info(LOG_TAG_CORE, message)
}

fun info(tag: String, message: String) {
if (!shouldLog()) {
return
}
Log.i(tag, message)
}

fun warn(message: String) {
warn(LOG_TAG_CORE, message)
}

fun warn(tag: String, message: String) {
if (!shouldLog()) {
return
}
Log.w(tag, message)
}

fun error(message: String) {
error(LOG_TAG_CORE, message, null)
}

fun error(message: String, e: Throwable?) {
error(LOG_TAG_CORE, message, e)
}

fun error(tag: String, message: String, e: Throwable?) {
if (!shouldLog()) {
return
}
Log.e(tag, message, e)
}

private fun shouldLog(): Boolean {
return BuildConfig.DEBUG
}
}
}
122 changes: 122 additions & 0 deletions src/webview/android/kotlin/PermissionHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2020-2022 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

package {{app-domain-reversed}}.{{app-name-snake-case}}

// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/PermissionHelper.java

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import java.util.Arrays;
import kotlin.collections.List;

object PermissionHelper {
/**
* Checks if a list of given permissions are all granted by the user
*
* @since 3.0.0
* @param permissions Permissions to check.
* @return True if all permissions are granted, false if at least one is not.
*/
fun hasPermissions(context: Context?, permissions: Array<String>): Boolean {
for (perm in permissions) {
if (ActivityCompat.checkSelfPermission(
context!!,
perm
) != PackageManager.PERMISSION_GRANTED
) {
return false
}
}
return true
}

/**
* Check whether the given permission has been defined in the AndroidManifest.xml
*
* @since 3.0.0
* @param permission A permission to check.
* @return True if the permission has been defined in the Manifest, false if not.
*/
fun hasDefinedPermission(context: Context, permission: String): Boolean {
var hasPermission = false
val requestedPermissions = getManifestPermissions(context)
if (requestedPermissions != null && requestedPermissions.isNotEmpty()) {
val requestedPermissionsList = listOf(*requestedPermissions)
val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
if (requestedPermissionsArrayList.contains(permission)) {
hasPermission = true
}
}
return hasPermission
}

/**
* Check whether all of the given permissions have been defined in the AndroidManifest.xml
* @param context the app context
* @param permissions a list of permissions
* @return true only if all permissions are defined in the AndroidManifest.xml
*/
fun hasDefinedPermissions(context: Context, permissions: Array<String>): Boolean {
for (permission in permissions) {
if (!hasDefinedPermission(context, permission)) {
return false
}
}
return true
}

/**
* Get the permissions defined in AndroidManifest.xml
*
* @since 3.0.0
* @return The permissions defined in AndroidManifest.xml
*/
private fun getManifestPermissions(context: Context): Array<String>? {
var requestedPermissions: Array<String>? = null
try {
val pm = context.packageManager
val packageInfo = if (Build.VERSION.SDK_INT >= 33) {
pm.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
} else {
@Suppress("DEPRECATION")
pm.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
}
if (packageInfo != null) {
requestedPermissions = packageInfo.requestedPermissions
}
} catch (ex: Exception) {
}
return requestedPermissions
}

/**
* Given a list of permissions, return a new list with the ones not present in AndroidManifest.xml
*
* @since 3.0.0
* @param neededPermissions The permissions needed.
* @return The permissions not present in AndroidManifest.xml
*/
fun getUndefinedPermissions(context: Context, neededPermissions: Array<String?>): Array<String?> {
val undefinedPermissions = ArrayList<String?>()
val requestedPermissions = getManifestPermissions(context)
if (requestedPermissions != null && requestedPermissions.isNotEmpty()) {
val requestedPermissionsList = listOf(*requestedPermissions)
val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
for (permission in neededPermissions) {
if (!requestedPermissionsArrayList.contains(permission)) {
undefinedPermissions.add(permission)
}
}
var undefinedPermissionArray = arrayOfNulls<String>(undefinedPermissions.size)
undefinedPermissionArray = undefinedPermissions.toArray(undefinedPermissionArray)
return undefinedPermissionArray
}
return neededPermissions
}
}
Loading

0 comments on commit bf39d9d

Please sign in to comment.