Android can now share multiple files at once
This commit is contained in:
parent
7f94f65bea
commit
6ef2b88d41
7 changed files with 109 additions and 78 deletions
|
|
@ -34,8 +34,8 @@ android {
|
|||
applicationId 'com.erroratline0.InfiniPaint'
|
||||
minSdkVersion 27
|
||||
targetSdk 36
|
||||
versionCode 1
|
||||
versionName "0.5.0"
|
||||
versionCode 2
|
||||
versionName "0.6.0"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-fexceptions", "-frtti"
|
||||
|
|
|
|||
2
android-project/app/proguard-rules.pro
vendored
2
android-project/app/proguard-rules.pro
vendored
|
|
@ -23,7 +23,7 @@
|
|||
void startNetworkService();
|
||||
void stopNetworkService();
|
||||
void shareText(java.lang.String);
|
||||
void shareInternalFile(java.lang.String, java.lang.String);
|
||||
void shareInternalFiles(java.lang.String[], java.lang.String);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:versionCode="2"
|
||||
android:versionName="0.6.0"
|
||||
android:installLocation="auto">
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
<meta-data android:name="SDL_ENV.SDL_ANDROID_TRAP_BACK_BUTTON" android:value="0"/>
|
||||
-->
|
||||
<service
|
||||
android:name=".InfiniPaintNetworkService"
|
||||
android:name="InfiniPaintNetworkService"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:exported="false">
|
||||
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import org.libsdl.app.SDLDummyEdit;
|
|||
import org.libsdl.app.SDLSurface;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InfiniPaint extends SDLActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -154,24 +155,43 @@ public class InfiniPaint extends SDLActivity {
|
|||
mSingleton.stopService(new Intent(mSingleton, InfiniPaintNetworkService.class));
|
||||
}
|
||||
|
||||
static public void shareInternalFile(String filePath, String mimeType) {
|
||||
File newFile = new File(getContext().getFilesDir(), filePath);
|
||||
Uri contentUri;
|
||||
static public void shareInternalFiles(String[] filePaths, String mimeType) {
|
||||
if(filePaths.length == 1) {
|
||||
File newFile = new File(getContext().getFilesDir(), filePaths[0]);
|
||||
Uri contentUri;
|
||||
|
||||
try {
|
||||
contentUri = getUriForFile(getContext(), "com.erroratline0.infinipaint.fileprovider", newFile);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.v("INFO", "[shareInternalFile] Exception " + e);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
contentUri = getUriForFile(getContext(), "com.erroratline0.infinipaint.fileprovider", newFile);
|
||||
} catch (Exception e) {
|
||||
Log.v("INFO", "[shareInternalFile] Exception " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||
sendIntent.setType(mimeType);
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, null);
|
||||
getContext().startActivity(shareIntent);
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
|
||||
sendIntent.setType(mimeType);
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, null);
|
||||
getContext().startActivity(shareIntent);
|
||||
}
|
||||
else if(filePaths.length > 1) {
|
||||
ArrayList<Uri> arrayList = new ArrayList<Uri>();
|
||||
for(String str : filePaths) {
|
||||
File newFile = new File(getContext().getFilesDir(), str);
|
||||
try {
|
||||
arrayList.add(getUriForFile(getContext(), "com.erroratline0.infinipaint.fileprovider", newFile));
|
||||
} catch (Exception e) {
|
||||
Log.v("INFO", "[shareInternalFile] Exception " + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
|
||||
sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayList);
|
||||
sendIntent.setType(mimeType);
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, null);
|
||||
getContext().startActivity(shareIntent);
|
||||
}
|
||||
}
|
||||
|
||||
static public void shareText(String textToSend) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,23 @@
|
|||
#include <modules/skunicode/include/SkUnicode_icu.h>
|
||||
#include "NetThreadManager.hpp"
|
||||
|
||||
template <typename T> class JNILocalRef {
|
||||
public:
|
||||
JNILocalRef(JNIEnv* e, T r):
|
||||
env(e),
|
||||
ref(r) {}
|
||||
~JNILocalRef() {
|
||||
env->DeleteLocalRef(ref);
|
||||
}
|
||||
T get() const { return ref; }
|
||||
operator T() const { return ref; }
|
||||
JNILocalRef(const JNILocalRef<T>&) = delete;
|
||||
JNILocalRef& operator=(const JNILocalRef<T>&) = delete;
|
||||
private:
|
||||
JNIEnv* env;
|
||||
T ref;
|
||||
};
|
||||
|
||||
std::string jstring2string(JNIEnv *env, jstring jStr) {
|
||||
if (!jStr)
|
||||
return "";
|
||||
|
|
@ -42,9 +59,9 @@ std::string jstring2string(JNIEnv *env, jstring jStr) {
|
|||
return std::string(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
jstring string2jstring(JNIEnv* env, const std::string& s) {
|
||||
JNILocalRef<jstring> string2jstring(JNIEnv* env, const std::string& s) {
|
||||
std::u16string u16str = SkUnicodes::ICU::Make()->convertUtf8ToUtf16(s.c_str(), s.size());
|
||||
return env->NewString((const jchar*)u16str.data(), u16str.length());
|
||||
return JNILocalRef<jstring>(env, env->NewString((const jchar*)u16str.data(), u16str.length()));
|
||||
}
|
||||
|
||||
namespace AndroidJNICalls {
|
||||
|
|
@ -58,26 +75,31 @@ namespace AndroidJNICalls {
|
|||
bool textChanged = false;
|
||||
bool cursorChanged = false;
|
||||
|
||||
void shareInternalFile(const std::string& filePath, const std::string& mimeType) {
|
||||
Logger::get().log(Logger::LogType::INFO, "[AndroidJNICalls::shareInternalFile] Share internal file " + filePath);
|
||||
void shareInternalFiles(const std::vector<std::string>& filePaths, const std::string& mimeType) {
|
||||
if(filePaths.empty())
|
||||
return;
|
||||
Logger::get().log(Logger::LogType::INFO, "[AndroidJNICalls::shareInternalFile] Share internal files");
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "shareInternalFile", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, string2jstring(env, filePath), string2jstring(env, mimeType));
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
JNILocalRef<jclass> jStrClass(env, env->FindClass("java/lang/String"));
|
||||
JNILocalRef<jobjectArray> jFilePathArray(env, env->NewObjectArray(filePaths.size(), jStrClass, nullptr));
|
||||
for(size_t i = 0; i < filePaths.size(); i++) {
|
||||
JNILocalRef<jstring> s = string2jstring(env, filePaths[i]);
|
||||
env->SetObjectArrayElement(jFilePathArray, i, s);
|
||||
}
|
||||
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "shareInternalFiles", "([Ljava/lang/String;Ljava/lang/String;)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, jFilePathArray.get(), string2jstring(env, mimeType).get());
|
||||
}
|
||||
|
||||
void shareText(const std::string& str) {
|
||||
Logger::get().log(Logger::LogType::INFO, "[AndroidJNICalls::shareText] Share text " + str);
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "shareText", "(Ljava/lang/String;)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, string2jstring(env, str));
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "shareText", "(Ljava/lang/String;)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, string2jstring(env, str).get());
|
||||
}
|
||||
|
||||
int get_android_text_pos_from_cursor_pos(const std::shared_ptr<RichText::TextBox>& t, const RichText::TextPosition& p) {
|
||||
|
|
@ -108,36 +130,30 @@ namespace AndroidJNICalls {
|
|||
modMap = nullptr;
|
||||
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "startTextInput", "(JLjava/lang/String;III)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, textboxID, string2jstring(env, textBox->get_string()),
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "startTextInput", "(JLjava/lang/String;III)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id, textboxID, string2jstring(env, textBox->get_string()).get(),
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::min(cursor->selectionBeginPos, cursor->selectionEndPos)),
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::max(cursor->selectionBeginPos, cursor->selectionEndPos)), inputType);
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
|
||||
void startNetworkService() {
|
||||
Logger::get().log(Logger::LogType::INFO, "[AndroidJNICalls::startNetworkService] Start service");
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "startNetworkService", "()V");
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "startNetworkService", "()V");
|
||||
env->CallStaticVoidMethod(clazz, method_id);
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
|
||||
void stopNetworkService() {
|
||||
Logger::get().log(Logger::LogType::INFO, "[AndroidJNICalls::stopNetworkService] Stop service");
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "stopNetworkService", "()V");
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "stopNetworkService", "()V");
|
||||
env->CallStaticVoidMethod(clazz, method_id);
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
|
||||
void updateModMap(CustomEvents::InputTextBoxID tId, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& newModMap) {
|
||||
|
|
@ -153,14 +169,12 @@ namespace AndroidJNICalls {
|
|||
*cursor = *newCursor;
|
||||
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "updateCursorPos", "(II)V");
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "updateCursorPos", "(II)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id,
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::min(cursor->selectionBeginPos, cursor->selectionEndPos)),
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::max(cursor->selectionBeginPos, cursor->selectionEndPos)));
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,14 +186,12 @@ namespace AndroidJNICalls {
|
|||
textBox->set_rich_text_data(newTextbox->get_rich_text_data());
|
||||
|
||||
JNIEnv* env = static_cast<JNIEnv*>(SDL_GetAndroidJNIEnv());
|
||||
jobject activity = (jobject)SDL_GetAndroidActivity();
|
||||
jclass clazz = env->GetObjectClass(activity);
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz, "updateCursorPos", "(II)V");
|
||||
JNILocalRef<jobject> activity(env, (jobject)SDL_GetAndroidActivity());
|
||||
JNILocalRef<jclass> clazz(env, env->GetObjectClass(activity));
|
||||
jmethodID method_id = env->GetStaticMethodID(clazz.get(), "updateCursorPos", "(II)V");
|
||||
env->CallStaticVoidMethod(clazz, method_id,
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::min(cursor->selectionBeginPos, cursor->selectionEndPos)),
|
||||
get_android_text_pos_from_cursor_pos(textBox, std::max(cursor->selectionBeginPos, cursor->selectionEndPos)));
|
||||
env->DeleteLocalRef(activity);
|
||||
env->DeleteLocalRef(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct InputManager;
|
|||
namespace AndroidJNICalls {
|
||||
extern InputManager* globalInputManager;
|
||||
|
||||
void shareInternalFile(const std::string& filePath, const std::string& mimeType);
|
||||
void shareInternalFiles(const std::vector<std::string>& filePaths, const std::string& mimeType);
|
||||
void shareText(const std::string& str);
|
||||
void startTextInput(CustomEvents::InputTextBoxID newTextboxID, const std::shared_ptr<RichText::TextBox>& newTextbox, const std::shared_ptr<RichText::TextBox::Cursor>& newCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& modMap, int inputType);
|
||||
void startNetworkService();
|
||||
|
|
|
|||
|
|
@ -428,14 +428,15 @@ void FileSelectScreen::move_selected_files(const std::filesystem::path& fromPath
|
|||
}
|
||||
|
||||
void FileSelectScreen::share_selected_files() {
|
||||
for(const FileInfo& f : fileList) {
|
||||
if(f.selected) {
|
||||
#ifdef __ANDROID__
|
||||
AndroidJNICalls::shareInternalFile("saves/" + f.fileName + ".infpnt", "application/octet-stream");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
std::vector<std::string> filesToSend;
|
||||
for(const FileInfo& f : fileList) {
|
||||
if(f.selected)
|
||||
filesToSend.emplace_back("saves/" + f.fileName + ".infpnt");
|
||||
}
|
||||
if(!filesToSend.empty())
|
||||
AndroidJNICalls::shareInternalFiles(filesToSend, "application/octet-stream");
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileSelectScreen::duplicate_selected_files(const std::filesystem::path& inPath) {
|
||||
|
|
@ -583,13 +584,11 @@ void FileSelectScreen::edit_action_bar() {
|
|||
editMode = false;
|
||||
});
|
||||
#ifdef __ANDROID__
|
||||
if(numberOfSelectedEntries == 1) {
|
||||
edit_action_bar_button("share", "data/icons/RemixIcon/share-line.svg", "Share", [&] {
|
||||
share_selected_files();
|
||||
update_file_list(fileList, savePath, false);
|
||||
editMode = false;
|
||||
});
|
||||
}
|
||||
edit_action_bar_button("share", "data/icons/RemixIcon/share-line.svg", "Share", [&] {
|
||||
share_selected_files();
|
||||
update_file_list(fileList, savePath, false);
|
||||
editMode = false;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
else if(selectedMenu == SelectedMenu::TRASH) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue