summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2021-03-31 10:58:01 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2021-03-31 20:07:54 +0200
commit4b8540911bc8fabee0729b31780a1ba8b4663121 (patch)
tree905eb00e313511e99dec66d0e6b0a5c40bec85a2
parent19e1f3723d4bfb91dadf77b398261da0e8237a8b (diff)
android: Use system file picker to create new docs
Similar to the way that existing documents can be opened from within the Android Viewer app using the system file picker by using 'Intent.ACTION_OPEN_DOCUMENT', use the system file picker via 'Intent.ACTION_CREATE_DOCUMENT' to create new docs as well, instead of providing a custom dialog to insert a file name. As described at [1], this allows to save files in locations supported by any existing DocumentsProvider (e.g. a Nextcloud share, if the Nextcloud app is installed and set up), not just locally. This also allows to further unify the handling in LOMainActivity. Just like for the cases where an existing document is opened using the system file picker or a document is passed from a third-party app, the document URI is now set in the Intent, a temporary file is used and writing back to the actual URI happens on save. Drop LibreOfficeMainActivity's method 'showSaveStatusMessage', which was only meant to be used when a new file was created, but was called from the more generic 'LOKitTileProvider::saveDocumentAs'. Change that to show a more general error message when saving fails. Since the actual file is now created by the DocumentsProvider, LOKitTileProvider only operates on the temporary copy anyway. Side note: With this change in place, overwriting existing files also no longer just happens silently, as used to be the case when typing the name of an existing file in the custom dialog for creating new files earlier. Since 'Intent.ACTION_OPEN_DOCUMENT' was introduced in SDK version 19 (Android 4.4), restrict creating new docs to corresponding devices. [1] https://developer.android.com/training/data-storage/shared/documents-files Change-Id: I8932cb892ca8ac97a04d15cbd1540d0ee68350da Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113408 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
-rw-r--r--android/source/res/values-de/strings.xml8
-rw-r--r--android/source/res/values-tr/strings.xml6
-rw-r--r--android/source/res/values/strings.xml8
-rw-r--r--android/source/src/java/org/libreoffice/LOKitTileProvider.java17
-rw-r--r--android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java75
-rw-r--r--android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java96
6 files changed, 105 insertions, 105 deletions
diff --git a/android/source/res/values-de/strings.xml b/android/source/res/values-de/strings.xml
index 4c6e25342ef7..6828066524c9 100644
--- a/android/source/res/values-de/strings.xml
+++ b/android/source/res/values-de/strings.xml
@@ -100,8 +100,6 @@
<string name="message_saving">Dokument wird gespeichert…</string>
<string name="message_save_incomplete">Speichern unvollständig. Gab es Änderungen?</string>
<string name="message_saving_failed">Speichern des Dokuments ist fehlgeschlagen.</string>
- <string name="create_new_file_success">"Neue Datei angelegt - "</string>
- <string name="create_new_file_error">Neue Datei konnte nicht angelegt weden, bitte Prüfen Sie den eingegeben Dateinamen.</string>
<!-- Document provider settings -->
<string name="storage_provider_settings">Speicheranbieter-Einstellungen</string>
@@ -128,10 +126,6 @@
<string name="action_cancel">Abbrechen</string>
<string name="no_save_document">NEIN</string>
- <!-- Create New Document Dialog Strings -->
- <string name="create_new_document_title">Dateiname eingeben</string>
- <string name="action_create">ANLEGEN</string>
-
<!-- Presentation Mode Strings -->
<string name="action_presentation">Präsentation</string>
<string name="action_add_slide">Folie hinzufügen</string>
@@ -223,8 +217,10 @@
<string name="display_language">Anzeigesprache</string>
<string name="display_language_summary">Wählen Sie die Standard-Anzeigesprache</string>
<string name="unable_to_export_pdf">PDF-Export nicht möglich</string>
+ <string name="unable_to_save">Speichern nicht möglich</string>
<string name="pdf_exported_at">PDF exportiert nach</string>
<string name="printing_not_supported">Ihr Gerät unterstützt Drucken nicht</string>
+ <string name="creating_new_files_not_supported">Erstellen neuer Dokumente auf diesem Gerät nicht verfügbar, benötigt Android-SDK-Version >= 19.</string>
<string name="error">Fehler</string>
<string name="enter_part_name">Name für Abschnitt eingeben</string>
<string name="bmp_null">Bmp ist null!</string>
diff --git a/android/source/res/values-tr/strings.xml b/android/source/res/values-tr/strings.xml
index 4ce70e91607d..357f441a8e86 100644
--- a/android/source/res/values-tr/strings.xml
+++ b/android/source/res/values-tr/strings.xml
@@ -96,8 +96,6 @@
<string name="message_saved">Kaydetme tamamlandı.</string>
<string name="message_saving">Belge kaydediliyor…</string>
<string name="message_save_incomplete">Kayıt tamamlanmadı. Değişiklik yapıldı mı?</string>
- <string name="create_new_file_success">"Yeni dosya oluşturuldu - "</string>
- <string name="create_new_file_error">Yeni dosya oluşturma başarısız. Lütfen dosya ismini kontrol ediniz.</string>
<!-- Document provider settings -->
<string name="storage_provider_settings">Depolama sağlayıcısı ayarları</string>
@@ -124,10 +122,6 @@
<string name="action_cancel">İptal</string>
<string name="no_save_document">Hayır</string>
- <!-- Create New Document Dialog Strings -->
- <string name="create_new_document_title">Dosya ismi girin</string>
- <string name="action_create">OLUŞTUR</string>
-
<!-- Presentation Mode Strings -->
<string name="action_presentation">Slayt Gösterisi</string>
<string name="action_add_slide">Slayt Ekle</string>
diff --git a/android/source/res/values/strings.xml b/android/source/res/values/strings.xml
index 8205176df685..5cd2c978cef5 100644
--- a/android/source/res/values/strings.xml
+++ b/android/source/res/values/strings.xml
@@ -100,8 +100,6 @@
<string name="message_saving">Saving the document…</string>
<string name="message_saving_failed">Saving the document failed.</string>
<string name="message_save_incomplete">Save incomplete. Were there any changes?</string>
- <string name="create_new_file_success">"Created new file - "</string>
- <string name="create_new_file_error">Unable to create new file, please check entered file name.</string>
<!-- Document provider settings -->
<string name="storage_provider_settings">Storage provider settings</string>
@@ -128,10 +126,6 @@
<string name="action_cancel">Cancel</string>
<string name="no_save_document">NO</string>
- <!-- Create New Document Dialog Strings -->
- <string name="create_new_document_title">Enter file name</string>
- <string name="action_create">CREATE</string>
-
<!-- Presentation Mode Strings -->
<string name="action_presentation">Slide show</string>
<string name="action_add_slide">Add Slide</string>
@@ -223,8 +217,10 @@
<string name="display_language">Display Language</string>
<string name="display_language_summary">Set the default display language</string>
<string name="unable_to_export_pdf">Unable to export to pdf</string>
+ <string name="unable_to_save">Unable to save file</string>
<string name="pdf_exported_at">Exported to PDF at</string>
<string name="printing_not_supported">Your device does not support printing</string>
+ <string name="creating_new_files_not_supported">Creating new files not supported on this device, requires Android SDK version >= 19.</string>
<string name="error">Error</string>
<string name="enter_part_name">Enter a part name</string>
<string name="bmp_null">Bmp is null!</string>
diff --git a/android/source/src/java/org/libreoffice/LOKitTileProvider.java b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
index 85eda566bae3..aafdbff311c1 100644
--- a/android/source/src/java/org/libreoffice/LOKitTileProvider.java
+++ b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
@@ -295,8 +295,6 @@ class LOKitTileProvider implements TileProvider {
}
}
-
-
@Override
public void saveDocumentAs(final String filePath, String format, boolean takeOwnership) {
String options = "";
@@ -327,7 +325,7 @@ class LOKitTileProvider implements TileProvider {
@Override
public void run() {
// There was some error
- mContext.showSaveStatusMessage(true);
+ mContext.showCustomStatusMessage(mContext.getString(R.string.unable_to_save));
}
});
}
@@ -348,17 +346,8 @@ class LOKitTileProvider implements TileProvider {
mContext.showCustomStatusMessage(mContext.getString(R.string.pdf_exported_at)+filePath);
}
});
- } else {
- if (takeOwnership) {
- mInputFile = filePath;
- }
- LOKitShell.getMainHandler().post(new Runnable() {
- @Override
- public void run() {
- // There was no error
- mContext.showSaveStatusMessage(false);
- }
- });
+ } else if (takeOwnership) {
+ mInputFile = filePath;
}
}
LOKitShell.hideProgressSpinner(mContext);
diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
index 6db06d155322..a070c292009c 100644
--- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
+++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -58,6 +58,7 @@ import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
/**
* Main activity of the LibreOffice App. It is started in the UI thread.
@@ -127,7 +128,7 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
private boolean isSearchToolbarOpen = false;
private static boolean isDocumentChanged = false;
private boolean isUNOCommandsToolbarOpen = false;
- public boolean isNewDocument = false;
+ private boolean isNewDocument = false;
private long lastModified = 0;
@Override
@@ -180,31 +181,35 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
mbISReadOnlyMode = !isExperimentalMode();
- if (getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY) != null) {
- // New document type string is not null, meaning we want to open a new document
- String newDocumentType = getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY);
- String newFilePath = getIntent().getStringExtra(LibreOfficeUIActivity.NEW_FILE_PATH_KEY);
-
- // Load the new document
- loadNewDocument(newFilePath, newDocumentType);
- } else if (getIntent().getData() != null) {
+ if (getIntent().getData() != null) {
if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
- if (copyFileToTemp() && mTempFile != null) {
+ final boolean isReadOnlyDoc;
+ if (getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY) != null) {
+ // New document type string is not null, meaning we want to open a new document
+ String newDocumentType = getIntent().getStringExtra(LibreOfficeUIActivity.NEW_DOC_TYPE_KEY);
+ // create a temporary local file, will be copied to the actual URI when saving
+ loadNewDocument(newDocumentType);
mInputFile = mTempFile;
- boolean isReadOnlyDoc = (getIntent().getFlags() & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
- mbISReadOnlyMode = !isExperimentalMode() || isReadOnlyDoc;
- Log.d(LOGTAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath());
-
- String displayName = extractDisplayNameFromIntent();
- if (displayName.isEmpty()) {
- // fall back to using temp file name
- displayName = mInputFile.getName();
- }
- toolbarTop.setTitle(displayName);
+ isReadOnlyDoc = false;
+ } else if (copyFileToTemp() && mTempFile != null) {
+ mInputFile = mTempFile;
+ isReadOnlyDoc = (getIntent().getFlags() & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
} else {
// TODO: can't open the file
Log.e(LOGTAG, "couldn't create temporary file from " + getIntent().getData());
+ return;
+ }
+
+ mbISReadOnlyMode = !isExperimentalMode() || isReadOnlyDoc;
+ Log.d(LOGTAG, "SCHEME_CONTENT: getPath(): " + getIntent().getData().getPath());
+
+ String displayName = extractDisplayNameFromIntent();
+ if (displayName.isEmpty()) {
+ // fall back to using temp file name
+ displayName = mInputFile.getName();
}
+ toolbarTop.setTitle(displayName);
+
} else if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_FILE)) {
mInputFile = new File(getIntent().getData().getPath());
Log.d(LOGTAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath());
@@ -280,12 +285,12 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
}
}
- // Loads a new Document
- private void loadNewDocument(String newFilePath, String newDocumentType) {
- mInputFile = new File(newFilePath);
- LOKitShell.sendNewDocumentLoadEvent(newFilePath, newDocumentType);
+ // Loads a new Document and saves it to a temporary file
+ private void loadNewDocument(String newDocumentType) {
+ String tempFileName = "LibreOffice_" + UUID.randomUUID().toString();
+ mTempFile = new File(this.getCacheDir(), tempFileName);
+ LOKitShell.sendNewDocumentLoadEvent(mTempFile.getPath(), newDocumentType);
isNewDocument = true;
- toolbarTop.setTitle(mInputFile.getName());
}
public RectF getCurrentCursorPosition() {
@@ -376,19 +381,8 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
if (documentUri != null) {
// case where file was opened using IDocumentProvider from within LO app
saveFilesToCloud();
- } else if (isNewDocument) {
- // nothing to do for actual save, the actual (local) file is already handled
- // by LOKitTileProvider
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(LibreOfficeMainActivity.this, R.string.message_saved,
- Toast.LENGTH_SHORT).show();
- }
- });
- setDocumentChanged(false);
} else {
- // case where file was passed via Intent
+ // case where file URI was passed via Intent
if (isReadOnlyMode() || mInputFile == null || getIntent().getData() == null || !getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT))
return;
@@ -1035,13 +1029,6 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
}
}
- // This method is used in LOKitTileProvider.java to show status of new file creation.
- public void showSaveStatusMessage(boolean error) {
- if (!error)
- Snackbar.make(mDrawerLayout, getString(R.string.create_new_file_success) + mInputFile.getName(), Snackbar.LENGTH_LONG).show();
- else
- Snackbar.make(mDrawerLayout, getString(R.string.create_new_file_error) + mInputFile.getName(), Snackbar.LENGTH_LONG).show(); }
-
public void showCustomStatusMessage(String message){
Snackbar.make(mDrawerLayout, message, Snackbar.LENGTH_LONG).show();
}
diff --git a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java
index 8e84868dbda5..517aa158035d 100644
--- a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java
+++ b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java
@@ -27,6 +27,7 @@ import android.graphics.drawable.Icon;
import android.hardware.usb.UsbManager;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -91,6 +92,14 @@ import java.util.List;
import java.util.Set;
public class LibreOfficeUIActivity extends AppCompatActivity implements SettingsListenerModel.OnSettingsPreferenceChangedListener, View.OnClickListener{
+ public enum DocumentType {
+ WRITER,
+ CALC,
+ IMPRESS,
+ DRAW,
+ INVALID
+ }
+
private String LOGTAG = LibreOfficeUIActivity.class.getSimpleName();
private SharedPreferences prefs;
private int filterMode = FileUtilities.ALL;
@@ -111,6 +120,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
private IFile currentDirectory;
private int currentlySelectedFile;
+ private DocumentType newDocType = DocumentType.INVALID;
+
private static final String CURRENT_DIRECTORY_KEY = "CURRENT_DIRECTORY";
private static final String DOC_PROVIDER_KEY = "CURRENT_DOCUMENT_PROVIDER";
private static final String FILTER_MODE_KEY = "FILTER_MODE";
@@ -121,7 +132,6 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
private static final String ENABLE_SHOW_HIDDEN_FILES_KEY = "ENABLE_SHOW_HIDDEN_FILES";
private static final String DISPLAY_LANGUAGE = "DISPLAY_LANGUAGE";
- public static final String NEW_FILE_PATH_KEY = "NEW_FILE_PATH_KEY";
public static final String NEW_DOC_TYPE_KEY = "NEW_DOC_TYPE_KEY";
public static final String NEW_WRITER_STRING_KEY = "private:factory/swriter";
public static final String NEW_IMPRESS_STRING_KEY = "private:factory/simpress";
@@ -172,6 +182,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
public static final int LIST_VIEW = 1;
private static final int REQUEST_CODE_OPEN_FILECHOOSER = 12345;
+ private static final int REQUEST_CODE_CREATE_NEW_DOCUMENT = 12346;
private DrawerLayout drawerLayout;
private NavigationView navigationDrawer;
@@ -487,6 +498,10 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
LibreOfficeMainActivity.class.getName());
intent.setComponent(componentName);
startActivity(intent);
+ } else if (requestCode == REQUEST_CODE_CREATE_NEW_DOCUMENT) {
+ // "forward" to LibreOfficeMainActivity to create + open the file
+ final Uri fileUri = data.getData();
+ loadNewDocument(newDocType, fileUri);
}
}
@@ -674,37 +689,50 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
}.execute(document);
}
- // Opens an Input dialog to get the name of new file
- private void createNewFileInputDialog(final String defaultFileName, final String newDocumentType) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.create_new_document_title);
- final EditText input = new EditText(this);
- input.setInputType(InputType.TYPE_CLASS_TEXT);
- input.setText(defaultFileName);
- builder.setView(input);
+ private void createNewFileDialog() {
+ final String extension;
+ if (newDocType == DocumentType.WRITER) {
+ extension = FileUtilities.DEFAULT_WRITER_EXTENSION;
+ } else if (newDocType == DocumentType.CALC) {
+ extension = FileUtilities.DEFAULT_SPREADSHEET_EXTENSION;
+ } else if (newDocType == DocumentType.IMPRESS) {
+ extension = FileUtilities.DEFAULT_IMPRESS_EXTENSION;
+ } else if (newDocType == DocumentType.DRAW) {
+ extension = FileUtilities.DEFAULT_DRAWING_EXTENSION;
+ } else {
+ Log.e(LOGTAG, "Invalid document type passed.");
+ return;
+ }
- builder.setPositiveButton(R.string.action_create, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final String newFilePath = currentDirectory.getUri().getPath() + input.getText().toString();
- loadNewDocument(newDocumentType, newFilePath);
- }
- });
+ String defaultFileName = getString(R.string.default_document_name) + extension;
+ String mimeType = FileUtilities.getMimeType(defaultFileName);
- builder.setNegativeButton(R.string.action_cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType(mimeType);
+ intent.putExtra(Intent.EXTRA_TITLE, defaultFileName);
- builder.show();
+ startActivityForResult(intent, REQUEST_CODE_CREATE_NEW_DOCUMENT);
}
- private void loadNewDocument(String newDocumentType, String newFilePath) {
+ private void loadNewDocument(DocumentType docType, Uri newFileUri) {
+ final String newDocumentType;
+ if (docType == DocumentType.WRITER) {
+ newDocumentType = NEW_WRITER_STRING_KEY;
+ } else if (docType == DocumentType.CALC) {
+ newDocumentType = NEW_CALC_STRING_KEY;
+ } else if (docType == DocumentType.IMPRESS) {
+ newDocumentType = NEW_IMPRESS_STRING_KEY;
+ } else if (docType == DocumentType.DRAW) {
+ newDocumentType = NEW_DRAW_STRING_KEY;
+ } else {
+ Log.w(LOGTAG, "invalid document type passed to loadNewDocument method. Ignoring request");
+ return;
+ }
+
Intent intent = new Intent(LibreOfficeUIActivity.this, LibreOfficeMainActivity.class);
intent.putExtra(NEW_DOC_TYPE_KEY, newDocumentType);
- intent.putExtra(NEW_FILE_PATH_KEY, newFilePath);
+ intent.setData(newFileUri);
startActivity(intent);
}
@@ -1158,6 +1186,12 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
int id = v.getId();
switch (id){
case R.id.editFAB:
+ // Intent.ACTION_CREATE_DOCUMENT, used in 'createNewFileDialog' requires SDK version 19
+ if (Build.VERSION.SDK_INT < 19) {
+ Toast.makeText(this,
+ getString(R.string.creating_new_files_not_supported), Toast.LENGTH_SHORT).show();
+ return;
+ }
if (isFabMenuOpen) {
collapseFabMenu();
} else {
@@ -1168,16 +1202,20 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
showSystemFilePickerAndOpenFile();
break;
case R.id.newWriterFAB:
- createNewFileInputDialog(getString(R.string.default_document_name) + FileUtilities.DEFAULT_WRITER_EXTENSION, NEW_WRITER_STRING_KEY);
+ newDocType = DocumentType.WRITER;
+ createNewFileDialog();
break;
case R.id.newImpressFAB:
- createNewFileInputDialog(getString(R.string.default_document_name) + FileUtilities.DEFAULT_IMPRESS_EXTENSION, NEW_IMPRESS_STRING_KEY);
+ newDocType = DocumentType.IMPRESS;
+ createNewFileDialog();
break;
case R.id.newCalcFAB:
- createNewFileInputDialog(getString(R.string.default_document_name) + FileUtilities.DEFAULT_SPREADSHEET_EXTENSION, NEW_CALC_STRING_KEY);
+ newDocType = DocumentType.CALC;
+ createNewFileDialog();
break;
case R.id.newDrawFAB:
- createNewFileInputDialog(getString(R.string.default_document_name) + FileUtilities.DEFAULT_DRAWING_EXTENSION, NEW_DRAW_STRING_KEY);
+ newDocType = DocumentType.DRAW;
+ createNewFileDialog();
break;
}
}