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

Android PDF file viewer and openLink function working #3268

Merged
merged 17 commits into from
Apr 8, 2024
Merged
3 changes: 3 additions & 0 deletions app/android/res/xml/file_paths.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="input_camera" path="./" />
<external-path
name="app_files"
path="Android/data/uk.co.lutraconsulting/" />
</paths>
43 changes: 43 additions & 0 deletions app/android/src/uk/co/lutraconsulting/InputActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
import android.graphics.Insets;
import android.graphics.Color;

import android.content.Intent;
import android.net.Uri;
import android.content.ActivityNotFoundException;
import java.io.File;
import androidx.core.content.FileProvider;
import android.widget.Toast;

import androidx.core.view.WindowCompat;
import androidx.core.splashscreen.SplashScreen;

Expand Down Expand Up @@ -115,6 +122,42 @@ public void hideSplashScreen()
keepSplashScreenVisible = false;
}

public void openFile( String filePath ) {
Log.d( TAG, "Expected file path: " + filePath );

File file = new File( filePath );

if ( !file.exists() ) {
Log.d( TAG, "File does not exist: " + filePath );
runOnUiThread( () -> Toast.makeText( getApplicationContext(), "File not available", Toast.LENGTH_SHORT ).show() );
return;
} else {
Log.d( TAG, "File exists: " + filePath );
}

Intent showFileIntent = new Intent( Intent.ACTION_VIEW );

try {
Uri fileUri = FileProvider.getUriForFile( this, "uk.co.lutraconsulting.fileprovider", file );
Log.d( TAG, "File URI: " + fileUri.toString() );

showFileIntent.setData( fileUri );

// FLAG_GRANT_READ_URI_PERMISSION grants temporary read permission to the content URI.
// FLAG_ACTIVITY_NEW_TASK is used when starting an Activity from a non-Activity context.
showFileIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION );
} catch ( IllegalArgumentException e ) {
Log.d( TAG, "FileProvider URI issue", e );
return;
}

if ( showFileIntent.resolveActivity( getPackageManager() ) != null ) {
startActivity( showFileIntent );
} else {
runOnUiThread( () -> Toast.makeText( getApplicationContext(), "No application for opening this file", Toast.LENGTH_SHORT ).show() );
}
}

public void quitGracefully()
{
String man = android.os.Build.MANUFACTURER.toUpperCase();
Expand Down
9 changes: 9 additions & 0 deletions app/androidutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ void AndroidUtils::hideSplashScreen()
#endif
}

void AndroidUtils::openFile( const QString &filePath )
{
#ifdef ANDROID
auto activity = QJniObject( QNativeInterface::QAndroidApplication::context() );
QJniObject jFilePath = QJniObject::fromString( filePath );
activity.callMethod<void>( "openFile", "(Ljava/lang/String;)V", jFilePath.object<jstring>() );
#endif
}

bool AndroidUtils::requestStoragePermission()
{
#ifdef ANDROID
Expand Down
1 change: 1 addition & 0 deletions app/androidutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class AndroidUtils: public QObject
*/
Q_INVOKABLE void callImagePicker( const QString &code = "" );
Q_INVOKABLE void callCamera( const QString &targetPath, const QString &code = "" );
Q_INVOKABLE void openFile( const QString &filePath );

#ifdef ANDROID
const static int MEDIA_CODE = 101;
Expand Down
35 changes: 34 additions & 1 deletion app/inpututils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QRegularExpression>
#include <QDesktopServices>
#include <algorithm>
#include <limits>
#include <math.h>
Expand Down Expand Up @@ -2141,3 +2141,36 @@ QList<QgsPoint> InputUtils::parsePositionUpdates( const QString &data )

return parsedUpdates;
}

void InputUtils::openLink( const QString &homePath, const QString &link )
{
qDebug() << "LINK" << link;
qDebug() << "HOMEPATH" << homePath;

QString cleanedLink = link.trimmed();
static QRegularExpression re( "^\\?|\\?$" );
cleanedLink.remove( re );

qDebug() << "cleanedLink" << cleanedLink;

if ( cleanedLink.startsWith( "project://" ) )
{
QString relativePath = cleanedLink.mid( QString( "project://" ).length() );
QString absoluteLinkPath = homePath + QDir::separator() + relativePath;

qDebug() << "relativePath" << relativePath;
qDebug() << "absoluteLinkPath" << absoluteLinkPath;

#ifdef Q_OS_ANDROID
qDebug() << "openLink android";
mAndroidUtils->openFile( absoluteLinkPath );
#elif defined(Q_OS_IOS)
qDebug() << "openLink ios";
#endif
}
else
{
cleanedLink.chop( 1 ); //remove \ from cleanedLink
QDesktopServices::openUrl( QUrl( cleanedLink) );
}
}
7 changes: 7 additions & 0 deletions app/inpututils.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ class InputUtils: public QObject
*/
Q_INVOKABLE static QString bytesToHumanSize( double bytes );

/**
* Opens the specified link in an appropriate application. For "project://" links, it converts them to
* absolute paths and opens with default file handlers. Other links are opened in the default web browser.
* @param link The link to open, either a "project://" link or a standard URL.
*/
Q_INVOKABLE void openLink( const QString &homePath, const QString &link );

Q_INVOKABLE bool acquireCameraPermission();

Q_INVOKABLE bool isBluetoothTurnedOn();
Expand Down
4 changes: 3 additions & 1 deletion app/qml/form/editors/MMFormTextMultilineEditor.qml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ MMBaseInput {
property var _fieldConfig: parent.fieldConfig
property bool _fieldValueIsNull: parent.fieldValueIsNull

property string _fieldHomePath: parent.fieldHomePath

property bool _fieldShouldShowTitle: parent.fieldShouldShowTitle
property bool _fieldIsReadOnly: parent.fieldIsReadOnly

Expand Down Expand Up @@ -87,7 +89,7 @@ MMBaseInput {
wrapMode: Text.WordWrap

onLinkActivated: function( link ) {
Qt.openUrlExternally( link )
__inputUtils.openLink( root._fieldHomePath, link )
}

onTextChanged: root.editorValueChanged( text, text === "" )
Expand Down
Loading