Created
October 11, 2016 16:26
-
-
Save digitalprecision/735820df14f696fc2c6c8b251b2b05d6 to your computer and use it in GitHub Desktop.
Android Webview (default) with Runtime Permissions via k0shk0sh PermissionsHelper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.shouttag.mothership; | |
import android.app.Activity; // Need for constants | |
import android.content.DialogInterface; // Needed for building out dialog box | |
import android.content.Intent; // Needed for intent interaction (camera) | |
import android.graphics.Color; // Needed for alert dialog option coloring | |
import android.support.annotation.NonNull; | |
import java.io.File; // Needed for storing image in temp file on device | |
import java.io.IOException; // Needed for storing image in temp file on device | |
import java.text.SimpleDateFormat; // Needed for date formatting | |
import java.util.Arrays; | |
import java.util.Date; // Needed for date api | |
import java.util.List; | |
import android.Manifest; // Needed for manifest permission access | |
import android.net.Uri; // Needed for onFileChooser | |
import android.os.Build; // Needed to determine sdk version | |
import android.os.Bundle; // Needed for onCreate | |
import android.os.Environment; // Need for external storage dir | |
import android.provider.MediaStore; // Needed for external storage access | |
import android.support.v7.app.AppCompatActivity; // Needed for activity extension | |
import android.support.v7.app.AlertDialog; // Needed for building out dialog box | |
import android.util.Log; // Needed for logging | |
import android.view.View; // Needed for hardware accel | |
import android.webkit.*; | |
import com.fastaccess.permission.base.PermissionHelper; | |
import com.fastaccess.permission.base.callback.OnPermissionCallback; | |
public class ActivityMain extends AppCompatActivity implements OnPermissionCallback | |
{ | |
protected static final int REQUEST_CODE_DEFAULT = 1; | |
protected static final int REQUEST_CODE_ANDROID_5 = 2; | |
protected static final int REQUEST_CODE_THUMBNAIL = 3; | |
protected static final int REQUEST_CODE_GALLERY = 4; | |
protected static final String LOG_TAG = "!!!!!"; | |
//protected static final String WEB_VIEW_URL = "https://dev_mpurcell.shouttag.com/test.html"; | |
protected static final String WEB_VIEW_URL = "https://dev_mpurcell.shouttag.com"; | |
protected PermissionHelper permissionHelper; | |
protected final static String[] PERMISSIONS_CAMERA = new String[] { | |
Manifest.permission.CAMERA, | |
Manifest.permission.WRITE_EXTERNAL_STORAGE | |
}; | |
protected final static String[] PERMISSIONS_GALLERY = new String[] { | |
Manifest.permission.WRITE_EXTERNAL_STORAGE | |
}; | |
/** | |
* Container for layout so snackbar knows which layout to render against for permissions | |
* | |
* @type View | |
*/ | |
protected View layoutWebView; | |
/** | |
* Container for temp file uri | |
* | |
* @type string | |
*/ | |
protected String tempFileUri; | |
/** | |
* @type WebView | |
*/ | |
protected WebView webView; | |
/** | |
* @type ValueCallback<Uri[]> | |
*/ | |
protected ValueCallback<Uri[]> fileUriCallback; | |
/** | |
* @type WebSettings | |
*/ | |
protected WebSettings webViewSettings; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) | |
{ | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
layoutWebView = findViewById(R.id.webview); | |
webView = (WebView) findViewById(R.id.webview); | |
webViewSettings = webView.getSettings(); | |
webViewSettings.setJavaScriptEnabled(true); | |
webViewSettings.setLoadWithOverviewMode(true); | |
webViewSettings.setAllowFileAccess(true); | |
webView.setWebViewClient(new MyCustom_Api_Client()); | |
webView.setWebChromeClient(new MyCustom_Api_ChromeClient()); | |
// If SDK version is greater of 19 then activate hardware acceleration otherwise activate software acceleration | |
if (Build.VERSION.SDK_INT >= 19) { | |
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); | |
} else if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT < 19) { | |
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); | |
} | |
webView.loadUrl(WEB_VIEW_URL); | |
permissionHelper = PermissionHelper.getInstance(this); | |
} | |
public class MyCustom_Api_ChromeClient extends WebChromeClient | |
{ | |
// For Android > 5.0 | |
@Override | |
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) | |
{ | |
renderImageUploadOptions(filePathCallback); | |
return true; | |
} | |
} | |
public class MyCustom_Api_Client extends WebViewClient {} | |
protected String convertPermToHumanReadable(String permission) | |
{ | |
switch (permission) { | |
case Manifest.permission.CAMERA: | |
return "camera"; | |
case Manifest.permission.WRITE_EXTERNAL_STORAGE: | |
return "external storage"; | |
default: | |
return null; | |
} | |
} | |
protected File createImageFile() throws IOException | |
{ | |
// Create an image file name | |
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); | |
String imageFileName = "JPEG_" + timeStamp + "_"; | |
File storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/!shouttag/"); | |
if (!storageDir.exists()) { | |
storageDir.mkdirs(); | |
} | |
File image = File.createTempFile( | |
imageFileName, /* prefix */ | |
".jpg", /* suffix */ | |
storageDir /* directory */ | |
); | |
// Save a file: path for use with ACTION_VIEW intents | |
tempFileUri = image.getAbsolutePath(); | |
return image; | |
} | |
protected void intentCamera() | |
{ | |
// Don't try to do individually, for some reason perms get pre-granted then nothing happens | |
permissionHelper | |
.setForceAccepting(false) | |
.request(PERMISSIONS_CAMERA); | |
if ((permissionHelper.isPermissionGranted(Manifest.permission.CAMERA)) && | |
(permissionHelper.isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE))) { | |
showCamera(); | |
} | |
} | |
protected void intentGallery() | |
{ | |
// Don't try to do individually, for some reason perms get pre-granted then nothing happens | |
permissionHelper | |
.setForceAccepting(false) | |
.request(PERMISSIONS_GALLERY); | |
if (permissionHelper.isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { | |
showGallery(); | |
} | |
} | |
@Override | |
public void onActivityResult(int requestCode, int resultCode, Intent intent) | |
{ | |
super.onActivityResult(requestCode, resultCode, intent); | |
permissionHelper.onActivityForResult(requestCode); | |
switch (requestCode) { | |
case REQUEST_CODE_ANDROID_5: | |
Uri result; | |
if (null == fileUriCallback) { | |
return; | |
} | |
if (intent == null || resultCode != Activity.RESULT_OK) { | |
result = null; | |
} else { | |
result = intent.getData(); | |
} | |
if (result != null) { | |
fileUriCallback.onReceiveValue(new Uri[]{result}); | |
fileUriCallback = null; | |
} | |
break; | |
case REQUEST_CODE_THUMBNAIL: | |
File file = new File(tempFileUri); | |
if (resultCode == Activity.RESULT_OK) { | |
Uri localUri = Uri.fromFile(file); | |
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri); | |
ActivityMain.this.sendBroadcast(localIntent); | |
fileUriCallback.onReceiveValue(new Uri[]{localUri}); | |
fileUriCallback = null; | |
} else { | |
if (file.exists()) { | |
file.delete(); | |
} | |
fileUriCallback.onReceiveValue(new Uri[]{}); | |
fileUriCallback = null; | |
} | |
break; | |
case REQUEST_CODE_GALLERY: | |
if (resultCode == RESULT_OK) { | |
Uri selectedImageUri = intent.getData(); | |
Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, selectedImageUri); | |
ActivityMain.this.sendBroadcast(localIntent); | |
// If we want to downsize check out the post | |
// http://stackoverflow.com/questions/2507898/how-to-pick-an-image-from-gallery-sd-card-for-my-app | |
fileUriCallback.onReceiveValue(new Uri[]{selectedImageUri}); | |
fileUriCallback = null; | |
} else { | |
fileUriCallback.onReceiveValue(new Uri[]{}); | |
fileUriCallback = null; | |
} | |
break; | |
} | |
} | |
protected void renderImageUploadOptions(ValueCallback<Uri[]> filePathCallback) | |
{ | |
fileUriCallback = filePathCallback; | |
final CharSequence[] items = { "Take Photo", "Choose from Gallery", "Cancel" }; | |
AlertDialog.Builder builder = new AlertDialog.Builder(ActivityMain.this); | |
builder.setTitle("Add Photo!"); | |
builder.setItems(items, new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int item) { | |
if (items[item].equals("Take Photo")) { | |
intentCamera(); | |
} else if (items[item].equals("Choose from Gallery")) { | |
intentGallery(); | |
} else if (items[item].equals("Cancel")) { | |
fileUriCallback.onReceiveValue(new Uri[]{}); | |
fileUriCallback = null; | |
dialog.dismiss(); | |
} | |
} | |
}); | |
builder.show(); | |
} | |
protected void showCamera() | |
{ | |
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); | |
if (takePictureIntent.resolveActivity(ActivityMain.this.getPackageManager()) != null) { | |
Uri imageUri = null; | |
try { | |
imageUri = Uri.fromFile(createImageFile()); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); | |
startActivityForResult(takePictureIntent, REQUEST_CODE_THUMBNAIL); | |
} | |
} | |
protected void showGallery() | |
{ | |
Intent intent = new Intent(); | |
intent.setType("image/*"); | |
intent.setAction(Intent.ACTION_PICK); | |
startActivityForResult(Intent.createChooser(intent, this.getString(R.string.select_image_from_gallery)), REQUEST_CODE_GALLERY); | |
} | |
/* | |
* PermissionHelper overrides | |
*/ | |
@Override public void onPermissionGranted(@NonNull String[] permissionName) | |
{ | |
//Log.i(LOG_TAG, "onPermissionGranted | Permission(s) " + Arrays.toString(permissionName) + " Granted"); | |
} | |
@Override public void onPermissionDeclined(@NonNull String[] permissionName) | |
{ | |
//Log.i(LOG_TAG, "onPermissionDeclined | Permission(s) " + Arrays.toString(permissionName) + " Declined"); | |
} | |
@Override public void onPermissionPreGranted(@NonNull String permissionsName) | |
{ | |
//Log.i(LOG_TAG, "onPermissionPreGranted | Permission( " + permissionsName + " ) preGranted"); | |
} | |
@Override public void onPermissionNeedExplanation(@NonNull String permissionName) | |
{ | |
//Log.d(LOG_TAG, "onPermissionPreGranted | Permission( " + permissionName + " ) preGranted"); | |
} | |
@Override public void onPermissionReallyDeclined(@NonNull String permissionName) | |
{ | |
//Log.i(LOG_TAG, "onPermissionReallyDeclined | Permission " + permissionName + " can only be granted from settingsScreen"); | |
} | |
@Override public void onNoPermissionNeeded() { | |
//Log.i(LOG_TAG, "onNoPermissionNeeded | Permission(s) not needed"); | |
} | |
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) | |
{ | |
// Skipping parent on purpose, I don't want to keep annoying the user about declined, and permanently declined perms | |
// onRequestPermissionsResult(requestCode, permissions, grantResults); | |
List<String> declinedPermissionsAsList; | |
declinedPermissionsAsList = permissionHelper.declinedPermissionsAsList(this, permissions); | |
if (!declinedPermissionsAsList.isEmpty()) { | |
final String[] declinedPermissions = declinedPermissionsAsList.toArray(new String[declinedPermissionsAsList.size()]); | |
for (int i = 0; i < declinedPermissions.length; i++) { | |
declinedPermissions[i] = convertPermToHumanReadable(declinedPermissions[i]); | |
} | |
AlertDialog dialog = new AlertDialog.Builder(this) | |
.setTitle("The following perms must be allowed to upload photos:") | |
.setItems(declinedPermissions, null) | |
.setPositiveButton("!shouttag Settings", new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
permissionHelper.openSettingsScreen(); | |
fileUriCallback.onReceiveValue(new Uri[]{}); | |
fileUriCallback = null; | |
} | |
}) | |
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
fileUriCallback.onReceiveValue(new Uri[]{}); | |
fileUriCallback = null; | |
dialog.dismiss(); | |
} | |
}) | |
.show(); | |
dialog.getButton(dialog.BUTTON_NEGATIVE).setTextColor(Color.RED); | |
dialog.getButton(dialog.BUTTON_POSITIVE).setTextColor(Color.rgb(60, 179, 113)); | |
} else { | |
if (Arrays.asList(permissions).contains(Manifest.permission.CAMERA)) { | |
showCamera(); | |
} else { | |
showGallery(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment