Java tutorial
/** * Copyright (c) 2016 by Stefan Gross All Rights Reserved. * Licensed under the terms of the MIT License * * Please see the LICENSE included with this distribution for details. * * @author Stefan Gross https://github.com/stgrosshh * */ package ti.permissions; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.appcelerator.kroll.KrollDict; import org.appcelerator.kroll.KrollFunction; import org.appcelerator.kroll.KrollModule; import org.appcelerator.kroll.KrollObject; import org.appcelerator.kroll.annotations.Kroll; import org.appcelerator.titanium.TiApplication; import org.appcelerator.titanium.TiBaseActivity; import org.appcelerator.titanium.TiC; import org.appcelerator.kroll.common.Log; import org.appcelerator.kroll.common.TiConfig; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.util.ArraySet; @Kroll.module(name = "Tipermissions", id = "ti.permissions") public class TipermissionsModule extends KrollModule { // Standard Debugging variables private static final String LCAT = "TipermissionsModule"; private static final boolean DBG = TiConfig.LOGD; // uncritical permission as of Android 6 Marshmallow static final List<String> simplePermissions = Arrays.asList(Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.ACCESS_NOTIFICATION_POLICY, Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.BROADCAST_STICKY, Manifest.permission.CHANGE_NETWORK_STATE, Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, Manifest.permission.DISABLE_KEYGUARD, Manifest.permission.EXPAND_STATUS_BAR, Manifest.permission.FLASHLIGHT, Manifest.permission.GET_ACCOUNTS, Manifest.permission.GET_PACKAGE_SIZE, Manifest.permission.INTERNET, Manifest.permission.KILL_BACKGROUND_PROCESSES, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.NFC, Manifest.permission.READ_SYNC_SETTINGS, Manifest.permission.READ_SYNC_STATS, Manifest.permission.RECEIVE_BOOT_COMPLETED, Manifest.permission.REORDER_TASKS, Manifest.permission.REQUEST_INSTALL_PACKAGES, Manifest.permission.SET_TIME_ZONE, Manifest.permission.SET_WALLPAPER, Manifest.permission.SET_WALLPAPER_HINTS, Manifest.permission.TRANSMIT_IR, Manifest.permission.USE_FINGERPRINT, Manifest.permission.VIBRATE, Manifest.permission.WAKE_LOCK, Manifest.permission.WRITE_SYNC_SETTINGS, Manifest.permission.SET_ALARM, Manifest.permission.INSTALL_SHORTCUT, Manifest.permission.UNINSTALL_SHORTCUT); // critical permissions as of Android 6 Marshmallow static final List<String> permissions = Arrays.asList(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.GET_ACCOUNTS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.READ_CALL_LOG, Manifest.permission.WRITE_CALL_LOG, Manifest.permission.ADD_VOICEMAIL, Manifest.permission.USE_SIP, Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission.BODY_SENSORS, Manifest.permission.SEND_SMS, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_WAP_PUSH, Manifest.permission.RECEIVE_MMS, //Manifest.permission.READ_CELL_BROADCASTS, // missing in level 23? Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.BLUETOOTH_PRIVILEGED, Manifest.permission.CAMERA); /* * Deprecated permissions? * * android.permission.ACCESS_WIMAX_STATE - unknown * android.permission.CHANGE_WIMAX_STATE - unknown * android.permission.SUBSCRIBED_FEEDS_READ - unknown */ // requestCode key in callback result @Kroll.constant public static final String KEY_REQUEST_CODE = "requestCode"; public TipermissionsModule() { super(); Log.d(LCAT, "Ti Permissions Module ctor"); } // TODO shall we implement convenience methods? -> would be a long list though?! /** * check, if given permission is currently granted * * @param requestedPermission - permission as defined in Manifest * @return */ @Kroll.method public boolean hasPermission(@Kroll.argument() String requestedPermission) { Log.d(LCAT, "check for granted permission: " + requestedPermission); // TODO really depends on Build or Platform??? if (Build.VERSION.SDK_INT < 23) { return true; } Context ctx = TiApplication.getInstance().getApplicationContext(); if (ContextCompat.checkSelfPermission(ctx, requestedPermission) != PackageManager.PERMISSION_GRANTED) { return false; } return true; } /** * Request a permission and optionally register a callback for the current activity * * @param requestedPermission permission as defined in Manifest * @param permissionCallback function called with result of permission prompt * @param requestCode - 8 Bit value to associate callback with request - if none is provided a system generated will used * @return true in case of valid request, false if requested permission is not a valid one */ @Kroll.method public boolean requestPermission(String requestedPermission, @Kroll.argument(optional = true) KrollFunction permissionCallback) { Log.d(LCAT, "Requesting permission: " + requestedPermission); if (!isValidPermissionString(requestedPermission)) { Log.e(LCAT, "Requested permission is not supported :" + requestedPermission); return false; } return handleRequest(new String[] { requestedPermission }, permissionCallback); } /** * Request a permission and optionally register a callback for the current activity * * @param requestedPermissions Array of permissions as defined in Manifest * @param permissionCallback function called with result of permission prompt * @param requestCode - 8 Bit value to associate callback with request - if none is provided, a system generated one is used * @return true in case of valid request, false if requested permission is not a valid one */ @Kroll.method public boolean requestPermissions(@Kroll.argument String[] requestedPerms, @Kroll.argument(optional = true) KrollFunction permissionCallback) { for (String permission : requestedPerms) { Log.d(LCAT, "Requesting permission: " + permission); if (!isValidPermissionString(permission)) { Log.e(LCAT, "Requested permission is not supported :" + permission); return false; } } return handleRequest(requestedPerms, permissionCallback); } private boolean handleRequest(String[] permissions, KrollFunction permissionCallback) { Activity activity = TiApplication.getAppCurrentActivity(); if (TiBaseActivity.cameraCallbackContext == null) { TiBaseActivity.cameraCallbackContext = getKrollObject(); } TiBaseActivity.cameraPermissionCallback = permissionCallback; Activity currentActivity = TiApplication.getInstance().getCurrentActivity(); currentActivity.requestPermissions(permissions, TiC.PERMISSION_CODE_CAMERA); return true; } private boolean isUncriticalPermissionString(String requestedPermission) { return simplePermissions.contains(requestedPermission); } private boolean isCriticalPermissionString(String requestedPermission) { return permissions.contains(requestedPermission); } private boolean isValidPermissionString(String requestedPermission) { return isCriticalPermissionString(requestedPermission) || isUncriticalPermissionString(requestedPermission); } }