app/android/src/de/itsblue/blueROCK/MainActivity.java
2021-07-05 20:55:34 +02:00

233 lines
8.9 KiB
Java
Executable file

// (c) 2017 Ekkehard Gentz (ekke)
// this project is based on ideas from
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
// see github project https://github.com/lasconic/ShareUtils-QML
// also inspired by:
// https://www.androidcode.ninja/android-share-intent-example/
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
// https://stackoverflow.com/questions/7156932/open-file-in-another-app
// http://www.qtcentre.org/threads/58668-How-to-use-QAndroidJniObject-for-intent-setData
// OpenURL in At Android: got ideas from:
// https://github.com/BernhardWenzel/open-url-in-qt-android
// https://github.com/tobiatesan/android_intents_qt
//
// see also /COPYRIGHT and /LICENSE
package de.itsblue.blueROCK;
import org.qtproject.qt5.android.QtNative;
import org.qtproject.qt5.android.bindings.QtActivity;
import android.os.*;
import android.content.*;
import android.app.*;
import java.lang.String;
import android.content.Intent;
import java.io.File;
import android.net.Uri;
import android.util.Log;
import android.content.ContentResolver;
import android.webkit.MimeTypeMap;
import org.ekkescorner.utils.*;
public class MainActivity extends QtActivity
{
// native - must be implemented in Cpp via JNI
// 'file' scheme or resolved from 'content' scheme:
public static native void setFileUrlReceived(String url);
//
public static native void setOtherUrlReceived(String url, String scheme);
// InputStream from 'content' scheme:
public static native void setFileReceivedAndSaved(String url);
//
public static native void fireActivityResult(int requestCode, int resultCode);
//
public static native boolean checkFileExits(String url);
public static boolean isIntentPending;
public static boolean isInitialized;
public static String workingDirPath;
// Use a custom Chooser without providing own App as share target !
// see QShareUtils.java createCustomChooserAndStartActivity()
// Selecting your own App as target could cause AndroidOS to call
// onCreate() instead of onNewIntent()
// and then you are in trouble because we're using 'singleInstance' as LaunchMode
// more details: my blog at Qt
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("ekkescorner", "onCreate QShareActivity");
// now we're checking if the App was started from another Android App via Intent
Intent theIntent = getIntent();
if (theIntent != null){
String theAction = theIntent.getAction();
if (theAction != null){
Log.d("ekkescorner onCreate ", theAction);
// QML UI not ready yet
// delay processIntent();
isIntentPending = true;
}
}
} // onCreate
// WIP - trying to find a solution to survive a 2nd onCreate
// ongoing discussion in QtMob (Slack)
// from other Apps not respecting that you only have a singleInstance
// there are problems per ex. sharing a file from Google Files App,
// but working well using Xiaomi FileManager App
@Override
public void onDestroy() {
Log.d("ekkescorner", "onDestroy QShareActivity");
// super.onDestroy();
// System.exit() closes the App before doing onCreate() again
// then the App was restarted, but looses context
// This works for Samsung My Files
// but Google Files doesn't call onDestroy()
System.exit(0);
}
// we start Activity with result code
// to test JNI with QAndroidActivityResultReceiver you must comment or rename
// this method here - otherwise you'll get wrong request or result codes
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check which request we're responding to
Log.d("ekkescorner onActivityResult", "requestCode: "+requestCode);
if (resultCode == RESULT_OK) {
Log.d("ekkescorner onActivityResult - resultCode: ", "SUCCESS");
} else {
Log.d("ekkescorner onActivityResult - resultCode: ", "CANCEL");
}
// hint: result comes back too fast for Action SEND
// if you want to delete/move the File add a Timer w 500ms delay
// see Example App main.qml - delayDeleteTimer
// if you want to revoke permissions for older OS
// it makes sense also do this after the delay
fireActivityResult(requestCode, resultCode);
}
// if we are opened from other apps:
@Override
public void onNewIntent(Intent intent) {
Log.d("ekkescorner", "onNewIntent");
super.onNewIntent(intent);
setIntent(intent);
// Intent will be processed, if all is initialized and Qt / QML can handle the event
if(isInitialized) {
processIntent();
} else {
isIntentPending = true;
}
} // onNewIntent
public void checkPendingIntents(String workingDir) {
isInitialized = true;
workingDirPath = workingDir;
Log.d("ekkescorner", workingDirPath);
if(isIntentPending) {
isIntentPending = false;
Log.d("ekkescorner", "checkPendingIntents: true");
processIntent();
} else {
Log.d("ekkescorner", "nothingPending");
}
} // checkPendingIntents
// process the Intent if Action is SEND or VIEW
private void processIntent(){
Intent intent = getIntent();
Uri intentUri;
String intentScheme;
String intentAction;
// we are listening to android.intent.action.SEND or VIEW (see Manifest)
if (intent.getAction().equals("android.intent.action.VIEW")){
intentAction = "VIEW";
intentUri = intent.getData();
} else if (intent.getAction().equals("android.intent.action.SEND")){
intentAction = "SEND";
Bundle bundle = intent.getExtras();
intentUri = (Uri)bundle.get(Intent.EXTRA_STREAM);
} else {
Log.d("ekkescorner Intent unknown action:", intent.getAction());
return;
}
Log.d("ekkescorner action:", intentAction);
if (intentUri == null){
Log.d("ekkescorner Intent URI:", "is null");
return;
}
Log.d("ekkescorner Intent URI:", intentUri.toString());
// content or file
intentScheme = intentUri.getScheme();
if (intentScheme == null){
Log.d("ekkescorner Intent URI Scheme:", "is null");
return;
}
if(intentScheme.equals("file")){
// URI as encoded string
Log.d("ekkescorner Intent File URI: ", intentUri.toString());
setFileUrlReceived(intentUri.toString());
// we are done Qt can deal with file scheme
return;
}
if(!intentScheme.equals("content")){
Log.d("ekkescorner Intent URI unknown scheme: ", intentScheme);
setOtherUrlReceived(intentUri.toString(), intentScheme);
return;
}
// ok - it's a content scheme URI
// we will try to resolve the Path to a File URI
// if this won't work or if the File cannot be opened,
// we'll try to copy the file into our App working dir via InputStream
// hopefully in most cases PathResolver will give a path
// you need the file extension, MimeType or Name from ContentResolver ?
// here's HowTo get it:
Log.d("ekkescorner Intent Content URI: ", intentUri.toString());
ContentResolver cR = this.getContentResolver();
MimeTypeMap mime = MimeTypeMap.getSingleton();
String fileExtension = mime.getExtensionFromMimeType(cR.getType(intentUri));
Log.d("ekkescorner","Intent extension: "+fileExtension);
String mimeType = cR.getType(intentUri);
Log.d("ekkescorner"," Intent MimeType: "+mimeType);
String name = QShareUtils.getContentName(cR, intentUri);
if(name != null) {
Log.d("ekkescorner Intent Name:", name);
} else {
Log.d("ekkescorner Intent Name:", "is NULL");
}
String filePath;
filePath = QSharePathResolver.getRealPathFromURI(this, intentUri);
if(filePath == null) {
Log.d("ekkescorner QSharePathResolver:", "filePath is NULL");
} else {
Log.d("ekkescorner QSharePathResolver:", filePath);
// to be safe check if this File Url really can be opened by Qt
// there were problems with MS office apps on Android 7
if (checkFileExits(filePath)) {
setFileUrlReceived(filePath);
// we are done Qt can deal with file scheme
return;
}
}
// trying the InputStream way:
filePath = QShareUtils.createFile(cR, intentUri, workingDirPath);
if(filePath == null) {
Log.d("ekkescorner Intent FilePath:", "is NULL");
return;
}
setFileReceivedAndSaved(filePath);
} // processIntent
} // class QShareActivity