summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2021-04-15 08:57:56 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2021-04-16 10:16:52 +0200
commit5a373d0ea8ba70e5b3ce3f7fb406a1f74f403ad8 (patch)
tree13f780a46ee6f00fb552d4bb108ea9d24c8f1baa
parent514e2b142f8c2d015996e333663ae4eb20bdbc65 (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> (cherry picked from commit d16e569209fe40c2cb5776f7b9415e273d5b2387)
-rw-r--r--android/source/res/menu/main.xml4
-rw-r--r--android/source/res/values-de/strings.xml1
-rw-r--r--android/source/res/values/strings.xml1
-rw-r--r--android/source/src/java/org/libreoffice/LOKitTileProvider.java8
-rw-r--r--android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java98
-rw-r--r--android/source/src/java/org/libreoffice/TileProvider.java5
-rw-r--r--android/source/src/java/org/libreoffice/ToolbarController.java3
-rw-r--r--android/source/src/java/org/libreoffice/ui/FileUtilities.java13
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");