diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2021-04-15 08:57:56 +0200 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2021-04-16 08:47:59 +0200 |
commit | d16e569209fe40c2cb5776f7b9415e273d5b2387 (patch) | |
tree | f9a625921abadabac5dd1b4f11209b1d756cf0fa /android | |
parent | a2b4564d719e6efeb614052b9c833991e447c68c (diff) |
android: Add a "Save As..." menu entry
This adds a "Save As..." menu entry to Android
Viewer in order to save the currently opened file
to a different location.
Currently, the file is always saved in the corresponding
ODF format, regardless of the original file type,
i.e. that e.g. a DOCX file is saved in ODT format.
(This could be extended to allow a selection of the
target format as needed.)
Like "Save As" (and as compared to "Save a Copy")
in the desktop version, the app remembers the
new document URI and subsequent save operations
will overwrite the newly saved file, not the originally
opened one.
(There is no need to create a new temporary
local file to use, though.)
The directory of the currently used file
is preselected in the file chooser used to
specify where to save the new file.
Make sure to copy the file in a non-main thread,
since the destination URI might be handled
by a DocumentsProvider that does network access.
However, for now the main thread just waits for
the separate thread to finish, just like
commit 7f838b73e85eb6f0a1dce4647650a5cf5f34ccd2
Date: Fri Mar 19 15:46:36 2021 +0100
tdf#129833 android: Move reading file to separate thread
implemented it for copying from the URI to the
temporary file when opening a file.
This also adds a 'TileProvider#isDrawing' method
(like the already existing 'isTextDocument',
'isSpreadsheet' and 'isPresentation' ones).
Change-Id: I6f56b71763431b89a6c74be35cc1e81fad136cd0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114058
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'android')
8 files changed, 125 insertions, 8 deletions
diff --git a/android/source/res/menu/main.xml b/android/source/res/menu/main.xml index 2c97b3201b9e..94856d52e759 100644 --- a/android/source/res/menu/main.xml +++ b/android/source/res/menu/main.xml @@ -36,6 +36,10 @@ android:title="@string/action_save" android:orderInCategory="100" /> + <item android:id="@+id/action_save_as" + android:title="@string/action_save_as" + android:orderInCategory="100" /> + <item android:id="@+id/action_exportToPDF" android:title="@string/action_exportToPDF" android:orderInCategory="100" diff --git a/android/source/res/values-de/strings.xml b/android/source/res/values-de/strings.xml index 639ddca4d9ef..c2c33ff5b5e5 100644 --- a/android/source/res/values-de/strings.xml +++ b/android/source/res/values-de/strings.xml @@ -48,6 +48,7 @@ <string name="action_strikeout">Durchgestrichen</string> <string name="action_keyboard">Tastatur anzeigen</string> <string name="action_save">Speichern</string> + <string name="action_save_as">Speichern unter...</string> <string name="action_fromat">Format anwenden</string> <string name="action_search">Suchen</string> <string name="action_UNO_commands">UNO-Kommando senden</string> diff --git a/android/source/res/values/strings.xml b/android/source/res/values/strings.xml index 5e7ad1e3ded7..d0014646bc15 100644 --- a/android/source/res/values/strings.xml +++ b/android/source/res/values/strings.xml @@ -47,6 +47,7 @@ <string name="action_strikeout">Strike Out</string> <string name="action_keyboard">Show keyboard</string> <string name="action_save">Save</string> + <string name="action_save_as">Save As...</string> <string name="action_fromat">Enable Format</string> <string name="action_search">Search</string> <string name="action_UNO_commands">Send UNO Cmd</string> diff --git a/android/source/src/java/org/libreoffice/LOKitTileProvider.java b/android/source/src/java/org/libreoffice/LOKitTileProvider.java index 2fb3551eada2..5f4684703f36 100644 --- a/android/source/src/java/org/libreoffice/LOKitTileProvider.java +++ b/android/source/src/java/org/libreoffice/LOKitTileProvider.java @@ -632,6 +632,14 @@ class LOKitTileProvider implements TileProvider { } /** + * @see TileProvider#isDrawing() + */ + @Override + public boolean isDrawing() { + return mDocument != null && mDocument.getDocumentType() == Document.DOCTYPE_DRAWING; + } + + /** * @see TileProvider#isTextDocument() */ @Override diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java index d97719afb726..255c4d5bdd95 100644 --- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -14,6 +14,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; +import android.provider.DocumentsContract; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.Snackbar; import android.support.v4.widget.DrawerLayout; @@ -62,6 +63,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin private static final String ENABLE_EXPERIMENTAL_PREFS_KEY = "ENABLE_EXPERIMENTAL"; private static final String ASSETS_EXTRACTED_PREFS_KEY = "ASSETS_EXTRACTED"; private static final String ENABLE_DEVELOPER_PREFS_KEY = "ENABLE_DEVELOPER"; + private static final int REQUEST_CODE_SAVEAS = 12345; //TODO "public static" is a temporary workaround public static LOKitThread loKitThread; @@ -309,6 +311,56 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND_NOTIFY, ".uno:Save", true)); } + /** + * Open file chooser and save the document to the URI + * selected there. + */ + public void saveDocumentAs() { + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + String mimeType = getODFMimeTypeForDocument(); + intent.setType(mimeType); + intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, mDocumentUri); + + startActivityForResult(intent, REQUEST_CODE_SAVEAS); + } + + /** + * Saves the document under the given URI using ODF format + * and uses that URI from now on for all operations. + * @param newUri URI to save the document and use from now on. + */ + private void saveDocumentAs(Uri newUri) { + mDocumentUri = newUri; + // save in ODF format + mTileProvider.saveDocumentAs(mTempFile.getPath(), true); + saveFileToOriginalSource(); + + String displayName = FileUtilities.retrieveDisplayNameForDocumentUri(getContentResolver(), mDocumentUri); + toolbarTop.setTitle(displayName); + } + + /** + * Returns the ODF MIME type that can be used for the current document, + * regardless of whether the document is an ODF Document or not + * (e.g. returns FileUtilities.MIMETYPE_OPENDOCUMENT_TEXT for a DOCX file). + * @return MIME type, or empty string, if no appropriate MIME type could be found. + */ + private String getODFMimeTypeForDocument() { + if (mTileProvider.isTextDocument()) + return FileUtilities.MIMETYPE_OPENDOCUMENT_TEXT; + else if (mTileProvider.isSpreadsheet()) + return FileUtilities.MIMETYPE_OPENDOCUMENT_SPREADSHEET; + else if (mTileProvider.isPresentation()) + return FileUtilities.MIMETYPE_OPENDOCUMENT_PRESENTATION; + else if (mTileProvider.isDrawing()) + return FileUtilities.MIMETYPE_OPENDOCUMENT_GRAPHICS; + else { + Log.w(LOGTAG, "Cannot determine MIME type to use."); + return ""; + } + } + public void saveFileToOriginalSource() { if (isReadOnlyMode() || mTempFile == null || mDocumentUri == null || !mDocumentUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) return; @@ -316,8 +368,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin boolean copyOK = false; try { final FileInputStream inputStream = new FileInputStream(mTempFile); - final OutputStream outputStream = getContentResolver().openOutputStream(mDocumentUri); - copyOK = copyStream(inputStream, outputStream); + copyOK = copyStreamToUri(inputStream, mDocumentUri); } catch (FileNotFoundException e) { e.printStackTrace(); } @@ -922,6 +973,40 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin return copyThread.result; } + /** + * Copies everything from the given InputStream to the given URI and closes the + * InputStream in the end. + * @see LibreOfficeMainActivity#copyUriToStream(Uri, OutputStream) + * which does the same thing the other way around. + */ + private boolean copyStreamToUri(final InputStream inputStream, final Uri outputUri) { + class CopyThread extends Thread { + /** Whether copy operation was successful. */ + private boolean result = false; + + @Override + public void run() { + final ContentResolver contentResolver = getContentResolver(); + try { + OutputStream outputStream = contentResolver.openOutputStream(outputUri); + result = copyStream(inputStream, outputStream); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + CopyThread copyThread = new CopyThread(); + copyThread.start(); + try { + // wait for copy operation to finish + // NOTE: might be useful to add some indicator in UI for long copy operations involving network... + copyThread.join(); + } catch(InterruptedException e) { + e.printStackTrace(); + } + return copyThread.result; + } + public void showCustomStatusMessage(String message){ Snackbar.make(mDrawerLayout, message, Snackbar.LENGTH_LONG).show(); } @@ -958,8 +1043,13 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mFormattingController.handleActivityResult(requestCode, resultCode, data); - hideBottomToolbar(); + if (requestCode == REQUEST_CODE_SAVEAS && resultCode == RESULT_OK) { + final Uri fileUri = data.getData(); + saveDocumentAs(fileUri); + } else { + mFormattingController.handleActivityResult(requestCode, resultCode, data); + hideBottomToolbar(); + } } } diff --git a/android/source/src/java/org/libreoffice/TileProvider.java b/android/source/src/java/org/libreoffice/TileProvider.java index 1a20c8b080d0..ea93d5b5c803 100644 --- a/android/source/src/java/org/libreoffice/TileProvider.java +++ b/android/source/src/java/org/libreoffice/TileProvider.java @@ -86,6 +86,11 @@ public interface TileProvider { void close(); /** + * Returns true if the current open document is a drawing. + */ + boolean isDrawing(); + + /** * Returns true if the current open document is a text document. */ boolean isTextDocument(); diff --git a/android/source/src/java/org/libreoffice/ToolbarController.java b/android/source/src/java/org/libreoffice/ToolbarController.java index 308bc9e6b254..ceea83a2b311 100644 --- a/android/source/src/java/org/libreoffice/ToolbarController.java +++ b/android/source/src/java/org/libreoffice/ToolbarController.java @@ -174,6 +174,9 @@ public class ToolbarController implements Toolbar.OnMenuItemClickListener { case R.id.action_save: mContext.getTileProvider().saveDocument(); return true; + case R.id.action_save_as: + mContext.saveDocumentAs(); + return true; case R.id.action_parts: mContext.openDrawer(); return true; diff --git a/android/source/src/java/org/libreoffice/ui/FileUtilities.java b/android/source/src/java/org/libreoffice/ui/FileUtilities.java index 5bcc48d31141..8422e845dd40 100644 --- a/android/source/src/java/org/libreoffice/ui/FileUtilities.java +++ b/android/source/src/java/org/libreoffice/ui/FileUtilities.java @@ -38,6 +38,11 @@ public class FileUtilities { public static final String DEFAULT_SPREADSHEET_EXTENSION = ".ods"; public static final String DEFAULT_DRAWING_EXTENSION = ".odg"; + public static final String MIMETYPE_OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text"; + public static final String MIMETYPE_OPENDOCUMENT_SPREADSHEET = "application/vnd.oasis.opendocument.spreadsheet"; + public static final String MIMETYPE_OPENDOCUMENT_PRESENTATION = "application/vnd.oasis.opendocument.presentation"; + public static final String MIMETYPE_OPENDOCUMENT_GRAPHICS = "application/vnd.oasis.opendocument.graphics"; + private static final Map<String, Integer> mExtnMap = new HashMap<String, Integer>(); private static final Map<String, String> extensionToMimeTypeMap = new HashMap<String, String>(); static { @@ -101,14 +106,14 @@ public class FileUtilities { // Android's MimeTypeMap lacks some types that we need extensionToMimeTypeMap.put("odb", "application/vnd.oasis.opendocument.database"); extensionToMimeTypeMap.put("odf", "application/vnd.oasis.opendocument.formula"); - extensionToMimeTypeMap.put("odg", "application/vnd.oasis.opendocument.graphics"); + extensionToMimeTypeMap.put("odg", MIMETYPE_OPENDOCUMENT_GRAPHICS); extensionToMimeTypeMap.put("otg", "application/vnd.oasis.opendocument.graphics-template"); extensionToMimeTypeMap.put("odi", "application/vnd.oasis.opendocument.image"); - extensionToMimeTypeMap.put("odp", "application/vnd.oasis.opendocument.presentation"); + extensionToMimeTypeMap.put("odp", MIMETYPE_OPENDOCUMENT_PRESENTATION); extensionToMimeTypeMap.put("otp", "application/vnd.oasis.opendocument.presentation-template"); - extensionToMimeTypeMap.put("ods", "application/vnd.oasis.opendocument.spreadsheet"); + extensionToMimeTypeMap.put("ods", MIMETYPE_OPENDOCUMENT_SPREADSHEET); extensionToMimeTypeMap.put("ots", "application/vnd.oasis.opendocument.spreadsheet-template"); - extensionToMimeTypeMap.put("odt", "application/vnd.oasis.opendocument.text"); + extensionToMimeTypeMap.put("odt", MIMETYPE_OPENDOCUMENT_TEXT); extensionToMimeTypeMap.put("odm", "application/vnd.oasis.opendocument.text-master"); extensionToMimeTypeMap.put("ott", "application/vnd.oasis.opendocument.text-template"); extensionToMimeTypeMap.put("oth", "application/vnd.oasis.opendocument.text-web"); |