android: images sharing
This commit is contained in:
parent
493d801aad
commit
5689be4579
7 changed files with 74 additions and 1 deletions
|
@ -19,11 +19,22 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Main">
|
android:theme="@style/Theme.Main">
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name=".FileProvider"
|
||||||
|
android:authorities="mw.gri.android.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/paths" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package mw.gri.android;
|
||||||
|
|
||||||
|
public class FileProvider extends androidx.core.content.FileProvider {
|
||||||
|
public FileProvider() {
|
||||||
|
super(R.xml.paths);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.Manifest;
|
||||||
import android.content.*;
|
import android.content.*;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
@ -17,6 +18,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.camera.core.*;
|
import androidx.camera.core.*;
|
||||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.DisplayCutoutCompat;
|
import androidx.core.view.DisplayCutoutCompat;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
|
@ -24,6 +26,7 @@ import androidx.core.view.WindowInsetsCompat;
|
||||||
import com.google.androidgamesdk.GameActivity;
|
import com.google.androidgamesdk.GameActivity;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@ -62,6 +65,11 @@ public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
// Clear cache on start.
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
Utils.deleteDirectoryContent(new File(getExternalCacheDir().getPath()), false);
|
||||||
|
}
|
||||||
|
|
||||||
// Setup environment variables for native code.
|
// Setup environment variables for native code.
|
||||||
try {
|
try {
|
||||||
Os.setenv("HOME", getExternalFilesDir("").getPath(), true);
|
Os.setenv("HOME", getExternalFilesDir("").getPath(), true);
|
||||||
|
@ -70,6 +78,7 @@ public class MainActivity extends GameActivity {
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onCreate(null);
|
super.onCreate(null);
|
||||||
|
|
||||||
// Register receiver to finish activity from the BackgroundService.
|
// Register receiver to finish activity from the BackgroundService.
|
||||||
|
@ -334,4 +343,14 @@ public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
// Pass image from camera into native code.
|
// Pass image from camera into native code.
|
||||||
public native void onCameraImage(byte[] buff, int rotation);
|
public native void onCameraImage(byte[] buff, int rotation);
|
||||||
|
|
||||||
|
// Called from native code to share image from provided path.
|
||||||
|
public void shareImage(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
Uri uri = FileProvider.getUriForFile(this, "mw.gri.android.fileprovider", file);
|
||||||
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
|
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
intent.setType("image/*");
|
||||||
|
startActivity(Intent.createChooser(intent, "Share image"));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ import android.media.Image;
|
||||||
import androidx.camera.core.ImageProxy;
|
import androidx.camera.core.ImageProxy;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
@ -135,4 +136,14 @@ public class Utils {
|
||||||
rowStart += plane.getRowStride();
|
rowStart += plane.getRowStride();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean deleteDirectoryContent(File directoryToBeDeleted, boolean deleteDirectory) {
|
||||||
|
File[] allContents = directoryToBeDeleted.listFiles();
|
||||||
|
if (allContents != null) {
|
||||||
|
for (File file : allContents) {
|
||||||
|
deleteDirectoryContent(file, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return directoryToBeDeleted.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
4
android/app/src/main/res/xml/paths.xml
Normal file
4
android/app/src/main/res/xml/paths.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-cache-path name="images" path="images/" />
|
||||||
|
</paths>
|
|
@ -12,6 +12,11 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
@ -116,6 +121,22 @@ impl PlatformCallbacks for Android {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn share_data(&self, name: String, data: Vec<u8>) -> Result<(), std::io::Error> {
|
fn share_data(&self, name: String, data: Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
// Create file at cache dir.
|
||||||
|
let default_cache = OsString::from(dirs::cache_dir().unwrap());
|
||||||
|
let mut cache = PathBuf::from(env::var_os("XDG_CACHE_HOME").unwrap_or(default_cache));
|
||||||
|
cache.push("images");
|
||||||
|
std::fs::create_dir_all(cache.to_str().unwrap())?;
|
||||||
|
cache.push(name);
|
||||||
|
let mut image = File::create_new(cache.clone()).unwrap();
|
||||||
|
image.write_all(data.as_slice()).unwrap();
|
||||||
|
image.sync_all().unwrap();
|
||||||
|
// Call share modal at system.
|
||||||
|
let vm = unsafe { jni::JavaVM::from_raw(self.android_app.vm_as_ptr() as _) }.unwrap();
|
||||||
|
let env = vm.attach_current_thread().unwrap();
|
||||||
|
let arg_value = env.new_string(cache.to_str().unwrap()).unwrap();
|
||||||
|
self.call_java_method("shareImage",
|
||||||
|
"(Ljava/lang/String;)V",
|
||||||
|
&[JValue::Object(&JObject::from(arg_value))]).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use std::thread;
|
||||||
use egui::{SizeHint, TextureHandle, TextureOptions};
|
use egui::{SizeHint, TextureHandle, TextureOptions};
|
||||||
use egui::load::SizedTexture;
|
use egui::load::SizedTexture;
|
||||||
use egui_extras::image::load_svg_bytes_with_size;
|
use egui_extras::image::load_svg_bytes_with_size;
|
||||||
use image::{EncodableLayout, ExtendedColorType, ImageEncoder};
|
use image::{ExtendedColorType, ImageEncoder};
|
||||||
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
|
||||||
use qrcodegen::QrCode;
|
use qrcodegen::QrCode;
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
|
|
Loading…
Reference in a new issue