From 12b33dce25a22e99c4f86f1ff139efb8dd144117 Mon Sep 17 00:00:00 2001 From: Patrick Luby Date: Fri, 5 Jan 2024 09:55:26 -0500 Subject: [PATCH] Eliminate hang in iOS app (and maybe the Android app) during export When exporting a document via this path, such as exporting to PDF via the .uno:ExportToPDF command, any exceptions thrown while saving the current document will leave the app in a blocked state if a "PENDING" message has been sent. The iOS app (and maybe the Android app) fails to set the URL to save to so we need to set it to a temporary file. Note: the iOS app is responsible for deleting the temporary file. Also, enable building iOS with TLS=OPENSSL by default. Signed-off-by: Patrick Luby Change-Id: Ibc070bed4e792bb0a481d2b900d12d214e3c519f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161692 Tested-by: Jenkins CollaboraOffice Reviewed-by: Andras Timar Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162125 Tested-by: Jenkins --- distro-configs/LibreOfficeiOS.conf | 3 +- distro-configs/LibreOfficeiOS_Sim.conf | 3 +- sfx2/source/doc/guisaveas.cxx | 68 ++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/distro-configs/LibreOfficeiOS.conf b/distro-configs/LibreOfficeiOS.conf index c0ba243ab840..ab36e05ba668 100644 --- a/distro-configs/LibreOfficeiOS.conf +++ b/distro-configs/LibreOfficeiOS.conf @@ -24,7 +24,8 @@ --disable-poppler --disable-python ---without-tls +# OpenSSL is the default +#--with-tls=openssl # iOS device --host=arm64-apple-ios diff --git a/distro-configs/LibreOfficeiOS_Sim.conf b/distro-configs/LibreOfficeiOS_Sim.conf index c121a29a9879..03558256657a 100644 --- a/distro-configs/LibreOfficeiOS_Sim.conf +++ b/distro-configs/LibreOfficeiOS_Sim.conf @@ -24,7 +24,8 @@ --disable-poppler --disable-python ---without-tls +# OpenSSL is the default +#--with-tls=openssl # iOS simulator (debug) --enable-ios-simulator diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx index 657d162ff732..7b286321c217 100644 --- a/sfx2/source/doc/guisaveas.cxx +++ b/sfx2/source/doc/guisaveas.cxx @@ -1101,12 +1101,48 @@ bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, if (comphelper::LibreOfficeKit::isActive()) { - // keep name with extension - aSuggestedName = aRecommendedName; - OUString aExtension; - if (size_t nPos = aSuggestedName.lastIndexOf('.') + 1) - aExtension = aSuggestedName.copy(nPos, aSuggestedName.getLength() - nPos); - aURL.SetExtension(aExtension); +#ifdef IOS + // The iOS app (and maybe the Android app) have fails to set the URL to + // save to so we need to set it to a temporary file. + // Note: the iOS app is responsible for deleting the temporary file. + if (nStoreMode & EXPORT_REQUESTED && aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE).isEmpty()) + { + // Mirror the "export/docbasename.pdf" path format to match the + // format used in the "downloadas" message handler in the iOS app's + // -[DocumentViewController userContentController:didReceiveScriptMessage] + // selector. + // Important note: temporary files created here must be in their + // own subdirectory since the iOS app's UIDocumentPickerDelegate + // will try to delete both the temporary file and its parent + // directory. + OUString aFullName = u"export/" + aRecommendedName; + OUString aBaseName; + OUString aExtension; + sal_Int32 nPos = aFullName.lastIndexOf( '.' ); + if ( nPos >= 0 ) + { + aBaseName = aFullName.copy(0, nPos); + aExtension = aFullName.copy(nPos, aFullName.getLength() - nPos); + } + aURL = INetURLObject(::utl::CreateTempURL( aBaseName, false, aExtension, nullptr, true)); + + // Remove any stale files left from a previous export + OUString fileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + if (!fileURL.isEmpty()) + osl::File::remove(fileURL); + } + else + { +#endif + // keep name with extension + aSuggestedName = aRecommendedName; + OUString aExtension; + if (size_t nPos = aSuggestedName.lastIndexOf('.') + 1) + aExtension = aSuggestedName.copy(nPos, aSuggestedName.getLength() - nPos); + aURL.SetExtension(aExtension); +#ifdef IOS + } +#endif } else { @@ -1822,10 +1858,22 @@ bool SfxStoringHelper::FinishGUIStoreModel(::comphelper::SequenceAsHashMap::cons // this is actually a save operation with different parameters // so storeTo or storeAs without DocInfo operations are used - if ( nStoreMode & EXPORT_REQUESTED ) - aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); - else - aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); +#ifdef IOS + try + { +#endif + if ( nStoreMode & EXPORT_REQUESTED ) + aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); + else + aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); +#ifdef IOS + } + catch( const uno::Exception& ) + { + // When using the iOS app (and maybe the Android app), the app + // will remain blocked if we rethrow an exception. + } +#endif } // Launch PDF viewer