[Libreoffice-commits] online.git: android/app

Jan Holesovsky (via logerrit) logerrit at kemper.freedesktop.org
Thu Jan 2 17:09:38 UTC 2020


 android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java          |    9 -
 android/app/src/main/java/org/libreoffice/androidapp/storage/external/BrowserSelectorActivity.java |    4 
 android/app/src/main/java/org/libreoffice/androidapp/storage/external/ExtsdDocumentsProvider.java  |   85 +++++-----
 android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java                 |   63 +++++--
 4 files changed, 92 insertions(+), 69 deletions(-)

New commits:
commit b0f763a88339d0e5f8dfbd1f5a5d07edfe6d1cdf
Author:     Jan Holesovsky <kendy at collabora.com>
AuthorDate: Thu Jan 2 17:26:45 2020 +0100
Commit:     Jan Holesovsky <kendy at collabora.com>
CommitDate: Thu Jan 2 18:09:20 2020 +0100

    android: Enable and fix the access to the external SD card (if present).
    
    It is necessary to trigger the system dialog to get the user's consent
    to access the SD card, so let's show it right away instead of forcing
    the user into the general provider settings activity.
    
    Remove various sub-Android-5 code.
    
    Various other details here and there to make it work.
    
    Change-Id: Ic06ce39d17778c97e8e5c8f38b8ecf34338c3c28
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/86137
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java
index 66627c6f0..9590ebe35 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/DocumentProviderFactory.java
@@ -106,15 +106,6 @@ public final class DocumentProviderFactory {
         return providerNames;
     }
 
-    /**
-     * Returns the default provider.
-     *
-     * @return default provider.
-     */
-    public IDocumentProvider getDefaultProvider() {
-        return providers[0];
-    }
-
     public Set<OnSharedPreferenceChangeListener> getChangeListeners() {
         Set<OnSharedPreferenceChangeListener> listeners =
                 new HashSet<OnSharedPreferenceChangeListener>();
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/external/BrowserSelectorActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/external/BrowserSelectorActivity.java
index d4c2e830c..eb7b49ade 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/storage/external/BrowserSelectorActivity.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/external/BrowserSelectorActivity.java
@@ -124,6 +124,10 @@ public class BrowserSelectorActivity extends AppCompatActivity {
         unregisterListeners();
         Log.d(LOGTAG, "Preference saved: " +
                 preferences.getString(preferenceKey, getString(R.string.directory_not_saved)));
+
+        // pass the result to whoever has called us
+        Intent resultIntent = new Intent();
+        setResult(resultCode, resultIntent);
         finish();
     }
 
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/storage/external/ExtsdDocumentsProvider.java b/android/app/src/main/java/org/libreoffice/androidapp/storage/external/ExtsdDocumentsProvider.java
index 2cb8cc72e..c6f481910 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/storage/external/ExtsdDocumentsProvider.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/storage/external/ExtsdDocumentsProvider.java
@@ -1,3 +1,12 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
 package org.libreoffice.androidapp.storage.external;
 
 import android.Manifest;
@@ -22,15 +31,15 @@ import androidx.core.content.ContextCompat;
 import androidx.documentfile.provider.DocumentFile;
 
 /**
- * Implementation of IDocumentProvider for the external file system, for android 4.4+
+ * Implementation of IDocumentProvider for the external file system.
  *
- * The DocumentFile class is required when accessing files in external storage
- * for Android 4.4+. The ExternalFile class is used to handle this.
+ * https://stackoverflow.com/questions/40068984/universal-way-to-write-to-external-sd-card-on-android
+ * https://developer.android.com/training/data-storage/shared/documents-files
  *
- * Android 4.4 & 5+ use different types of root directory paths,
- * 5 using a DirectoryTree Uri and 4.4 using a normal File path.
- * As such, different methods are required to obtain the rootDirectory IFile.
- * 4.4 has to guess the location of the rootDirectory as well.
+ * On the Android versions we target, it's not possible to access files on a
+ * SD card directly, first you need to trigger the system file picker
+ * (Intert.ACTION_OPEN_DOCUMENT_TREE), and then you have to access the files
+ * via the content provider you've got.
  */
 public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
         OnSharedPreferenceChangeListener{
@@ -38,7 +47,7 @@ public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
 
     private int id;
     private File cacheDir;
-    private String rootPathURI;
+    private boolean hasRemovableStorage = false;
 
     public ExtsdDocumentsProvider(int id, Context context) {
         this.id = id;
@@ -47,16 +56,26 @@ public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
     }
 
     private void setupRootPathUri(Context context) {
-        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
-        rootPathURI = preferences.getString(
-                DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI, guessRootURI(context));
+        String rootURI = guessRootURI(context);
+        if (rootURI != null && !rootURI.isEmpty())
+            hasRemovableStorage = true;
     }
 
+    /**
+     * Even though this provides a file:///-like path, it is not possible to
+     * use the files there directly, we have to go through the content:// url
+     * that we get from the Intent.ACTION_OPEN_DOCUMENT_TREE.
+     *
+     * But it is useful to still keep this code, to decide whether we should
+     * show the "External SD" in the menu or not.
+     */
+    @Override
     public String guessRootURI(Context context) {
         // TODO: unfortunately the getExternalFilesDirs function relies on devices to actually
         // follow guidelines re external storage. Of course device manufacturers don't and as such
         // you cannot rely on it returning the actual paths (neither the compat, nor the native variant)
-        File[] possibleRemovables = ContextCompat.getExternalFilesDirs(context,null);
+        File[] possibleRemovables = ContextCompat.getExternalFilesDirs(context, null);
+
         // the primary dir that is already covered by the "LocalDocumentsProvider"
         // might be emulated/part of internal memory or actual SD card
         // TODO: change to not confuse android's "external storage" with "expandable storage"
@@ -65,17 +84,22 @@ public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
         for (File option: possibleRemovables) {
             // Returned paths may be null if a storage device is unavailable.
             if (null == option) {
-                Log.w(LOGTAG,"path was a null option :-/"); continue; }
+                Log.w(LOGTAG, "path was a null option :-/");
+                continue;
+            }
+
             String optionPath = option.getAbsolutePath();
-            if(optionPath.contains(primaryExternal)) {
+            if (optionPath.startsWith(primaryExternal)) {
                 Log.v(LOGTAG, "did get file path - but is same as primary storage ("+ primaryExternal +")");
                 continue;
             }
 
-            return option.toURI().toString();
+            String optionURI = Uri.fromFile(option).toString();
+
+            Log.d(LOGTAG, "got the path: " + optionURI);
+            return optionURI;
         }
 
-        // TODO: do some manual probing of possible directories (/storage/sdcard1 and similar)
         Log.i(LOGTAG, "no secondary storage reported");
         return null;
     }
@@ -103,24 +127,11 @@ public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
 
     @Override
     public IFile getRootDirectory(Context context) {
-        if(android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
-            return android4RootDirectory(context);
-        } else {
-            return android5RootDirectory(context);
-        }
-    }
-
-    private ExternalFile android4RootDirectory(Context context) {
-        try{
-            File f = new File(new URI(rootPathURI));
-            return new ExternalFile(this, DocumentFile.fromFile(f), context);
-        } catch (Exception e) {
-            //invalid rootPathURI
+        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+        String rootPathURI = preferences.getString(DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI, "");
+        if (rootPathURI.isEmpty())
             throw buildRuntimeExceptionForInvalidFileURI(context);
-        }
-    }
 
-    private ExternalFile android5RootDirectory(Context context) {
         try {
             return new ExternalFile(this,
                                     DocumentFile.fromTreeUri(context, Uri.parse(rootPathURI)),
@@ -164,16 +175,10 @@ public class ExtsdDocumentsProvider implements IExternalDocumentProvider,
         // but they refer to the primary external storage anyway, so what currently is covered by the
         // "LocalDocumentsProvider"
 
-        // FIXME temporarily disabled for good
-        return false;
-        //return rootPathURI!=null && ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
+        return hasRemovableStorage && ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
     }
 
     @Override
-    public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
-        if (key.equals(DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI)) {
-            rootPathURI = preferences.getString(key, "");
-        }
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
     }
-
 }
diff --git a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
index 2317d42ad..389f9b5a7 100644
--- a/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
+++ b/android/app/src/main/java/org/libreoffice/androidapp/ui/LibreOfficeUIActivity.java
@@ -66,6 +66,7 @@ import org.libreoffice.androidapp.storage.DocumentProviderFactory;
 import org.libreoffice.androidapp.storage.DocumentProviderSettingsActivity;
 import org.libreoffice.androidapp.storage.IDocumentProvider;
 import org.libreoffice.androidapp.storage.IFile;
+import org.libreoffice.androidapp.storage.external.BrowserSelectorActivity;
 import org.libreoffice.androidlib.LOActivity;
 
 import java.io.File;
@@ -115,7 +116,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
     FilenameFilter filenameFilter;
     private List<IFile> filePaths = new ArrayList<IFile>();
     private DocumentProviderFactory documentProviderFactory;
-    private IDocumentProvider documentProvider;
+    private IDocumentProvider documentProvider = null;
     private IFile homeDirectory;
     private IFile currentDirectory;
     private int currentlySelectedFile;
@@ -168,6 +169,7 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
 
     /** Request code to evaluate that we are returning from the LOActivity. */
     private static final int LO_ACTIVITY_REQUEST_CODE = 42;
+    private static final int SD_CARD_REQUEST_CODE = 43;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -199,10 +201,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
     }
 
     public void createUI() {
-
         setContentView(R.layout.activity_document_browser);
 
-
         Toolbar toolbar = findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
 
@@ -279,27 +279,27 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
                     }
 
                     case R.id.menu_provider_documents: {
-                        switchToDocumentProvider(documentProviderFactory.getProvider(0));
+                        switchToDocumentProvider(0);
                         return true;
                     }
 
                     case R.id.menu_provider_filesystem: {
-                        switchToDocumentProvider(documentProviderFactory.getProvider(1));
+                        switchToDocumentProvider(1);
                         return true;
                     }
 
                     case R.id.menu_provider_extsd: {
-                        switchToDocumentProvider(documentProviderFactory.getProvider(2));
+                        switchToDocumentProvider(DocumentProviderFactory.EXTSD_PROVIDER_INDEX);
                         return true;
                     }
 
                     case R.id.menu_provider_otg: {
-                        switchToDocumentProvider(documentProviderFactory.getProvider(3));
+                        switchToDocumentProvider(3);
                         return true;
                     }
 
                     case R.id.menu_provider_owncloud: {
-                        switchToDocumentProvider(documentProviderFactory.getProvider(4));
+                        switchToDocumentProvider(4);
                         return true;
                     }
 
@@ -430,11 +430,14 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
         return viewMode == LIST_VIEW;
     }
 
-    private void switchToDocumentProvider(IDocumentProvider provider) {
+    private void switchToDocumentProvider(int providerId) {
+        IDocumentProvider provider = documentProviderFactory.getProvider(providerId);
 
         new AsyncTask<IDocumentProvider, Void, Void>() {
             @Override
             protected Void doInBackground(IDocumentProvider... provider) {
+                Log.d(LOGTAG, "switching to document provider " + provider[0].getId());
+
                 // switch document provider:
                 // these operations may imply network access and must be run in
                 // a different thread
@@ -453,15 +456,28 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
                         }
                     }
                 } catch (final RuntimeException e) {
-                    final Activity activity = LibreOfficeUIActivity.this;
-                    activity.runOnUiThread(new Runnable() {
-                        @Override
-                        public void run() {
-                            Toast.makeText(activity, e.getMessage(),
-                                    Toast.LENGTH_SHORT).show();
-                        }
-                    });
-                    startActivity(new Intent(activity, DocumentProviderSettingsActivity.class));
+                    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(LibreOfficeUIActivity.this);
+                    String sdPath = preferences.getString(DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI, "");
+
+                    if (provider[0].getId() != DocumentProviderFactory.EXTSD_PROVIDER_INDEX || !sdPath.isEmpty()) {
+                        LibreOfficeUIActivity.this.runOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                Toast.makeText(LibreOfficeUIActivity.this, e.getMessage(),
+                                        Toast.LENGTH_SHORT).show();
+                            }
+                        });
+                    }
+
+                    if (provider[0].getId() == DocumentProviderFactory.EXTSD_PROVIDER_INDEX) {
+                        Intent i = new Intent(LibreOfficeUIActivity.this, BrowserSelectorActivity.class);
+                        i.putExtra(BrowserSelectorActivity.PREFERENCE_KEY_EXTRA, DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI);
+                        i.putExtra(BrowserSelectorActivity.MODE_EXTRA, BrowserSelectorActivity.MODE_EXT_SD);
+                        startActivityForResult(i, SD_CARD_REQUEST_CODE);
+                    }
+                    else
+                        startActivity(new Intent(LibreOfficeUIActivity.this, DocumentProviderSettingsActivity.class));
+
                     Log.e(LOGTAG, "failed to switch document provider " + e.getMessage(), e.getCause());
                     return null;
                 }
@@ -1046,6 +1062,11 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
             Log.d(LOGTAG, "LOActivity has finished.");
             saveFileToCloud();
         }
+        else if (requestCode == SD_CARD_REQUEST_CODE) {
+            Log.d(LOGTAG, "SD card chooser has finished.");
+            if (resultCode == RESULT_OK)
+                switchToDocumentProvider(DocumentProviderFactory.EXTSD_PROVIDER_INDEX);
+        }
     }
 
     /** Actually copy the file to the remote storage (if applicable). */
@@ -1109,7 +1130,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
                     new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                     PERMISSION_WRITE_EXTERNAL_STORAGE);
         } else {
-            switchToDocumentProvider(documentProviderFactory.getDefaultProvider());
+            if (documentProvider == null)
+                switchToDocumentProvider(0);
             setEditFABVisibility(View.VISIBLE);
         }
         Log.d(LOGTAG, "onStart");
@@ -1368,7 +1390,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings
         switch (requestCode) {
             case PERMISSION_WRITE_EXTERNAL_STORAGE:
                 if (permissions.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-                    switchToDocumentProvider(documentProviderFactory.getDefaultProvider());
+                    if (documentProvider == null)
+                        switchToDocumentProvider(0);
                     setEditFABVisibility(View.VISIBLE);
                 } else {
                     setEditFABVisibility(View.INVISIBLE);


More information about the Libreoffice-commits mailing list