2018-08-15 20:30:06 -07:00
package com.reactnativecommunity.webview ;
2018-08-07 23:02:40 -07:00
2019-01-07 06:02:47 -08:00
import android.Manifest ;
2018-11-21 12:46:43 +02:00
import android.app.Activity ;
2019-01-07 06:02:47 -08:00
import android.app.DownloadManager ;
import android.content.Context ;
2018-11-21 12:46:43 +02:00
import android.content.Intent ;
2019-01-07 06:02:47 -08:00
import android.content.pm.PackageManager ;
2018-11-21 12:46:43 +02:00
import android.net.Uri ;
import android.os.Build ;
import android.os.Environment ;
import android.os.Parcelable ;
import android.provider.MediaStore ;
2020-05-26 19:59:08 -07:00
2019-05-16 23:33:25 +01:00
import androidx.annotation.RequiresApi ;
import androidx.core.content.ContextCompat ;
import androidx.core.content.FileProvider ;
2020-05-26 19:59:08 -07:00
2018-11-21 12:46:43 +02:00
import android.util.Log ;
2019-02-28 13:12:27 -08:00
import android.webkit.MimeTypeMap ;
2018-11-21 12:46:43 +02:00
import android.webkit.ValueCallback ;
import android.webkit.WebChromeClient ;
2019-01-07 06:02:47 -08:00
import android.widget.Toast ;
2018-11-21 12:46:43 +02:00
import com.facebook.react.bridge.ActivityEventListener ;
import com.facebook.react.bridge.Promise ;
2018-08-07 23:02:40 -07:00
import com.facebook.react.bridge.ReactApplicationContext ;
import com.facebook.react.bridge.ReactContextBaseJavaModule ;
import com.facebook.react.bridge.ReactMethod ;
2019-03-27 10:52:36 +01:00
import com.facebook.react.module.annotations.ReactModule ;
2019-01-07 06:02:47 -08:00
import com.facebook.react.modules.core.PermissionAwareActivity ;
import com.facebook.react.modules.core.PermissionListener ;
2018-08-07 23:02:40 -07:00
2018-11-21 12:46:43 +02:00
import java.io.File ;
import java.io.IOException ;
import java.util.ArrayList ;
2020-02-18 18:40:30 -08:00
import java.util.Arrays ;
2018-11-21 12:46:43 +02:00
import static android.app.Activity.RESULT_OK ;
2019-03-27 10:52:36 +01:00
@ReactModule ( name = RNCWebViewModule . MODULE_NAME )
2018-11-21 12:46:43 +02:00
public class RNCWebViewModule extends ReactContextBaseJavaModule implements ActivityEventListener {
2019-03-27 10:52:36 +01:00
public static final String MODULE_NAME = "RNCWebView" ;
2018-11-21 12:46:43 +02:00
private static final int PICKER = 1 ;
private static final int PICKER_LEGACY = 3 ;
2019-03-19 15:42:47 +01:00
private static final int FILE_DOWNLOAD_PERMISSION_REQUEST = 1 ;
2018-11-21 12:46:43 +02:00
private ValueCallback < Uri > filePathCallbackLegacy ;
private ValueCallback < Uri []> filePathCallback ;
2020-05-26 19:59:08 -07:00
private File outputImage ;
private File outputVideo ;
2019-01-07 06:02:47 -08:00
private DownloadManager . Request downloadRequest ;
2020-05-26 19:59:08 -07:00
private enum MimeType {
DEFAULT ( "*/*" ),
IMAGE ( "image" ),
VIDEO ( "video" );
private final String value ;
MimeType ( String value ) {
this . value = value ;
}
}
2019-03-19 15:42:47 +01:00
private PermissionListener webviewFileDownloaderPermissionListener = new PermissionListener () {
@Override
public boolean onRequestPermissionsResult ( int requestCode , String [] permissions , int [] grantResults ) {
switch ( requestCode ) {
case FILE_DOWNLOAD_PERMISSION_REQUEST : {
// If request is cancelled, the result arrays are empty.
if ( grantResults . length > 0 && grantResults [ 0 ] == PackageManager . PERMISSION_GRANTED ) {
if ( downloadRequest != null ) {
downloadFile ();
}
} else {
Toast . makeText ( getCurrentActivity (). getApplicationContext (), "Cannot download files as permission was denied. Please provide permission to write to storage, in order to download files." , Toast . LENGTH_LONG ). show ();
}
return true ;
}
}
return false ;
}
};
2018-08-07 23:02:40 -07:00
2018-09-19 01:19:06 +02:00
public RNCWebViewModule ( ReactApplicationContext reactContext ) {
2018-08-07 23:02:40 -07:00
super ( reactContext );
2018-11-21 12:46:43 +02:00
reactContext . addActivityEventListener ( this );
2018-08-07 23:02:40 -07:00
}
@Override
public String getName () {
2019-03-27 10:52:36 +01:00
return MODULE_NAME ;
2018-08-07 23:02:40 -07:00
}
2018-11-21 12:46:43 +02:00
@ReactMethod
public void isFileUploadSupported ( final Promise promise ) {
2019-03-19 15:42:47 +01:00
Boolean result = false ;
int current = Build . VERSION . SDK_INT ;
if ( current >= Build . VERSION_CODES . LOLLIPOP ) {
result = true ;
}
if ( current >= Build . VERSION_CODES . JELLY_BEAN && current <= Build . VERSION_CODES . JELLY_BEAN_MR2 ) {
result = true ;
}
promise . resolve ( result );
2018-11-21 12:46:43 +02:00
}
public void onActivityResult ( Activity activity , int requestCode , int resultCode , Intent data ) {
if ( filePathCallback == null && filePathCallbackLegacy == null ) {
2019-03-19 15:42:47 +01:00
return ;
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
boolean imageTaken = false ;
boolean videoTaken = false ;
if ( outputImage != null && outputImage . length () > 0 ) {
imageTaken = true ;
}
if ( outputVideo != null && outputVideo . length () > 0 ) {
videoTaken = true ;
}
2018-11-21 12:46:43 +02:00
// based off of which button was pressed, we get an activity result and a file
// the camera activity doesn't properly return the filename* (I think?) so we use
// this filename instead
switch ( requestCode ) {
2019-03-19 15:42:47 +01:00
case PICKER :
2018-11-21 12:46:43 +02:00
if ( resultCode != RESULT_OK ) {
2019-03-19 15:42:47 +01:00
if ( filePathCallback != null ) {
filePathCallback . onReceiveValue ( null );
}
2018-11-21 12:46:43 +02:00
} else {
2020-05-26 19:59:08 -07:00
if ( imageTaken ) {
filePathCallback . onReceiveValue ( new Uri [] { getOutputUri ( outputImage )});
} else if ( videoTaken ) {
filePathCallback . onReceiveValue ( new Uri [] { getOutputUri ( outputVideo )});
2019-03-19 15:42:47 +01:00
} else {
2020-05-26 19:59:08 -07:00
filePathCallback . onReceiveValue ( this . getSelectedFiles ( data , resultCode ));
2019-03-19 15:42:47 +01:00
}
2018-11-21 12:46:43 +02:00
}
break ;
2019-03-19 15:42:47 +01:00
case PICKER_LEGACY :
2020-05-26 19:59:08 -07:00
if ( resultCode != RESULT_OK ) {
filePathCallbackLegacy . onReceiveValue ( null );
} else {
if ( imageTaken ) {
filePathCallbackLegacy . onReceiveValue ( getOutputUri ( outputImage ));
} else if ( videoTaken ) {
filePathCallbackLegacy . onReceiveValue ( getOutputUri ( outputVideo ));
} else {
filePathCallbackLegacy . onReceiveValue ( data . getData ());
}
}
2018-11-21 12:46:43 +02:00
break ;
}
2020-05-26 19:59:08 -07:00
if ( outputImage != null && ! imageTaken ) {
outputImage . delete ();
}
if ( outputVideo != null && ! videoTaken ) {
outputVideo . delete ();
}
2018-11-21 12:46:43 +02:00
filePathCallback = null ;
2019-03-19 15:42:47 +01:00
filePathCallbackLegacy = null ;
2020-05-26 19:59:08 -07:00
outputImage = null ;
outputVideo = null ;
2018-11-21 12:46:43 +02:00
}
public void onNewIntent ( Intent intent ) {
}
private Uri [] getSelectedFiles ( Intent data , int resultCode ) {
if ( data == null ) {
2019-03-19 15:42:47 +01:00
return null ;
2018-11-21 12:46:43 +02:00
}
// we have multiple files selected
if ( data . getClipData () != null ) {
2019-03-19 15:42:47 +01:00
final int numSelectedFiles = data . getClipData (). getItemCount ();
Uri [] result = new Uri [ numSelectedFiles ] ;
for ( int i = 0 ; i < numSelectedFiles ; i ++ ) {
result [ i ] = data . getClipData (). getItemAt ( i ). getUri ();
}
return result ;
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
// we have one file selected
if ( data . getData () != null && resultCode == RESULT_OK && Build . VERSION . SDK_INT >= Build . VERSION_CODES . LOLLIPOP ) {
return WebChromeClient . FileChooserParams . parseResult ( resultCode , data );
}
2018-11-21 12:46:43 +02:00
return null ;
}
public void startPhotoPickerIntent ( ValueCallback < Uri > filePathCallback , String acceptType ) {
2019-03-19 15:42:47 +01:00
filePathCallbackLegacy = filePathCallback ;
2018-11-21 12:46:43 +02:00
2019-03-19 15:42:47 +01:00
Intent fileChooserIntent = getFileChooserIntent ( acceptType );
Intent chooserIntent = Intent . createChooser ( fileChooserIntent , "" );
2018-11-21 12:46:43 +02:00
2019-03-19 15:42:47 +01:00
ArrayList < Parcelable > extraIntents = new ArrayList <> ();
if ( acceptsImages ( acceptType )) {
2020-05-26 19:59:08 -07:00
Intent photoIntent = getPhotoIntent ();
if ( photoIntent != null ) {
extraIntents . add ( photoIntent );
}
2019-03-19 15:42:47 +01:00
}
if ( acceptsVideo ( acceptType )) {
2020-05-26 19:59:08 -07:00
Intent videoIntent = getVideoIntent ();
if ( videoIntent != null ) {
extraIntents . add ( videoIntent );
}
2019-03-19 15:42:47 +01:00
}
chooserIntent . putExtra ( Intent . EXTRA_INITIAL_INTENTS , extraIntents . toArray ( new Parcelable [] {}));
2018-11-21 12:46:43 +02:00
2019-03-19 15:42:47 +01:00
if ( chooserIntent . resolveActivity ( getCurrentActivity (). getPackageManager ()) != null ) {
getCurrentActivity (). startActivityForResult ( chooserIntent , PICKER_LEGACY );
} else {
Log . w ( "RNCWebViewModule" , "there is no Activity to handle this Intent" );
}
2018-11-21 12:46:43 +02:00
}
@RequiresApi ( api = Build . VERSION_CODES . LOLLIPOP )
2020-05-26 19:59:08 -07:00
public boolean startPhotoPickerIntent ( final ValueCallback < Uri []> callback , final String [] acceptTypes , final boolean allowMultiple ) {
2018-11-21 12:46:43 +02:00
filePathCallback = callback ;
ArrayList < Parcelable > extraIntents = new ArrayList <> ();
2020-05-26 19:59:08 -07:00
if ( ! needsCameraPermission ()) {
2020-02-18 18:40:30 -08:00
if ( acceptsImages ( acceptTypes )) {
2020-05-26 19:59:08 -07:00
Intent photoIntent = getPhotoIntent ();
if ( photoIntent != null ) {
extraIntents . add ( photoIntent );
}
2020-02-18 18:40:30 -08:00
}
if ( acceptsVideo ( acceptTypes )) {
2020-05-26 19:59:08 -07:00
Intent videoIntent = getVideoIntent ();
if ( videoIntent != null ) {
extraIntents . add ( videoIntent );
}
2020-02-18 18:40:30 -08:00
}
2018-11-21 12:46:43 +02:00
}
Intent fileSelectionIntent = getFileChooserIntent ( acceptTypes , allowMultiple );
Intent chooserIntent = new Intent ( Intent . ACTION_CHOOSER );
chooserIntent . putExtra ( Intent . EXTRA_INTENT , fileSelectionIntent );
chooserIntent . putExtra ( Intent . EXTRA_INITIAL_INTENTS , extraIntents . toArray ( new Parcelable [] {}));
if ( chooserIntent . resolveActivity ( getCurrentActivity (). getPackageManager ()) != null ) {
2019-03-19 15:42:47 +01:00
getCurrentActivity (). startActivityForResult ( chooserIntent , PICKER );
2018-11-21 12:46:43 +02:00
} else {
2019-03-19 15:42:47 +01:00
Log . w ( "RNCWebViewModule" , "there is no Activity to handle this Intent" );
2018-11-21 12:46:43 +02:00
}
return true ;
}
2019-01-07 06:02:47 -08:00
public void setDownloadRequest ( DownloadManager . Request request ) {
this . downloadRequest = request ;
}
public void downloadFile () {
DownloadManager dm = ( DownloadManager ) getCurrentActivity (). getBaseContext (). getSystemService ( Context . DOWNLOAD_SERVICE );
String downloadMessage = "Downloading" ;
dm . enqueue ( this . downloadRequest );
Toast . makeText ( getCurrentActivity (). getApplicationContext (), downloadMessage , Toast . LENGTH_LONG ). show ();
}
public boolean grantFileDownloaderPermissions () {
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M ) {
return true ;
}
boolean result = true ;
if ( ContextCompat . checkSelfPermission ( getCurrentActivity (), Manifest . permission . WRITE_EXTERNAL_STORAGE ) != PackageManager . PERMISSION_GRANTED ) {
result = false ;
}
if ( ! result ) {
PermissionAwareActivity activity = getPermissionAwareActivity ();
2019-03-19 15:42:47 +01:00
activity . requestPermissions ( new String [] { Manifest . permission . WRITE_EXTERNAL_STORAGE }, FILE_DOWNLOAD_PERMISSION_REQUEST , webviewFileDownloaderPermissionListener );
2019-01-07 06:02:47 -08:00
}
return result ;
}
2020-02-18 18:40:30 -08:00
protected boolean needsCameraPermission () {
boolean needed = false ;
PackageManager packageManager = getCurrentActivity (). getPackageManager ();
try {
String [] requestedPermissions = packageManager . getPackageInfo ( getReactApplicationContext (). getPackageName (), PackageManager . GET_PERMISSIONS ). requestedPermissions ;
if ( Arrays . asList ( requestedPermissions ). contains ( Manifest . permission . CAMERA )
&& ContextCompat . checkSelfPermission ( getCurrentActivity (), Manifest . permission . CAMERA ) != PackageManager . PERMISSION_GRANTED ) {
needed = true ;
}
} catch ( PackageManager . NameNotFoundException e ) {
needed = true ;
}
return needed ;
}
2018-11-21 12:46:43 +02:00
private Intent getPhotoIntent () {
2020-05-26 19:59:08 -07:00
Intent intent = null ;
try {
outputImage = getCapturedFile ( MimeType . IMAGE );
Uri outputImageUri = getOutputUri ( outputImage );
intent = new Intent ( MediaStore . ACTION_IMAGE_CAPTURE );
intent . putExtra ( MediaStore . EXTRA_OUTPUT , outputImageUri );
} catch ( IOException | IllegalArgumentException e ) {
Log . e ( "CREATE FILE" , "Error occurred while creating the File" , e );
e . printStackTrace ();
}
2018-11-21 12:46:43 +02:00
return intent ;
}
private Intent getVideoIntent () {
2020-05-26 19:59:08 -07:00
Intent intent = null ;
try {
outputVideo = getCapturedFile ( MimeType . VIDEO );
Uri outputVideoUri = getOutputUri ( outputVideo );
intent = new Intent ( MediaStore . ACTION_VIDEO_CAPTURE );
intent . putExtra ( MediaStore . EXTRA_OUTPUT , outputVideoUri );
} catch ( IOException | IllegalArgumentException e ) {
Log . e ( "CREATE FILE" , "Error occurred while creating the File" , e );
e . printStackTrace ();
}
2018-11-21 12:46:43 +02:00
return intent ;
}
private Intent getFileChooserIntent ( String acceptTypes ) {
String _acceptTypes = acceptTypes ;
if ( acceptTypes . isEmpty ()) {
2020-05-26 19:59:08 -07:00
_acceptTypes = MimeType . DEFAULT . value ;
2018-11-21 12:46:43 +02:00
}
2019-02-28 13:12:27 -08:00
if ( acceptTypes . matches ( "\\.\\w+" )) {
_acceptTypes = getMimeTypeFromExtension ( acceptTypes . replace ( "." , "" ));
}
2018-11-21 12:46:43 +02:00
Intent intent = new Intent ( Intent . ACTION_GET_CONTENT );
intent . addCategory ( Intent . CATEGORY_OPENABLE );
intent . setType ( _acceptTypes );
return intent ;
}
private Intent getFileChooserIntent ( String [] acceptTypes , boolean allowMultiple ) {
Intent intent = new Intent ( Intent . ACTION_GET_CONTENT );
intent . addCategory ( Intent . CATEGORY_OPENABLE );
2020-05-26 19:59:08 -07:00
intent . setType ( MimeType . DEFAULT . value );
2018-11-21 12:46:43 +02:00
intent . putExtra ( Intent . EXTRA_MIME_TYPES , getAcceptedMimeType ( acceptTypes ));
intent . putExtra ( Intent . EXTRA_ALLOW_MULTIPLE , allowMultiple );
return intent ;
}
private Boolean acceptsImages ( String types ) {
2019-02-28 13:12:27 -08:00
String mimeType = types ;
if ( types . matches ( "\\.\\w+" )) {
2019-03-19 15:42:47 +01:00
mimeType = getMimeTypeFromExtension ( types . replace ( "." , "" ));
2019-02-28 13:12:27 -08:00
}
2020-05-26 19:59:08 -07:00
return mimeType . isEmpty () || mimeType . toLowerCase (). contains ( MimeType . IMAGE . value );
2018-11-21 12:46:43 +02:00
}
2019-03-19 15:42:47 +01:00
2018-11-21 12:46:43 +02:00
private Boolean acceptsImages ( String [] types ) {
2019-02-28 13:12:27 -08:00
String [] mimeTypes = getAcceptedMimeType ( types );
2020-05-26 19:59:08 -07:00
return arrayContainsString ( mimeTypes , MimeType . DEFAULT . value ) || arrayContainsString ( mimeTypes , MimeType . IMAGE . value );
2018-11-21 12:46:43 +02:00
}
private Boolean acceptsVideo ( String types ) {
2020-05-26 19:59:08 -07:00
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M ) {
return false ;
}
2019-02-28 13:12:27 -08:00
String mimeType = types ;
if ( types . matches ( "\\.\\w+" )) {
2019-03-19 15:42:47 +01:00
mimeType = getMimeTypeFromExtension ( types . replace ( "." , "" ));
2019-02-28 13:12:27 -08:00
}
2020-05-26 19:59:08 -07:00
return mimeType . isEmpty () || mimeType . toLowerCase (). contains ( MimeType . VIDEO . value );
2018-11-21 12:46:43 +02:00
}
2019-03-19 15:42:47 +01:00
2018-11-21 12:46:43 +02:00
private Boolean acceptsVideo ( String [] types ) {
2020-05-26 19:59:08 -07:00
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M ) {
return false ;
}
2019-02-28 13:12:27 -08:00
String [] mimeTypes = getAcceptedMimeType ( types );
2020-05-26 19:59:08 -07:00
return arrayContainsString ( mimeTypes , MimeType . DEFAULT . value ) || arrayContainsString ( mimeTypes , MimeType . VIDEO . value );
2018-11-21 12:46:43 +02:00
}
2019-03-19 15:42:47 +01:00
private Boolean arrayContainsString ( String [] array , String pattern ) {
for ( String content : array ) {
if ( content . contains ( pattern )) {
return true ;
}
2018-11-21 12:46:43 +02:00
}
return false ;
}
private String [] getAcceptedMimeType ( String [] types ) {
2020-05-26 19:59:08 -07:00
if ( noAcceptTypesSet ( types )) {
return new String [] { MimeType . DEFAULT . value };
2018-11-21 12:46:43 +02:00
}
2019-02-28 13:12:27 -08:00
String [] mimeTypes = new String [ types . length ] ;
for ( int i = 0 ; i < types . length ; i ++ ) {
2019-03-19 15:42:47 +01:00
String t = types [ i ] ;
// convert file extensions to mime types
if ( t . matches ( "\\.\\w+" )) {
String mimeType = getMimeTypeFromExtension ( t . replace ( "." , "" ));
2020-05-26 23:59:18 +02:00
if ( mimeType != null ) {
mimeTypes [ i ] = mimeType ;
} else {
mimeTypes [ i ] = t ;
}
2019-03-19 15:42:47 +01:00
} else {
mimeTypes [ i ] = t ;
}
2019-02-28 13:12:27 -08:00
}
return mimeTypes ;
}
private String getMimeTypeFromExtension ( String extension ) {
String type = null ;
if ( extension != null ) {
2019-03-19 15:42:47 +01:00
type = MimeTypeMap . getSingleton (). getMimeTypeFromExtension ( extension );
2019-02-28 13:12:27 -08:00
}
return type ;
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
private Uri getOutputUri ( File capturedFile ) {
2018-11-21 12:46:43 +02:00
// for versions below 6.0 (23) we use the old File creation & permissions model
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M ) {
2019-03-19 15:42:47 +01:00
return Uri . fromFile ( capturedFile );
2018-11-21 12:46:43 +02:00
}
// for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions
String packageName = getReactApplicationContext (). getPackageName ();
2019-03-19 15:42:47 +01:00
return FileProvider . getUriForFile ( getReactApplicationContext (), packageName + ".fileprovider" , capturedFile );
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
private File getCapturedFile ( MimeType mimeType ) throws IOException {
2018-11-21 12:46:43 +02:00
String prefix = "" ;
String suffix = "" ;
String dir = "" ;
2020-05-26 19:59:08 -07:00
switch ( mimeType ) {
case IMAGE :
prefix = "image-" ;
suffix = ".jpg" ;
dir = Environment . DIRECTORY_PICTURES ;
break ;
case VIDEO :
prefix = "video-" ;
suffix = ".mp4" ;
dir = Environment . DIRECTORY_MOVIES ;
break ;
default :
break ;
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
String filename = prefix + String . valueOf ( System . currentTimeMillis ()) + suffix ;
File outputFile = null ;
2018-11-21 12:46:43 +02:00
// for versions below 6.0 (23) we use the old File creation & permissions model
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . M ) {
2019-03-19 15:42:47 +01:00
// only this Directory works on all tested Android versions
// ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21)
File storageDir = Environment . getExternalStoragePublicDirectory ( dir );
2020-05-26 19:59:08 -07:00
outputFile = new File ( storageDir , filename );
} else {
File storageDir = getReactApplicationContext (). getExternalFilesDir ( null );
outputFile = File . createTempFile ( prefix , suffix , storageDir );
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
return outputFile ;
2018-11-21 12:46:43 +02:00
}
2020-05-26 19:59:08 -07:00
private Boolean noAcceptTypesSet ( String [] types ) {
2018-11-21 12:46:43 +02:00
// when our array returned from getAcceptTypes() has no values set from the webview
// i.e. <input type="file" />, without any "accept" attr
// will be an array with one empty string element, afaik
2020-05-26 19:59:08 -07:00
return types . length == 0 || ( types . length == 1 && types [ 0 ] != null && types [ 0 ] . length () == 0 );
2018-11-21 12:46:43 +02:00
}
2019-01-07 06:02:47 -08:00
private PermissionAwareActivity getPermissionAwareActivity () {
Activity activity = getCurrentActivity ();
if ( activity == null ) {
2019-03-19 15:42:47 +01:00
throw new IllegalStateException ( "Tried to use permissions API while not attached to an Activity." );
2019-01-07 06:02:47 -08:00
} else if ( ! ( activity instanceof PermissionAwareActivity )) {
2019-03-19 15:42:47 +01:00
throw new IllegalStateException ( "Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity." );
2019-01-07 06:02:47 -08:00
}
return ( PermissionAwareActivity ) activity ;
}
2018-11-21 12:46:43 +02:00
}