Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix android #5

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,2 +1,23 @@
<manifest package="io.flutter.plugins.webviewflutter">
</manifest>
<manifest package="io.flutter.plugins.webviewflutter"
xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="io.flutter.plugins.webviewflutter.RequestCameraPermissionActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
<activity
android:name="io.flutter.plugins.webviewflutter.FileChooserActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />

<provider
android:name="io.flutter.plugins.webviewflutter.GenericFileProvider"
android:authorities="${applicationId}.generic.provider"
android:exported="false"
android:grantUriPermissions="true"
>
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"
/>
</provider>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

public class Constants {
static final String ACTION_REQUEST_CAMERA_PERMISSION_FINISHED =
"action_request_camera_permission_denied";
static final String ACTION_FILE_CHOOSER_FINISHED = "action_file_chooser_completed";

static final String EXTRA_TITLE = "extra_title";
static final String EXTRA_TYPE = "extra_type";
static final String EXTRA_SHOW_CAMERA_OPTION = "extra_show_camera_option";
static final String EXTRA_FILE_URI = "extra_file_uri";

static final String WEBVIEW_STORAGE_DIRECTORY = "storage";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.flutter.plugins.webviewflutter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.view.View;
import android.view.ViewParent;
import android.webkit.DownloadListener;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebViewHostApi;
import java.util.Map;
import java.util.Objects;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

class CustomDownloadListener {
public static void setCustomDownloadListener(Context context, WebView webView) {
webView.setDownloadListener(new DownloadListener()
{
public void onDownloadStart(String url,
String userAgent,
String contentDisposition,
String mimetype,
long contentLength)
{
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

import static io.flutter.plugins.webviewflutter.Constants.ACTION_FILE_CHOOSER_FINISHED;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_FILE_URI;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_SHOW_CAMERA_OPTION;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_TITLE;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_TYPE;
import static io.flutter.plugins.webviewflutter.Constants.WEBVIEW_STORAGE_DIRECTORY;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileChooserActivity extends Activity {

private static final int FILE_CHOOSER_REQUEST_CODE = 12322;
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");

private Uri cameraImageUri;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showFileChooser(getIntent().getBooleanExtra(EXTRA_SHOW_CAMERA_OPTION, false));
}

private void showFileChooser(boolean enableCamera) {
Intent galleryIntent = createGalleryIntent();
Intent takePictureIntent = enableCamera ? createCameraIntent() : null;
if (galleryIntent == null && takePictureIntent == null) {
// cannot open anything: cancel file chooser
sendBroadcast(new Intent(ACTION_FILE_CHOOSER_FINISHED));
finish();
} else {
Intent[] intentArray =
takePictureIntent != null ? new Intent[] {takePictureIntent} : new Intent[] {};

Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(
Intent.EXTRA_INTENT, galleryIntent != null ? galleryIntent : takePictureIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, getIntent().getStringExtra(EXTRA_TITLE));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);

startActivityForResult(chooserIntent, FILE_CHOOSER_REQUEST_CODE);
}
}

private Intent createGalleryIntent() {
Intent filesIntent = new Intent(Intent.ACTION_GET_CONTENT);
filesIntent.setType(getIntent().getStringExtra(EXTRA_TYPE));
return (filesIntent.resolveActivity(getPackageManager()) != null) ? filesIntent : null;
}

private Intent createCameraIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) == null) {
return null;
}
// Create the File where the photo should go
cameraImageUri = getTempImageUri();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri);

return takePictureIntent;
}

private File getStorageDirectory() {
File imageDirectory = new File(getCacheDir(), WEBVIEW_STORAGE_DIRECTORY);
if (!imageDirectory.exists() && !imageDirectory.mkdir()) {
Log.e("WEBVIEW", "Unable to create storage directory");
}
return imageDirectory;
}

private Uri getTempImageUri() {
String imageFileName = "IMG-" + simpleDateFormat.format(new Date()) + ".jpg";
File imageFile = new File(getStorageDirectory(), imageFileName);
return FileProvider.getUriForFile(
this, getApplicationContext().getPackageName() + ".generic.provider", imageFile);
}

private String getFileNameFromUri(Uri uri) {
Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
assert returnCursor != null;
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
String name = returnCursor.getString(nameIndex);
returnCursor.close();
return name;
}

private Uri copyToLocalUri(Uri uri) {
InputStream in = null;
OutputStream out = null;
try {
File destination = new File(getStorageDirectory(), getFileNameFromUri(uri));
in = getContentResolver().openInputStream(uri);
out = new FileOutputStream(destination);

int cnt = 0;
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
cnt += len;
}

return FileProvider.getUriForFile(
this, getApplicationContext().getPackageName() + ".generic.provider", destination);
} catch (Exception e) {
Log.e("WEBVIEW", "Unable to copy selected image", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

return null;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
Intent intent = new Intent(ACTION_FILE_CHOOSER_FINISHED);
if (resultCode == Activity.RESULT_OK) {
if (data != null && data.getDataString() != null) {
// result from file browser
final Uri uri = copyToLocalUri(data.getData());
intent.putExtra(EXTRA_FILE_URI, uri.toString());
} else {
// result from camera
intent.putExtra(EXTRA_FILE_URI, cameraImageUri.toString());
}
}
sendBroadcast(intent);
finish();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.


package io.flutter.plugins.webviewflutter;


import static io.flutter.plugins.webviewflutter.Constants.ACTION_FILE_CHOOSER_FINISHED;
import static io.flutter.plugins.webviewflutter.Constants.ACTION_REQUEST_CAMERA_PERMISSION_FINISHED;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_FILE_URI;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_SHOW_CAMERA_OPTION;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_TITLE;
import static io.flutter.plugins.webviewflutter.Constants.EXTRA_TYPE;


import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.webkit.ValueCallback;
import androidx.core.content.ContextCompat;


public class FileChooserLauncher extends BroadcastReceiver {


private Context context;
private String title;
private String type;
private boolean showCameraOption;
private ValueCallback<Uri[]> filePathCallback;


public FileChooserLauncher(
Context context,
String title,
String type,
boolean showCameraOption,
ValueCallback<Uri[]> filePathCallback) {
this.context = context;
this.title = title;
this.type = type;
this.showCameraOption = showCameraOption;
this.filePathCallback = filePathCallback;
}


private boolean hasCameraPermission() {
return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}


public void start() {
if (!showCameraOption || hasCameraPermission()) {
showFileChooser();
} else {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_REQUEST_CAMERA_PERMISSION_FINISHED);
context.registerReceiver(this, intentFilter);


Intent intent = new Intent(context, RequestCameraPermissionActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}


private void showFileChooser() {
IntentFilter intentFilter = new IntentFilter(ACTION_FILE_CHOOSER_FINISHED);
context.registerReceiver(this, intentFilter);


Intent intent = new Intent(context, FileChooserActivity.class);
intent.putExtra(EXTRA_TITLE, title);
intent.putExtra(EXTRA_TYPE, type);
intent.putExtra(EXTRA_SHOW_CAMERA_OPTION, showCameraOption && hasCameraPermission());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}


@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_REQUEST_CAMERA_PERMISSION_FINISHED)) {
context.unregisterReceiver(this);
showFileChooser();
} else if (intent.getAction().equals(ACTION_FILE_CHOOSER_FINISHED)) {
String uriString = intent.getStringExtra(EXTRA_FILE_URI);
Uri[] result = uriString != null ? new Uri[] {Uri.parse(uriString)} : null;
filePathCallback.onReceiveValue(result);
context.unregisterReceiver(this);
filePathCallback = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.webviewflutter;

import androidx.core.content.FileProvider;

public class GenericFileProvider extends FileProvider {}
Loading