diff options
Diffstat (limited to 'android/source/src/java/org/libreoffice')
18 files changed, 51 insertions, 2624 deletions
diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java index aed1cf946a69..6af44912bb52 100644 --- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -1,6 +1,5 @@ package org.libreoffice; -import android.app.Activity; import android.app.AlertDialog; import android.content.ClipData; import android.content.ClipboardManager; @@ -11,14 +10,11 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; -import android.database.Cursor; import android.graphics.RectF; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; -import android.provider.OpenableColumns; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.Snackbar; import android.support.v4.widget.DrawerLayout; @@ -38,8 +34,6 @@ import android.widget.Toast; import org.libreoffice.overlay.CalcHeadersController; import org.libreoffice.overlay.DocumentOverlay; -import org.libreoffice.storage.DocumentProviderFactory; -import org.libreoffice.storage.IFile; import org.libreoffice.ui.FileUtilities; import org.libreoffice.ui.LibreOfficeUIActivity; import org.mozilla.gecko.gfx.GeckoLayerClient; @@ -51,7 +45,6 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; @@ -80,9 +73,6 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin private static boolean mIsDeveloperMode; private static boolean mbISReadOnlyMode; - private int providerId; - private URI documentUri; - private DrawerLayout mDrawerLayout; Toolbar toolbarTop; @@ -129,7 +119,6 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin private static boolean isDocumentChanged = false; private boolean isUNOCommandsToolbarOpen = false; private boolean isNewDocument = false; - private long lastModified = 0; @Override public void onCreate(Bundle savedInstanceState) { @@ -212,13 +201,9 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin } else if (getIntent().getData().getScheme().equals(ContentResolver.SCHEME_FILE)) { mInputFile = new File(getIntent().getData().getPath()); + mbISReadOnlyMode = true; Log.d(LOGTAG, "SCHEME_FILE: getPath(): " + getIntent().getData().getPath()); toolbarTop.setTitle(mInputFile.getName()); - // Gather data to rebuild IFile object later - providerId = getIntent().getIntExtra( - "org.libreoffice.document_provider_id", 0); - documentUri = (URI) getIntent().getSerializableExtra( - "org.libreoffice.document_uri"); } } else { mInputFile = new File(DEFAULT_DOC_PATH); @@ -234,8 +219,6 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin mDrawerList.setOnItemClickListener(new DocumentPartClickListener()); } - lastModified = mInputFile.lastModified(); - mToolbarController.setupToolbars(); TabHost host = findViewById(R.id.toolbarTabHost); @@ -363,14 +346,12 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin } /** - * Save the document and invoke save on document provider to upload the file - * to the cloud if necessary. + * Save the document. */ public void saveDocument() { if (!mInputFile.exists()) { // Needed for handling null in case new document is not created. mInputFile = new File(DEFAULT_DOC_PATH); - lastModified = mInputFile.lastModified(); } Toast.makeText(this, R.string.message_saving, Toast.LENGTH_SHORT).show(); // local save @@ -378,98 +359,51 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin } public void saveFileToOriginalSource() { - if (documentUri != null) { - // case where file was opened using IDocumentProvider from within LO app - saveFilesToCloud(); - } else { - // case where file URI was passed via Intent - if (isReadOnlyMode() || mInputFile == null || getIntent().getData() == null || !getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) - return; - - Uri uri = getIntent().getData(); - FileInputStream inputStream = null; - OutputStream outputStream = null; + if (isReadOnlyMode() || mInputFile == null || getIntent().getData() == null || !getIntent().getData().getScheme().equals(ContentResolver.SCHEME_CONTENT)) + return; - try { - inputStream = new FileInputStream(mInputFile); - // OutputStream for the actual (original) location - outputStream = getContentResolver().openOutputStream(uri); - - byte[] buffer = new byte[4096]; - int readBytes = inputStream.read(buffer); - while (readBytes != -1) { - outputStream.write(buffer, 0, readBytes); - readBytes = inputStream.read(buffer); - } + Uri uri = getIntent().getData(); + FileInputStream inputStream = null; + OutputStream outputStream = null; - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(LibreOfficeMainActivity.this, R.string.message_saved, - Toast.LENGTH_SHORT).show(); - } - }); - setDocumentChanged(false); - } catch (Exception e) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(LibreOfficeMainActivity.this, R.string.message_saving_failed, - Toast.LENGTH_SHORT).show(); - } - }); - e.printStackTrace(); - } finally { - try { - if (inputStream != null) - inputStream.close(); - if (outputStream != null) - outputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } + try { + inputStream = new FileInputStream(mInputFile); + // OutputStream for the actual (original) location + outputStream = getContentResolver().openOutputStream(uri); + + byte[] buffer = new byte[4096]; + int readBytes = inputStream.read(buffer); + while (readBytes != -1) { + outputStream.write(buffer, 0, readBytes); + readBytes = inputStream.read(buffer); } - } - } - public void saveFilesToCloud(){ - final Activity activity = LibreOfficeMainActivity.this; - final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - try { - // rebuild the IFile object from the data passed in the Intent - IFile mStorageFile = DocumentProviderFactory.getInstance() - .getProvider(providerId).createFromUri(LibreOfficeMainActivity.this, documentUri); - // call document provider save operation - mStorageFile.saveDocument(mInputFile); - } - catch (final RuntimeException e) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(activity, e.getMessage(), - Toast.LENGTH_SHORT).show(); - } - }); - Log.e(LOGTAG, e.getMessage(), e.getCause()); + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(LibreOfficeMainActivity.this, R.string.message_saved, + Toast.LENGTH_SHORT).show(); } - return null; - } - - @Override - protected void onPostExecute(Void param) { - Toast.makeText(activity, R.string.message_saved, + }); + setDocumentChanged(false); + } catch (Exception e) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(LibreOfficeMainActivity.this, R.string.message_saving_failed, Toast.LENGTH_SHORT).show(); - setDocumentChanged(false); + } + }); + e.printStackTrace(); + } finally { + try { + if (inputStream != null) + inputStream.close(); + if (outputStream != null) + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); } - }; - - if (lastModified < mInputFile.lastModified()) { - task.execute(); - lastModified = mInputFile.lastModified(); - } else { - Toast.makeText(activity, R.string.message_save_incomplete, Toast.LENGTH_LONG).show(); } } diff --git a/android/source/src/java/org/libreoffice/storage/DocumentProviderFactory.java b/android/source/src/java/org/libreoffice/storage/DocumentProviderFactory.java deleted file mode 100644 index 07387f1e5511..000000000000 --- a/android/source/src/java/org/libreoffice/storage/DocumentProviderFactory.java +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- 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.storage; - -import java.util.HashSet; -import java.util.Set; - -import org.libreoffice.storage.external.ExtsdDocumentsProvider; -import org.libreoffice.storage.external.OTGDocumentsProvider; -import org.libreoffice.storage.local.LocalDocumentsDirectoryProvider; -import org.libreoffice.storage.local.LocalDocumentsProvider; - -import android.content.Context; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; - -/** - * Keeps the instances of the available IDocumentProviders in the system. - * Instances are maintained in a sorted list and providers have to be - * accessed from their position. - * - * The factory follows the Singleton pattern, there is only one instance of it - * in the application and it must be retrieved with - * DocumentProviderFactory.getInstance(). - */ -public final class DocumentProviderFactory { - public static int EXTSD_PROVIDER_INDEX = 2; - public static int OTG_PROVIDER_INDEX = 3; - - /** - * Private factory instance for the Singleton pattern. - */ - private static DocumentProviderFactory instance = null; - - private IDocumentProvider[] providers; - - private String[] providerNames; - - private DocumentProviderFactory() { - // private to prevent external instances of the factory - } - - /** - * Initializes the factory with some context. If this method is called for - * twice or more times those calls will have no effect. - * - * @param context - * Application context for the factory. - */ - public static void initialize(Context context) { - if (instance == null) { - // initialize instance - instance = new DocumentProviderFactory(); - - // initialize document providers list - instance.providers = new IDocumentProvider[4]; - instance.providers[0] = new LocalDocumentsDirectoryProvider(0); - instance.providers[1] = new LocalDocumentsProvider(1); - instance.providers[OTG_PROVIDER_INDEX] = new OTGDocumentsProvider(OTG_PROVIDER_INDEX, context); - instance.providers[EXTSD_PROVIDER_INDEX] = new ExtsdDocumentsProvider(EXTSD_PROVIDER_INDEX, context); - - // initialize document provider names list - instance.providerNames = new String[instance.providers.length]; - for (int i = 0; i < instance.providers.length; i++) { - instance.providerNames[i] = context.getString(instance - .getProvider(i).getNameResource()); - } - } - } - - /** - * Retrieve the unique instance of the factory. - * - * @return the unique factory object or null if it is not yet initialized. - */ - public static DocumentProviderFactory getInstance() { - return instance; - } - - /** - * Retrieve the provider associated to a certain id. - * - * @param id - * @return document provider with that id. - */ - public IDocumentProvider getProvider(int id) { - // as for now, id == position in providers array - return providers[id]; - } - - /** - * Returns a sorted list of the names of the providers. Order is meaningful - * to retrieve the actual provider object with getProvider(). - * - * @return Array with the names of the available providers. - */ - public String[] getNames() { - 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>(); - for (IDocumentProvider provider : providers) { - if (provider instanceof OnSharedPreferenceChangeListener) - listeners.add((OnSharedPreferenceChangeListener) provider); - } - return listeners; - } -} diff --git a/android/source/src/java/org/libreoffice/storage/DocumentProviderSettingsActivity.java b/android/source/src/java/org/libreoffice/storage/DocumentProviderSettingsActivity.java deleted file mode 100644 index 55656f9d6c55..000000000000 --- a/android/source/src/java/org/libreoffice/storage/DocumentProviderSettingsActivity.java +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- 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.storage; - -import java.util.Set; - -import org.libreoffice.R; -import org.libreoffice.storage.external.BrowserSelectorActivity; - -import android.content.Intent; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import android.support.v7.app.AppCompatActivity; - -public class DocumentProviderSettingsActivity extends AppCompatActivity { - - public static final String KEY_PREF_EXTERNAL_SD_PATH_URI = "pref_extsd_path_uri"; - public static final String KEY_PREF_OTG_PATH_URI = "pref_otg_path_uri"; - - private Set<OnSharedPreferenceChangeListener> listeners; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // Display the fragment as the main content. - getFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment()).commit(); - } - - @Override - protected void onResume() { - super.onResume(); - listeners = DocumentProviderFactory.getInstance().getChangeListeners(); - for (OnSharedPreferenceChangeListener listener : listeners) { - PreferenceManager.getDefaultSharedPreferences(this) - .registerOnSharedPreferenceChangeListener(listener); - } - } - - @Override - protected void onPause() { - super.onPause(); - for (OnSharedPreferenceChangeListener listener : listeners) { - PreferenceManager.getDefaultSharedPreferences(this) - .unregisterOnSharedPreferenceChangeListener(listener); - } - } - - public static class SettingsFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.documentprovider_preferences); - - PreferenceScreen extSDPreference = - (PreferenceScreen)findPreference(KEY_PREF_EXTERNAL_SD_PATH_URI); - PreferenceScreen otgPreference = - (PreferenceScreen)findPreference(KEY_PREF_OTG_PATH_URI); - - extSDPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - startBrowserSelectorActivity(KEY_PREF_EXTERNAL_SD_PATH_URI, - BrowserSelectorActivity.MODE_EXT_SD); - return true; - } - }); - otgPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - startBrowserSelectorActivity(KEY_PREF_OTG_PATH_URI, - BrowserSelectorActivity.MODE_OTG); - return true; - } - }); - - } - - private void startBrowserSelectorActivity(String prefKey, String mode) { - Intent i = new Intent(getActivity(), BrowserSelectorActivity.class); - i.putExtra(BrowserSelectorActivity.PREFERENCE_KEY_EXTRA, prefKey); - i.putExtra(BrowserSelectorActivity.MODE_EXTRA, mode); - startActivity(i); - } - - } -} diff --git a/android/source/src/java/org/libreoffice/storage/IDocumentProvider.java b/android/source/src/java/org/libreoffice/storage/IDocumentProvider.java deleted file mode 100644 index 4e82e250de55..000000000000 --- a/android/source/src/java/org/libreoffice/storage/IDocumentProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- 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.storage; - -import android.content.Context; - -import java.net.URI; - -/** - * Represents a Document Provider, an object able to provide documents from a - * certain source (e.g. local documents, DropBox, Google Docs). - */ -public interface IDocumentProvider { - - /** - * Provides the content root element for the Document Provider. - * - * @return Content root element. - * @throws RuntimeException in case of error. - * @param context - */ - IFile getRootDirectory(Context context); - - /** - * Transforms some URI into the IFile object that represents that content. - * - * - * @param context - * @param uri - * URI pointing to some content object that has been previously - * retrieved with IFile.getUri(). - * @return IFile object pointing to the content represented by uri. - * @throws RuntimeException in case of error. - */ - IFile createFromUri(Context context, URI uri); - - /** - * Get internationalized name for this provider. This name is intended to be - * shown in the UI. - * - * @return string resource pointing to the provider name. - */ - int getNameResource(); - - /** - * Provides the unique ID for a document provider instance in a program. - * - * This ID should be set when the instance is built. It could be used to - * tell two instances of the same document provider apart. - * - * @return Unique ID for a document provider instance. - */ - int getId(); - - /** - * Checks if the Document Provider is available or not. - * - * @return A boolean value based on provider availability. - * @param context - */ - boolean checkProviderAvailability(Context context); -} diff --git a/android/source/src/java/org/libreoffice/storage/IFile.java b/android/source/src/java/org/libreoffice/storage/IFile.java deleted file mode 100644 index c9cfa7f1198d..000000000000 --- a/android/source/src/java/org/libreoffice/storage/IFile.java +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- 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.storage; - -import android.content.Context; - -import java.io.File; -import java.io.FileFilter; -import java.net.URI; -import java.util.Date; -import java.util.List; - -/** - * An abstraction of the File class, intended to be implemented by different - * Document Providers. - * - * It represents a file or a directory in the context of a certain Document - * Provider. It wraps the file-related operations and provides access to the - * final document as a local File, downloading it if necessary. - */ -public interface IFile { - - /** - * Provides a URI that represents this IFile object. - * - * @return URI that represents this IFile object in the context of the - * Document Provider that created it. The URI can be transformed - * back into an IFile object with IDocumentProvider.createFromUri(). - */ - URI getUri(); - - /** - * Returns the name of the file or directory represented by this file. - * - * @return This file's name. - */ - String getName(); - - /** - * Indicates if this file represents a directory in the context of the - * Document Provider which originated it. - * - * @return true if this file is a directory, false otherwise. - */ - boolean isDirectory(); - - /** - * Returns the file size in bytes. - * - * @return file size in bytes, 0 if the file does not exist. - */ - long getSize(); - - /** - * Returns the time when this file was last modified, measured in - * milliseconds since January 1st, 1970, midnight. - * - * @return time when this file was last modified, or 0 if the file does not - * exist. - */ - Date getLastModified(); - - /** - * Returns a list containing the files in the directory represented by this - * file. - * - * @return list of files contained by this directory, or an empty list if - * this is not a directory. - * @throws RuntimeException in case of error. - */ - List<IFile> listFiles(); - - /** - * Gets the list of files contained in the directory represented by this - * file, and filters it through some FilenameFilter. - * - * @param filter - * the filter to match names against. - * @return filtered list of files contained by this directory, or an empty - * list if this is not a directory. - * @throws RuntimeException in case of error. - */ - List<IFile> listFiles(FileFilter filter); - - /** - * Returns the pparent of this file. - * - * @return this file's parent or null if it does not have it. - * @param context - */ - IFile getParent(Context context); - - /** - * Returns the document wrapped by this IFile as a local file. The result - * for a directory is not defined. - * - * @return local file containing the document wrapped by this object. - * @throws RuntimeException in case of error. - */ - File getDocument(); - - /** - * Replaces the wrapped document with a new version of it. - * - * @param file - * A local file pointing to the new version of the document. - */ - void saveDocument(File file); -} diff --git a/android/source/src/java/org/libreoffice/storage/IOUtils.java b/android/source/src/java/org/libreoffice/storage/IOUtils.java deleted file mode 100644 index f345f5cbed3b..000000000000 --- a/android/source/src/java/org/libreoffice/storage/IOUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.libreoffice.storage; - -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; - -/** - * File IO related methods. - */ -public class IOUtils { - private static final int BUFFER_SIZE = 1024 * 8; - private static final String LOGTAG = IOUtils.class.getSimpleName(); - - public static File getFileFromURIString(String URIpath) throws IllegalArgumentException{ - try{ - return new File(new URI(URIpath)); - } catch (URISyntaxException e) { - //should not happen as all URIs are system generated - Log.wtf(LOGTAG, e.getReason()); - return null; - } - } - - public static boolean isInvalidFile(File f) { - return f == null || !f.exists() || f.getTotalSpace() == 0 - || !f.canRead() || !f.canWrite(); - } - - public static int copy(InputStream input, OutputStream output) throws Exception { - byte[] buffer = new byte[BUFFER_SIZE]; - - BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE); - BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE); - - int count = 0, n = 0; - try { - while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) { - out.write(buffer, 0, n); - count += n; - } - out.flush(); - } finally { - if (out != null) out.close(); - if (in != null) in.close(); - } - - return count; - } - -} diff --git a/android/source/src/java/org/libreoffice/storage/external/BrowserSelectorActivity.java b/android/source/src/java/org/libreoffice/storage/external/BrowserSelectorActivity.java deleted file mode 100644 index 07b64623b701..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/BrowserSelectorActivity.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.libreoffice.storage.external; - -import android.annotation.TargetApi; -import android.content.ContentResolver; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.UriPermission; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; - -import org.libreoffice.R; -import org.libreoffice.storage.DocumentProviderFactory; - -import java.util.Set; - -/** - * Activity to select which directory browser to use. - * Android 5+ will use the DocumentTree intent to locate a browser. - * Android 4+ & OTG will use the internal directory browser. - */ -public class BrowserSelectorActivity extends AppCompatActivity { - public static final String PREFERENCE_KEY_EXTRA = "org.libreoffice.pref_key_extra"; - public static final String MODE_EXTRA = "org.libreoffice.mode_extra"; - public static final String MODE_OTG = "OTG"; - public static final String MODE_EXT_SD = "EXT_SD"; - - private static final String LOGTAG = BrowserSelectorActivity.class.getSimpleName(); - private static final int REQUEST_DOCUMENT_TREE = 1; - private static final int REQUEST_INTERNAL_BROWSER = 2; - private Set<SharedPreferences.OnSharedPreferenceChangeListener> listeners; - private String preferenceKey; - private SharedPreferences preferences; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - preferenceKey = getIntent().getStringExtra(PREFERENCE_KEY_EXTRA); - preferences = PreferenceManager.getDefaultSharedPreferences(this); - String mode = getIntent().getStringExtra(MODE_EXTRA); - - if(mode.equals(MODE_EXT_SD)) { - findSDCard(); - } else if (mode.equals(MODE_OTG)) { - findOTGDevice(); - } - } - - private void findOTGDevice() { - useInternalBrowser(DocumentProviderFactory.OTG_PROVIDER_INDEX); - } - - private void findSDCard() { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - useDocumentTreeBrowser(); - } else { - useInternalBrowser(DocumentProviderFactory.EXTSD_PROVIDER_INDEX); - } - } - - private void useInternalBrowser(int providerIndex) { - IExternalDocumentProvider provider = - (IExternalDocumentProvider) DocumentProviderFactory.getInstance() - .getProvider(providerIndex); - String previousDirectoryPath = preferences.getString(preferenceKey, provider.guessRootURI(this)); - Intent i = new Intent(this, DirectoryBrowserActivity.class); - i.putExtra(DirectoryBrowserActivity.DIRECTORY_PATH_EXTRA, previousDirectoryPath); - startActivityForResult(i, REQUEST_INTERNAL_BROWSER); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void useDocumentTreeBrowser() { - Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); - startActivityForResult(i, REQUEST_DOCUMENT_TREE); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - //listeners are registered here as onActivityResult is called before onResume - super.onActivityResult(requestCode, resultCode, data); - - registerListeners(); - if(resultCode == RESULT_OK) { - switch(requestCode) { - case REQUEST_DOCUMENT_TREE: - Uri treeUri = data.getData(); - preferences.edit() - .putString(preferenceKey, treeUri.toString()) - .apply(); - - updatePersistedUriPermission(treeUri); - getContentResolver().takePersistableUriPermission(treeUri, - Intent.FLAG_GRANT_READ_URI_PERMISSION | - Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - break; - - case REQUEST_INTERNAL_BROWSER: - Uri fileUri = data.getData(); - preferences.edit() - .putString(preferenceKey, fileUri.toString()) - .apply(); - break; - default: - } - } - unregisterListeners(); - Log.d(LOGTAG, "Preference saved: " + - preferences.getString(preferenceKey, getString(R.string.directory_not_saved))); - finish(); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void updatePersistedUriPermission(Uri treeUri) { - freePreviousUriPermissions(); - - //TODO: Use non-emulator Android 5+ device to check if needed - /*this.grantUriPermission(this.getPackageName(), - treeUri, - Intent.FLAG_GRANT_READ_URI_PERMISSION | - Intent.FLAG_GRANT_WRITE_URI_PERMISSION); */ - - getContentResolver().takePersistableUriPermission(treeUri, - Intent.FLAG_GRANT_READ_URI_PERMISSION | - Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void freePreviousUriPermissions() { - ContentResolver cr = getContentResolver(); - for (UriPermission uriPermission : cr.getPersistedUriPermissions()) { - cr.releasePersistableUriPermission(uriPermission.getUri(), 0); - } - } - - private void registerListeners() { - listeners = DocumentProviderFactory.getInstance().getChangeListeners(); - for (SharedPreferences.OnSharedPreferenceChangeListener listener : listeners) { - PreferenceManager.getDefaultSharedPreferences(this) - .registerOnSharedPreferenceChangeListener(listener); - } - } - - private void unregisterListeners() { - for (SharedPreferences.OnSharedPreferenceChangeListener listener : listeners) { - PreferenceManager.getDefaultSharedPreferences(this) - .unregisterOnSharedPreferenceChangeListener(listener); - } - } -} diff --git a/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserActivity.java b/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserActivity.java deleted file mode 100644 index 1cf9f52fa7c0..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserActivity.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.libreoffice.storage.external; - - -import android.app.Fragment; -import android.app.FragmentManager; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; - -import org.libreoffice.R; - -/** - * Container for DirectoryBrowserFragment - */ -public class DirectoryBrowserActivity extends AppCompatActivity { - public static final String DIRECTORY_PATH_EXTRA = "org.libreoffice.directory_path_extra"; - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Intent data = getIntent(); - String initialPath = data.getStringExtra(DIRECTORY_PATH_EXTRA); - - setContentView(R.layout.activity_directory_browser); - FragmentManager fm = getFragmentManager(); - Fragment fragment = DirectoryBrowserFragment.newInstance(initialPath); - fm.beginTransaction() - .add(R.id.fragment_container, fragment) - .commit(); - } - - @Override - public void onBackPressed() { - FragmentManager fm = getFragmentManager(); - if(fm.getBackStackEntryCount() > 0) { - fm.popBackStack(); - } else { - super.onBackPressed(); - } - } -} diff --git a/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserFragment.java b/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserFragment.java deleted file mode 100644 index 18165650a617..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/DirectoryBrowserFragment.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.libreoffice.storage.external; - -import android.app.Activity; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.support.annotation.Nullable; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -import org.libreoffice.R; -import org.libreoffice.storage.IOUtils; - -import java.io.File; -import java.util.ArrayList; -import java.util.Comparator; - -/** - * A simple directory browser. - */ -public class DirectoryBrowserFragment extends Fragment { - private static final String LOGTAG = DirectoryBrowserFragment.class.getSimpleName(); - private static final String INITIAL_PATH_URI_KEY = "initial_path"; - private File currentDirectory; - private FileArrayAdapter directoryAdapter; - - public static DirectoryBrowserFragment newInstance(String initialPathURI) { - Bundle args = new Bundle(); - args.putString(INITIAL_PATH_URI_KEY, initialPathURI); - DirectoryBrowserFragment fragment = new DirectoryBrowserFragment(); - fragment.setArguments(args); - Log.d(LOGTAG, "Saved path: " + initialPathURI); - - return fragment; - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - String initialPathURI = getArguments().getString(INITIAL_PATH_URI_KEY); - setupCurrentDirectory(initialPathURI); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_directory_browser, container, false); - - final EditText directoryHeader = v.findViewById(R.id.directory_header); - Button directorySearchButton = v.findViewById(R.id.directory_search_button); - Button positiveButton = v.findViewById(R.id.confirm_button); - Button negativeButton = v.findViewById(R.id.cancel_button); - ImageView upImage = v.findViewById(R.id.up_image); - ListView directoryListView = v.findViewById(R.id.directory_list); - - directoryHeader.setText(currentDirectory.getPath()); - directorySearchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String currentPath = currentDirectory.getAbsolutePath(); - String enteredPath = directoryHeader.getText().toString(); - File testDirectory = new File(enteredPath); - if(enteredPath.equals(currentPath)) ; - else if (isInvalidFileDirectory(testDirectory)) { - Toast.makeText(getActivity(), R.string.bad_directory, Toast.LENGTH_SHORT) - .show(); - } - else { - changeDirectory(testDirectory); - } - } - }); - - positiveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent data = new Intent(); - data.setData(Uri.fromFile(currentDirectory)); - getActivity().setResult(Activity.RESULT_OK, data); - getActivity().finish(); - } - }); - - negativeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getActivity().setResult(Activity.RESULT_CANCELED, null); - getActivity().finish(); - } - }); - - upImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - changeDirectory(currentDirectory.getParentFile()); - } - }); - - directoryAdapter = new FileArrayAdapter(getActivity(), new ArrayList<File>()); - directoryAdapter.populateFileList(currentDirectory); - directoryListView.setAdapter(directoryAdapter); - directoryListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - changeDirectory(directoryAdapter.getItem(position)); - } - }); - - return v; - } - - private void changeDirectory(File destination) { - if(destination == null) { - Toast.makeText(getActivity(), R.string.unable_to_go_further, Toast.LENGTH_SHORT) - .show(); - } else { - Fragment fragment = DirectoryBrowserFragment.newInstance(destination.toURI().toString()); - getActivity().getFragmentManager().beginTransaction() - .replace(R.id.fragment_container, fragment) - .addToBackStack(null) - .commit(); - } - } - - private void setupCurrentDirectory(String initialPathURI) { - File initialDirectory = null; - if(initialPathURI != null && !initialPathURI.isEmpty()) { - initialDirectory = IOUtils.getFileFromURIString(initialPathURI); - } - - if(isInvalidFileDirectory(initialDirectory)) { - initialDirectory = Environment.getExternalStorageDirectory(); - } - currentDirectory = initialDirectory; - } - - private boolean isInvalidFileDirectory(File f) { - return f == null || !f.exists() || !f.isDirectory() ||!f.canRead(); - } - - private class FileArrayAdapter extends ArrayAdapter<File> { - private Comparator<File> caseInsensitiveNaturalOrderComparator; - - public FileArrayAdapter(Context context, ArrayList<File> files) { - super(context, 0, files); - caseInsensitiveNaturalOrderComparator = new AlphabeticalFileComparator(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = getActivity().getLayoutInflater() - .inflate(android.R.layout.simple_list_item_1, null); - } - - File f = this.getItem(position); - TextView tv = convertView.findViewById(android.R.id.text1); - tv.setText(f.getName()); - - return convertView; - } - - public void sortAlphabetically() { - this.sort(caseInsensitiveNaturalOrderComparator); - } - - public void populateFileList(File directory) { - for(File f : directory.listFiles()){ - if(f.isDirectory()){ - directoryAdapter.add(f); - } - } - directoryAdapter.sortAlphabetically(); - } - } - - private class AlphabeticalFileComparator implements Comparator<File> { - @Override - public int compare(File lhs, File rhs) { - String lhsName = lhs.getName(); - String rhsName = rhs.getName(); - - return lhsName.compareToIgnoreCase(rhsName); - } - } -} diff --git a/android/source/src/java/org/libreoffice/storage/external/ExternalFile.java b/android/source/src/java/org/libreoffice/storage/external/ExternalFile.java deleted file mode 100644 index aff33e4413ef..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/ExternalFile.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.libreoffice.storage.external; - -import android.content.Context; -import android.support.v4.provider.DocumentFile; -import android.util.Log; - -import org.libreoffice.storage.IFile; -import org.libreoffice.storage.IOUtils; - -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Implementation of IFile for the external file system, for Android 4.4+ - * - * Uses the DocumentFile class. - * - * The DocumentFile class obfuscates the path of the files it wraps, - * preventing usage of LOK's documentLoad method. A copy of the DocumentFile's contents - * will be created in the cache when files are opened, allowing use of documentLoad. - */ -public class ExternalFile implements IFile{ - private final static String LOGTAG = "ExternalFile"; - - private ExtsdDocumentsProvider provider; - private DocumentFile docFile; - private File duplicateFile; - private Context context; - - public ExternalFile(ExtsdDocumentsProvider provider, DocumentFile docFile, Context context) { - this.provider = provider; - this.context = context; - this.docFile = docFile; - } - - @Override - public URI getUri() { - try{ - return new URI(docFile.toString()); - } catch (URISyntaxException e) { - Log.e(LOGTAG, e.getMessage(), e.getCause()); - return null; - } - } - - @Override - public String getName() { - return docFile.getName(); - } - - @Override - public boolean isDirectory() { - return docFile.isDirectory(); - } - - @Override - public long getSize() { - return docFile.length(); - } - - @Override - public Date getLastModified() { - return new Date(docFile.lastModified()); - } - - @Override - public List<IFile> listFiles() { - List<IFile> children = new ArrayList<IFile>(); - for (DocumentFile child : docFile.listFiles()) { - children.add(new ExternalFile(provider, child, context)); - } - return children; - } - - @Override - public List<IFile> listFiles(FileFilter filter) { - File file; - try{ - List<IFile> children = new ArrayList<IFile>(); - for (DocumentFile child : docFile.listFiles()) { - file = new File(new URI(child.getUri().toString())); - if(filter.accept(file)) - children.add(new ExternalFile(provider, child, context)); - } - return children; - - }catch (Exception e){ - e.printStackTrace(); - } - /* if something goes wrong */ - return listFiles(); - - } - - @Override - public IFile getParent(Context context) { - // this is the root node - if(docFile.getParentFile() == null) return null; - - return new ExternalFile(provider, docFile.getParentFile(), this.context); - } - - @Override - public File getDocument() { - if(isDirectory()) { - return null; - } else { - duplicateFile = duplicateInCache(); - return duplicateFile; - } - } - - private File duplicateInCache() { - try{ - InputStream istream = context.getContentResolver(). - openInputStream(docFile.getUri()); - - File storageFolder = provider.getCacheDir(); - File fileCopy = new File(storageFolder, docFile.getName()); - OutputStream ostream = new FileOutputStream(fileCopy); - - IOUtils.copy(istream, ostream); - return fileCopy; - } catch (Exception e) { - Log.e(LOGTAG, e.getMessage(), e.getCause()); - return null; - } - } - - @Override - public void saveDocument(File file) { - try{ - OutputStream ostream = context.getContentResolver(). - openOutputStream(docFile.getUri()); - InputStream istream = new FileInputStream(file); - - IOUtils.copy(istream, ostream); - - } catch (Exception e) { - Log.e(LOGTAG, e.getMessage(), e.getCause()); - } - } - - @Override - public boolean equals(Object object) { - if (this == object) - return true; - if (!(object instanceof ExternalFile)) - return false; - ExternalFile file = (ExternalFile) object; - return file.getUri().equals(getUri()); - } - -} diff --git a/android/source/src/java/org/libreoffice/storage/external/ExtsdDocumentsProvider.java b/android/source/src/java/org/libreoffice/storage/external/ExtsdDocumentsProvider.java deleted file mode 100644 index e45929374bbd..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/ExtsdDocumentsProvider.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.libreoffice.storage.external; - -import android.Manifest; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.preference.PreferenceManager; -import android.support.v4.content.ContextCompat; -import android.support.v4.provider.DocumentFile; -import android.util.Log; - -import org.libreoffice.R; -import org.libreoffice.storage.DocumentProviderSettingsActivity; -import org.libreoffice.storage.IFile; - -import java.io.File; -import java.net.URI; - -/** - * Implementation of IDocumentProvider for the external file system, for android 4.4+ - * - * The DocumentFile class is required when accessing files in external storage - * for Android 4.4+. The ExternalFile class is used to handle this. - * - * 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. - */ -public class ExtsdDocumentsProvider implements IExternalDocumentProvider, - OnSharedPreferenceChangeListener{ - private static final String LOGTAG = ExtsdDocumentsProvider.class.getSimpleName(); - - private int id; - private File cacheDir; - private String rootPathURI; - - public ExtsdDocumentsProvider(int id, Context context) { - this.id = id; - setupRootPathUri(context); - setupCache(context); - } - - private void setupRootPathUri(Context context) { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - rootPathURI = preferences.getString( - DocumentProviderSettingsActivity.KEY_PREF_EXTERNAL_SD_PATH_URI, guessRootURI(context)); - } - - 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); - // 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" - String primaryExternal = Environment.getExternalStorageDirectory().getAbsolutePath(); - - 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; } - String optionPath = option.getAbsolutePath(); - if(optionPath.contains(primaryExternal)) { - Log.v(LOGTAG, "did get file path - but is same as primary storage ("+ primaryExternal +")"); - continue; - } - - return option.toURI().toString(); - } - - // TODO: do some manual probing of possible directories (/storage/sdcard1 and similar) - Log.i(LOGTAG, "no secondary storage reported"); - return null; - } - - private void setupCache(Context context) { - // TODO: probably we should do smarter cache management - cacheDir = new File(context.getExternalCacheDir(), "externalFiles"); - if (cacheDir.exists()) { - deleteRecursive(cacheDir); - } - cacheDir.mkdirs(); - } - - private static void deleteRecursive(File file) { - if (file.isDirectory()) { - for (File child : file.listFiles()) - deleteRecursive(child); - } - file.delete(); - } - - public File getCacheDir() { - return cacheDir; - } - - @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 - throw buildRuntimeExceptionForInvalidFileURI(context); - } - } - - private ExternalFile android5RootDirectory(Context context) { - try { - return new ExternalFile(this, - DocumentFile.fromTreeUri(context, Uri.parse(rootPathURI)), - context); - } catch (Exception e) { - //invalid rootPathURI - throw buildRuntimeExceptionForInvalidFileURI(context); - } - } - - private RuntimeException buildRuntimeExceptionForInvalidFileURI(Context context) { - // ToDo: discarding the original exception / catch-all handling is bad style - return new RuntimeException(context.getString(R.string.ext_document_provider_error)); - } - - @Override - public IFile createFromUri(Context context, URI javaURI) { - //TODO: refactor when new DocumentFile API exist - //uri must be of a DocumentFile file, not directory. - Uri androidUri = Uri.parse(javaURI.toString()); - return new ExternalFile(this, - DocumentFile.fromSingleUri(context, androidUri), - context); - } - - @Override - public int getNameResource() { - return R.string.external_sd_file_system; - } - - @Override - public int getId() { - return id; - } - - @Override - public boolean checkProviderAvailability(Context context) { - // too many devices (or I am just unlucky) don't report the mounted state properly, and other - // devices also consider dedicated part of internal storage to be "mounted" so cannot use - // getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && isExternalStorageRemovable() - // but they refer to the primary external storage anyway, so what currently is covered by the - // "LocalDocumentsProvider" - return rootPathURI!=null && 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, ""); - } - } - -} diff --git a/android/source/src/java/org/libreoffice/storage/external/IExternalDocumentProvider.java b/android/source/src/java/org/libreoffice/storage/external/IExternalDocumentProvider.java deleted file mode 100644 index a439417b60cd..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/IExternalDocumentProvider.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.libreoffice.storage.external; - -import android.content.Context; - -import org.libreoffice.storage.IDocumentProvider; - - -/** - * Interface for external document providers. - */ -public interface IExternalDocumentProvider extends IDocumentProvider { - - /** - * Used to obtain the default directory to display when - * browsing using the internal DirectoryBrowser. - * - * @return a guess of the root file's URI. - * @param context - */ - String guessRootURI(Context context); - -} diff --git a/android/source/src/java/org/libreoffice/storage/external/OTGDocumentsProvider.java b/android/source/src/java/org/libreoffice/storage/external/OTGDocumentsProvider.java deleted file mode 100644 index 4341bc3541e6..000000000000 --- a/android/source/src/java/org/libreoffice/storage/external/OTGDocumentsProvider.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.libreoffice.storage.external; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.preference.PreferenceManager; -import android.util.Log; - -import org.libreoffice.R; -import org.libreoffice.storage.DocumentProviderSettingsActivity; -import org.libreoffice.storage.IFile; -import org.libreoffice.storage.IOUtils; -import org.libreoffice.storage.local.LocalFile; - -import java.io.File; -import java.net.URI; - -/** - * TODO: OTG currently uses LocalFile. Change to an IFile that handles abrupt OTG unmounting - */ -public class OTGDocumentsProvider implements IExternalDocumentProvider, - SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String LOGTAG = OTGDocumentsProvider.class.getSimpleName(); - - private String rootPathURI; - private int id; - - public OTGDocumentsProvider(int id, Context context) { - this.id = id; - setupRootPath(context); - } - - private void setupRootPath(Context context) { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - rootPathURI = preferences.getString( - DocumentProviderSettingsActivity.KEY_PREF_OTG_PATH_URI, ""); - } - - @Override - public IFile createFromUri(Context context, URI uri) { - return new LocalFile(uri); - } - - @Override - public int getNameResource() { - return R.string.otg_file_system; - } - - @Override - public int getId() { - return id; - } - - @Override - public IFile getRootDirectory(Context context) { - // TODO: handle this with more fine-grained exceptions - if(rootPathURI.equals("")) { - Log.e(LOGTAG, "rootPathURI is empty"); - throw new RuntimeException(context.getString(R.string.ext_document_provider_error)); - } - - File f = IOUtils.getFileFromURIString(rootPathURI); - if(IOUtils.isInvalidFile(f)) { - Log.e(LOGTAG, "rootPathURI is invalid - missing device?"); - throw new RuntimeException(context.getString(R.string.otg_missing_error)); - } - - return new LocalFile(f); - } - - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(DocumentProviderSettingsActivity.KEY_PREF_OTG_PATH_URI)) { - rootPathURI = sharedPreferences.getString(key, ""); - } - } - - @Override - public String guessRootURI(Context context) { - return ""; - } - - @Override - public boolean checkProviderAvailability(Context context) { - // check if system supports USB Host - return rootPathURI.length()>0 && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST); - } -} diff --git a/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsDirectoryProvider.java b/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsDirectoryProvider.java deleted file mode 100644 index 15522e93a45e..000000000000 --- a/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsDirectoryProvider.java +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- 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.storage.local; - -import java.io.File; - -import org.libreoffice.storage.IFile; -import org.libreoffice.R; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Environment; -import android.support.v4.content.ContextCompat; -import android.util.Log; - -/** - * A convenience IDocumentProvider to browse the /sdcard/Documents directory. - * - * Extends LocalDocumentsProvider to overwrite getRootDirectory and set it to - * /sdcard/Documents. Most documents will probably be stored there so there is - * no need for the user to browse the filesystem from the root every time. - */ -public class LocalDocumentsDirectoryProvider extends LocalDocumentsProvider { - - public LocalDocumentsDirectoryProvider(int id) { - super(id); - } - - private static File getDocumentsDir() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - // DIRECTORY_DOCUMENTS is 19 or later only - return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); - } else { - return new File(Environment.getExternalStorageDirectory() + "/Documents"); - } - } - - @Override - public IFile getRootDirectory(Context context) { - File documentsDirectory = getDocumentsDir(); - if (!documentsDirectory.exists()) { - if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - if(!documentsDirectory.mkdirs()) { - // fallback to the toplevel dir - might be due to the dir not mounted/used as USB-Mass-Storage or similar - // TODO: handle unavailability of the storage/failure of the mkdir properly - Log.e("LocalDocumentsProvider", "not sure how we ended up here - if we have read permissions to use it in the first place, we also should have the write-permissions.."); - documentsDirectory = Environment.getExternalStorageDirectory(); - } - } - } - return new LocalFile(documentsDirectory); - } - - @Override - public int getNameResource() { - return R.string.local_documents; - } - - @Override - public boolean checkProviderAvailability(Context context) { - File documentsDirectory = getDocumentsDir(); - return documentsDirectory.exists() && ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - } -} diff --git a/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsProvider.java b/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsProvider.java deleted file mode 100644 index 1a10fad424db..000000000000 --- a/android/source/src/java/org/libreoffice/storage/local/LocalDocumentsProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- 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.storage.local; - -import java.net.URI; - -import org.libreoffice.storage.IDocumentProvider; -import org.libreoffice.storage.IFile; - -import org.libreoffice.R; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Environment; -import android.support.v4.content.ContextCompat; - -/** - * Implementation of IDocumentProvider for the local file system. - */ -public class LocalDocumentsProvider implements IDocumentProvider { - - private int id; - - public LocalDocumentsProvider(int id) { - this.id = id; - } - - @Override - public IFile getRootDirectory(Context context) { - return new LocalFile(Environment.getExternalStorageDirectory()); - } - - @Override - public IFile createFromUri(Context context, URI uri) { - return new LocalFile(uri); - } - - @Override - public int getNameResource() { - return R.string.local_file_system; - } - - @Override - public int getId() { - return id; - } - - @Override - public boolean checkProviderAvailability(Context context) { - return ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - } -} diff --git a/android/source/src/java/org/libreoffice/storage/local/LocalFile.java b/android/source/src/java/org/libreoffice/storage/local/LocalFile.java deleted file mode 100644 index 4ff5bbf119f4..000000000000 --- a/android/source/src/java/org/libreoffice/storage/local/LocalFile.java +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- 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.storage.local; - -import android.content.Context; - -import java.io.File; -import java.io.FileFilter; -import java.net.URI; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.libreoffice.storage.IFile; - -/** - * Implementation of IFile for the local file system. - */ -public class LocalFile implements IFile { - - private File file; - - public LocalFile(File file) { - this.file = file; - } - - public LocalFile(URI uri) { - this.file = new File(uri); - } - - public URI getUri() { - return file.toURI(); - } - - public String getName() { - return file.getName(); - } - - @Override - public boolean isDirectory() { - return file.isDirectory(); - } - - @Override - public long getSize() { - return file.length(); - } - - @Override - public Date getLastModified() { - return new Date(file.lastModified()); - } - - @Override - public List<IFile> listFiles() { - List<IFile> children = new ArrayList<IFile>(); - for (File child : file.listFiles()) { - children.add(new LocalFile(child)); - } - return children; - } - - @Override - public List<IFile> listFiles(FileFilter filter) { - List<IFile> children = new ArrayList<IFile>(); - for (File child : file.listFiles(filter)) { - children.add(new LocalFile(child)); - } - return children; - } - - @Override - public IFile getParent(Context context) { - return new LocalFile(file.getParentFile()); - } - - @Override - public File getDocument() { - return file; - } - - @Override - public boolean equals(Object object) { - if (this == object) - return true; - if (!(object instanceof LocalFile)) - return false; - LocalFile file = (LocalFile) object; - return file.getUri().equals(getUri()); - } - - @Override - public void saveDocument(File file) { - // do nothing; file is local - } -} diff --git a/android/source/src/java/org/libreoffice/ui/FileUtilities.java b/android/source/src/java/org/libreoffice/ui/FileUtilities.java index 5a4224f2ceb9..5bcc48d31141 100644 --- a/android/source/src/java/org/libreoffice/ui/FileUtilities.java +++ b/android/source/src/java/org/libreoffice/ui/FileUtilities.java @@ -8,17 +8,9 @@ */ package org.libreoffice.ui; -import org.libreoffice.storage.IFile; - import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.text.Collator; import java.util.Map; -import java.util.Collections; -import java.util.List; import java.util.HashMap; -import java.util.Comparator; import android.content.ContentResolver; import android.database.Cursor; @@ -41,17 +33,6 @@ public class FileUtilities { static final int UNKNOWN = 10; - static final int SORT_AZ = 0; - static final int SORT_ZA = 1; - /** Oldest Files First*/ - static final int SORT_OLDEST = 2; - /** Newest Files First*/ - static final int SORT_NEWEST = 3; - /** Largest Files First */ - static final int SORT_LARGEST = 4; - /** Smallest Files First */ - static final int SORT_SMALLEST = 5; - public static final String DEFAULT_WRITER_EXTENSION = ".odt"; public static final String DEFAULT_IMPRESS_EXTENSION = ".odp"; public static final String DEFAULT_SPREADSHEET_EXTENSION = ".ods"; @@ -183,81 +164,6 @@ public class FileUtilities { return true; } - static FileFilter getFileFilter(final int mode) { - return new FileFilter() { - public boolean accept(File pathname) { - if (pathname.isDirectory()) - return true; - if (lookupExtension(pathname.getName()) == UNKNOWN) - return false; - return doAccept(pathname.getName(), mode, ""); - } - }; - } - - static FilenameFilter getFilenameFilter(final int mode) { - return new FilenameFilter() { - public boolean accept(File dir, String filename) { - if (new File(dir , filename).isDirectory()) - return true; - return doAccept(filename, mode, ""); - } - }; - } - - static void sortFiles(List<IFile> files, int sortMode) { - if (files == null) - return; - // Compare filenames in the default locale - final Collator mCollator = Collator.getInstance(); - switch (sortMode) { - case SORT_AZ: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return mCollator.compare(lhs.getName(), rhs.getName()); - } - }); - break; - case SORT_ZA: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return mCollator.compare(rhs.getName(), lhs.getName()); - } - }); - break; - case SORT_OLDEST: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return lhs.getLastModified().compareTo(rhs.getLastModified()); - } - }); - break; - case SORT_NEWEST: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return rhs.getLastModified().compareTo(lhs.getLastModified()); - } - }); - break; - case SORT_LARGEST: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return Long.valueOf(rhs.getSize()).compareTo(lhs.getSize()); - } - }); - break; - case SORT_SMALLEST: - Collections.sort(files , new Comparator<IFile>() { - public int compare(IFile lhs, IFile rhs) { - return Long.valueOf(lhs.getSize()).compareTo(rhs.getSize()); - } - }); - break; - default: - Log.e(LOGTAG, "uncatched sortMode: " + sortMode); - } - } - static boolean isHidden(File file) { return file.getName().startsWith("."); } @@ -266,20 +172,6 @@ public class FileUtilities { return isHidden(file) && file.getName().endsWith(".png"); } - static boolean hasThumbnail(File file) { - String filename = file.getName(); - if (lookupExtension(filename) == DOC) // only do this for docs for now - { - // Will need another method to check if Thumb is up-to-date - or extend this one? - return new File(file.getParent(), getThumbnailName(file)).isFile(); - } - return true; - } - - static String getThumbnailName(File file) { - return "." + file.getName().split("[.]")[0] + ".png" ; - } - /** * Tries to retrieve the display (which should be the document name) * for the given URI using the given resolver. diff --git a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java index 3236b53e7dc5..9f89bbedc525 100644 --- a/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java +++ b/android/source/src/java/org/libreoffice/ui/LibreOfficeUIActivity.java @@ -9,85 +9,48 @@ package org.libreoffice.ui; -import android.Manifest; -import android.app.Activity; import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.database.Cursor; 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.preference.PreferenceManager; -import android.provider.OpenableColumns; -import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.NavigationView; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; -import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; -import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.OvershootInterpolator; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import org.libreoffice.AboutDialogFragment; -import org.libreoffice.LOKitShell; import org.libreoffice.LibreOfficeMainActivity; import org.libreoffice.LocaleHelper; import org.libreoffice.R; import org.libreoffice.SettingsActivity; import org.libreoffice.SettingsListenerModel; -import org.libreoffice.storage.DocumentProviderFactory; -import org.libreoffice.storage.DocumentProviderSettingsActivity; -import org.libreoffice.storage.IDocumentProvider; -import org.libreoffice.storage.IFile; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.net.URI; -import java.net.URISyntaxException; -import java.text.SimpleDateFormat; + import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class LibreOfficeUIActivity extends AppCompatActivity implements SettingsListenerModel.OnSettingsPreferenceChangedListener, View.OnClickListener{ public enum DocumentType { @@ -99,37 +62,13 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings } private String LOGTAG = LibreOfficeUIActivity.class.getSimpleName(); - private SharedPreferences prefs; - private int filterMode = FileUtilities.ALL; - private int viewMode; - private int sortMode; - private boolean showHiddenFiles; - private String displayLanguage; - - // dynamic permissions IDs - private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0; - - FileFilter fileFilter; - FilenameFilter filenameFilter; - private List<IFile> filePaths = new ArrayList<IFile>(); - private DocumentProviderFactory documentProviderFactory; - private IDocumentProvider documentProvider; - private IFile homeDirectory; - 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"; - public static final String EXPLORER_VIEW_TYPE_KEY = "EXPLORER_VIEW_TYPE"; public static final String EXPLORER_PREFS_KEY = "EXPLORER_PREFS"; - public static final String SORT_MODE_KEY = "SORT_MODE"; private static final String RECENT_DOCUMENTS_KEY = "RECENT_DOCUMENT_URIS"; // delimiter used for storing multiple URIs in a string private static final String RECENT_DOCUMENTS_DELIMITER = " "; - 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_DOC_TYPE_KEY = "NEW_DOC_TYPE_KEY"; @@ -178,19 +117,9 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings "image/svg+xml", }; - public static final int GRID_VIEW = 0; - 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; - private ActionBar actionBar; - private ActionBarDrawerToggle drawerToggle; - private RecyclerView fileRecyclerView; - private RecyclerView recentRecyclerView; - private Animation fabOpenAnimation; private Animation fabCloseAnimation; private boolean isFabMenuOpen = false; @@ -203,28 +132,15 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings private LinearLayout writerLayout; private LinearLayout impressLayout; private LinearLayout calcLayout; - private LinearLayout systemFilePickerLayout; - private TextView openFileView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // initialize document provider factory - DocumentProviderFactory.initialize(this); - documentProviderFactory = DocumentProviderFactory.getInstance(); - - PreferenceManager.setDefaultValues(this, R.xml.documentprovider_preferences, false); readPreferences(); SettingsListenerModel.getInstance().setListener(this); - // Registering the USB detect broadcast receiver - IntentFilter filter = new IntentFilter(); - filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); - filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); - registerReceiver(mUSBReceiver, filter); - // init UI and populate with contents from the provider - + // init UI createUI(); fabOpenAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_open); fabCloseAnimation = AnimationUtils.loadAnimation(this, R.anim.fab_close); @@ -236,15 +152,14 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings } public void createUI() { - setContentView(R.layout.activity_document_browser); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - actionBar = getSupportActionBar(); + ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setIcon(R.drawable.lo_icon); } editFAB = findViewById(R.id.editFAB); @@ -261,11 +176,13 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings impressLayout = findViewById(R.id.impressLayout); calcLayout = findViewById(R.id.calcLayout); drawLayout = findViewById(R.id.drawLayout); - openFileView = findViewById(R.id.open_file_view); + TextView openFileView = findViewById(R.id.open_file_view); openFileView.setOnClickListener(this); - recentRecyclerView = findViewById(R.id.list_recent); + RecyclerView recentRecyclerView = findViewById(R.id.list_recent); + + SharedPreferences prefs = getSharedPreferences(EXPLORER_PREFS_KEY, MODE_PRIVATE); String recentPref = prefs.getString(RECENT_DOCUMENTS_KEY, ""); List<String> recentFileStrings = Arrays.asList(recentPref.split(RECENT_DOCUMENTS_DELIMITER)); @@ -280,95 +197,6 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings recentRecyclerView.setLayoutManager(new GridLayoutManager(this, 2)); recentRecyclerView.setAdapter(new RecentFilesAdapter(this, recentFiles)); - - fileRecyclerView = findViewById(R.id.file_recycler_view); - systemFilePickerLayout = findViewById(R.id.system_file_picker_layout); - //This should be tested because it possibly disables view recycling - fileRecyclerView.setNestedScrollingEnabled(false); - openDirectory(currentDirectory); - registerForContextMenu(fileRecyclerView); - - //Setting up navigation drawer - drawerLayout = findViewById(R.id.drawer_layout); - navigationDrawer = findViewById(R.id.navigation_drawer); - - final ArrayList<CharSequence> providerNames = new ArrayList<CharSequence>( - Arrays.asList(documentProviderFactory.getNames()) - ); - - // Loop through the document providers menu items and check if they are available or not - for (int index = 0; index < providerNames.size(); index++) { - MenuItem item = navigationDrawer.getMenu().getItem(index); - item.setEnabled(documentProviderFactory.getProvider(index).checkProviderAvailability(this)); - } - - navigationDrawer.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { - @Override - public boolean onNavigationItemSelected(@NonNull MenuItem item) { - - switch (item.getItemId()) { - case R.id.menu_storage_preferences: { - startActivity(new Intent(LibreOfficeUIActivity.this, DocumentProviderSettingsActivity.class)); - return true; - } - - case R.id.menu_provider_documents: { - switchToDocumentProvider(documentProviderFactory.getProvider(0)); - return true; - } - - case R.id.menu_provider_filesystem: { - switchToDocumentProvider(documentProviderFactory.getProvider(1)); - return true; - } - - case R.id.menu_provider_extsd: { - switchToDocumentProvider(documentProviderFactory.getProvider(2)); - return true; - } - - case R.id.menu_provider_otg: { - switchToDocumentProvider(documentProviderFactory.getProvider(3)); - return true; - } - - case R.id.menu_system_file_dialog: { - switchToSystemFileDialogLayout(); - return true; - } - - default: - return false; - } - - - } - }); - drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, - R.string.document_locations, R.string.close_document_locations) { - - @Override - public void onDrawerOpened(View drawerView) { - super.onDrawerOpened(drawerView); - supportInvalidateOptionsMenu(); - navigationDrawer.requestFocus(); // Make keypad navigation easier - if (isFabMenuOpen) { - collapseFabMenu(); //Collapse FAB Menu when drawer is opened - } - } - - @Override - public void onDrawerClosed(View drawerView) { - super.onDrawerClosed(drawerView); - supportInvalidateOptionsMenu(); - } - }; - drawerToggle.setDrawerIndicatorEnabled(true); - drawerLayout.addDrawerListener(drawerToggle); - drawerToggle.syncState(); - - // initially show layout with item to open system file picker - switchToSystemFileDialogLayout(); } private void expandFabMenu() { @@ -398,42 +226,8 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings } @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - - drawerToggle.syncState(); - } - - private void refreshView() { - // enable home icon as "up" if required - if (currentDirectory != null && homeDirectory != null && !currentDirectory.equals(homeDirectory)) { - drawerToggle.setDrawerIndicatorEnabled(false); - } else { - drawerToggle.setDrawerIndicatorEnabled(true); - } - - FileUtilities.sortFiles(filePaths, sortMode); - // refresh view - fileRecyclerView.setLayoutManager(isViewModeList() ? new LinearLayoutManager(this) : new GridLayoutManager(this, 3)); - fileRecyclerView.setAdapter(new ExplorerItemAdapter(this, filePaths)); - // close drawer if it was open - drawerLayout.closeDrawer(navigationDrawer); - if (isFabMenuOpen) { - collapseFabMenu(); - } - } - - @Override public void onBackPressed() { - if (drawerLayout.isDrawerOpen(navigationDrawer)) { - drawerLayout.closeDrawer(navigationDrawer); - if (isFabMenuOpen) { - collapseFabMenu(); - } - } else if (currentDirectory != null && homeDirectory != null && !currentDirectory.equals(homeDirectory)) { - // navigate upwards in directory hierarchy - openParentDirectory(); - } else if (isFabMenuOpen) { + if (isFabMenuOpen) { collapseFabMenu(); } else { super.onBackPressed(); @@ -441,32 +235,6 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings } @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.context_menu, menu); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.context_menu_open: - open(currentlySelectedFile); - return true; - case R.id.context_menu_share: - share(currentlySelectedFile); - return true; - default: - return super.onContextItemSelected(item); - } - } - - private boolean isViewModeList(){ - return viewMode == LIST_VIEW; - } - - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_OPEN_FILECHOOSER && resultCode == RESULT_OK) { final Uri fileUri = data.getData(); @@ -495,172 +263,6 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings } } - - private void switchToDocumentProvider(IDocumentProvider provider) { - fileRecyclerView.setVisibility(View.VISIBLE); - systemFilePickerLayout.setVisibility(View.GONE); - - new AsyncTask<IDocumentProvider, Void, Void>() { - @Override - protected Void doInBackground(IDocumentProvider... provider) { - // switch document provider: - // these operations may imply network access and must be run in - // a different thread - try { - homeDirectory = provider[0].getRootDirectory(LibreOfficeUIActivity.this); - List<IFile> paths = homeDirectory.listFiles(FileUtilities - .getFileFilter(filterMode)); - filePaths = new ArrayList<IFile>(); - for(IFile file: paths) { - if(showHiddenFiles){ - filePaths.add(file); - } else { - if(!file.getName().startsWith(".")){ - filePaths.add(file); - } - } - } - } - 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)); - Log.e(LOGTAG, "failed to switch document provider "+ e.getMessage(), e.getCause()); - return null; - } - //no exception - documentProvider = provider[0]; - currentDirectory = homeDirectory; - return null; - } - - @Override - protected void onPostExecute(Void result) { - refreshView(); - } - }.execute(provider); - } - - private void switchToSystemFileDialogLayout() { - fileRecyclerView.setVisibility(View.GONE); - findViewById(R.id.text_directory_path).setVisibility(View.GONE); - systemFilePickerLayout.setVisibility(View.VISIBLE); - refreshView(); - } - - public void openDirectory(IFile dir) { - if (dir == null) - return; - - //show recent files if in home directory - if (dir.equals(homeDirectory)) { - recentRecyclerView.setVisibility(View.VISIBLE); - findViewById(R.id.header_browser).setVisibility((View.VISIBLE)); - findViewById(R.id.header_recents).setVisibility((View.VISIBLE)); - actionBar.setTitle(R.string.app_name); - findViewById(R.id.text_directory_path).setVisibility(View.GONE); - } else { - recentRecyclerView.setVisibility(View.GONE); - findViewById(R.id.header_browser).setVisibility((View.GONE)); - findViewById(R.id.header_recents).setVisibility((View.GONE)); - actionBar.setTitle(dir.getName()); - findViewById(R.id.text_directory_path).setVisibility(View.VISIBLE); - ((TextView)findViewById(R.id.text_directory_path)).setText(getString(R.string.current_dir, - dir.getUri().getPath())); - } - - new AsyncTask<IFile, Void, Void>() { - @Override - protected Void doInBackground(IFile... dir) { - // get list of files: - // this operation may imply network access and must be run in - // a different thread - currentDirectory = dir[0]; - try { - List<IFile> paths = currentDirectory.listFiles(FileUtilities - .getFileFilter(filterMode)); - filePaths = new ArrayList<IFile>(); - for(IFile file: paths) { - if(showHiddenFiles){ - filePaths.add(file); - } else { - if(!file.getName().startsWith(".")){ - filePaths.add(file); - } - } - } - } - 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(); - } - }); - Log.e(LOGTAG, e.getMessage(), e.getCause()); - } - return null; - } - - @Override - protected void onPostExecute(Void result) { - refreshView(); - } - }.execute(dir); - } - - public void open(final IFile document) { - new AsyncTask<IFile, Void, File>() { - @Override - protected File doInBackground(IFile... document) { - // this operation may imply network access and must be run in - // a different thread - try { - return document[0].getDocument(); - } - 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(); - } - }); - Log.e(LOGTAG, e.getMessage(), e.getCause()); - return null; - } - } - - @Override - protected void onPostExecute(File file) { - if (file != null) { - Intent i = new Intent(Intent.ACTION_VIEW, Uri.fromFile(file)); - String packageName = getApplicationContext().getPackageName(); - ComponentName componentName = new ComponentName(packageName, - LibreOfficeMainActivity.class.getName()); - i.setComponent(componentName); - - // these extras allow to rebuild the IFile object in LOMainActivity - i.putExtra("org.libreoffice.document_provider_id", - documentProvider.getId()); - i.putExtra("org.libreoffice.document_uri", - document.getUri()); - - startActivity(i); - } - } - }.execute(document); - } - public void openDocument(final Uri documentUri) { // "forward" to LibreOfficeMainActivity to open the file Intent intent = new Intent(Intent.ACTION_VIEW, documentUri); @@ -722,212 +324,17 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings startActivity(intent); } - private void open(int position) { - IFile file = filePaths.get(position); - if (!file.isDirectory()) { - open(file); - } else { - openDirectory(file); - } - } - - private void openParentDirectory() { - new AsyncTask<Void, Void, IFile>() { - @Override - protected IFile doInBackground(Void... dir) { - // this operation may imply network access and must be run in - // a different thread - return currentDirectory.getParent(LibreOfficeUIActivity.this); - } - - @Override - protected void onPostExecute(IFile result) { - openDirectory(result); - } - }.execute(); - } - - private void share(int position) { - - new AsyncTask<IFile, Void, File>() { - @Override - protected File doInBackground(IFile... document) { - // this operation may imply network access and must be run in - // a different thread - try { - return document[0].getDocument(); - } 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(); - } - }); - Log.e(LOGTAG, e.getMessage(), e.getCause()); - return null; - } - } - - @Override - protected void onPostExecute(File file) { - if (file != null) { - Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); - Uri uri = Uri.fromFile(file); - sharingIntent.setType(FileUtilities.getMimeType(file.getName())); - sharingIntent.putExtra(android.content.Intent.EXTRA_STREAM, uri); - sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, - file.getName()); - startActivity(Intent.createChooser(sharingIntent, - getString(R.string.share_via))); - } - } - }.execute(filePaths.get(position)); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.view_menu, menu); - switch (sortMode) { - case FileUtilities.SORT_SMALLEST: { - menu.findItem(R.id.menu_sort_size_asc).setChecked(true); - } - break; - - case FileUtilities.SORT_LARGEST: { - menu.findItem(R.id.menu_sort_size_desc).setChecked(true); - } - break; - - case FileUtilities.SORT_AZ: { - menu.findItem(R.id.menu_sort_az).setChecked(true); - } - break; - - case FileUtilities.SORT_ZA: { - menu.findItem(R.id.menu_sort_za).setChecked(true); - } - break; - - case FileUtilities.SORT_NEWEST: { - menu.findItem(R.id.menu_sort_modified_newest).setChecked(true); - } - break; - - case FileUtilities.SORT_OLDEST: { - menu.findItem(R.id.menu_sort_modified_oldest).setChecked(true); - } - break; - } - - switch (filterMode) { - case FileUtilities.ALL: - menu.findItem(R.id.menu_filter_everything).setChecked(true); - break; - - case FileUtilities.DOC: - menu.findItem(R.id.menu_filter_documents).setChecked(true); - break; - - case FileUtilities.CALC: - menu.findItem(R.id.menu_filter_presentations).setChecked(true); - break; - - case FileUtilities.IMPRESS: - menu.findItem(R.id.menu_filter_presentations).setChecked(true); - break; - - case FileUtilities.DRAWING: - menu.findItem(R.id.menu_filter_drawings).setChecked(true); - break; - } - return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - // Will close the drawer if the home button is pressed - if (drawerToggle.onOptionsItemSelected(item)) { - return true; - } - switch (item.getItemId()) { - case android.R.id.home: - if (!currentDirectory.equals(homeDirectory)){ - openParentDirectory(); - } - break; - - case R.id.menu_filter_everything: - item.setChecked(true); - filterMode = FileUtilities.ALL; - openDirectory(currentDirectory); - break; - - case R.id.menu_filter_documents: - item.setChecked(true); - filterMode = FileUtilities.DOC; - openDirectory(currentDirectory); - break; - - case R.id.menu_filter_spreadsheets: - item.setChecked(true); - filterMode = FileUtilities.CALC; - openDirectory(currentDirectory); - break; - - case R.id.menu_filter_presentations: - item.setChecked(true); - filterMode = FileUtilities.IMPRESS; - openDirectory(currentDirectory); - break; - - case R.id.menu_filter_drawings: - item.setChecked(true); - filterMode = FileUtilities.DRAWING; - openDirectory(currentDirectory); - break; - - case R.id.menu_sort_size_asc: { - sortMode = FileUtilities.SORT_SMALLEST; - this.onResume(); - } - break; - - case R.id.menu_sort_size_desc: { - sortMode = FileUtilities.SORT_LARGEST; - this.onResume(); - } - break; - - case R.id.menu_sort_az: { - sortMode = FileUtilities.SORT_AZ; - this.onResume(); - } - break; - - case R.id.menu_sort_za: { - sortMode = FileUtilities.SORT_ZA; - this.onResume(); - } - break; - - case R.id.menu_sort_modified_newest: { - sortMode = FileUtilities.SORT_NEWEST; - this.onResume(); - } - break; - - case R.id.menu_sort_modified_oldest: { - sortMode = FileUtilities.SORT_OLDEST; - this.onResume(); - } - break; - case R.id.action_about: { AboutDialogFragment aboutDialogFragment = new AboutDialogFragment(); aboutDialogFragment.show(getSupportFragmentManager(), "AboutDialogFragment"); @@ -940,154 +347,28 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings default: return super.onOptionsItemSelected(item); } - return true; } public void readPreferences(){ - prefs = getSharedPreferences(EXPLORER_PREFS_KEY, MODE_PRIVATE); - sortMode = prefs.getInt(SORT_MODE_KEY, FileUtilities.SORT_AZ); SharedPreferences defaultPrefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); - viewMode = Integer.valueOf(defaultPrefs.getString(EXPLORER_VIEW_TYPE_KEY, ""+ GRID_VIEW)); - filterMode = Integer.valueOf(defaultPrefs.getString(FILTER_MODE_KEY , "-1")); - showHiddenFiles = defaultPrefs.getBoolean(ENABLE_SHOW_HIDDEN_FILES_KEY, false); - displayLanguage = defaultPrefs.getString(DISPLAY_LANGUAGE, LocaleHelper.SYSTEM_DEFAULT_LANGUAGE); - - Intent i = this.getIntent(); - if (i.hasExtra(CURRENT_DIRECTORY_KEY)) { - try { - currentDirectory = documentProvider.createFromUri(this, new URI( - i.getStringExtra(CURRENT_DIRECTORY_KEY))); - } catch (URISyntaxException e) { - currentDirectory = documentProvider.getRootDirectory(this); - } - Log.d(LOGTAG, CURRENT_DIRECTORY_KEY); - } - - if (i.hasExtra(FILTER_MODE_KEY)) { - filterMode = i.getIntExtra( FILTER_MODE_KEY, FileUtilities.ALL); - Log.d(LOGTAG, FILTER_MODE_KEY); - } - - if (i.hasExtra(EXPLORER_VIEW_TYPE_KEY)) { - viewMode = i.getIntExtra( EXPLORER_VIEW_TYPE_KEY, GRID_VIEW); - Log.d(LOGTAG, EXPLORER_VIEW_TYPE_KEY); - } - + final String displayLanguage = defaultPrefs.getString(DISPLAY_LANGUAGE, LocaleHelper.SYSTEM_DEFAULT_LANGUAGE); LocaleHelper.setLocale(this, displayLanguage); } @Override public void settingsPreferenceChanged(SharedPreferences sharedPreferences, String key) { readPreferences(); - refreshView(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - // TODO Auto-generated method stub - super.onSaveInstanceState(outState); - - if(currentDirectory != null) { - outState.putString(CURRENT_DIRECTORY_KEY, currentDirectory.getUri().toString()); - Log.d(LOGTAG, currentDirectory.toString() + Integer.toString(filterMode) + Integer.toString(viewMode)); - } - outState.putInt(FILTER_MODE_KEY, filterMode); - outState.putInt(EXPLORER_VIEW_TYPE_KEY , viewMode); - if(documentProvider != null) - outState.putInt(DOC_PROVIDER_KEY, documentProvider.getId()); - - outState.putBoolean(ENABLE_SHOW_HIDDEN_FILES_KEY , showHiddenFiles); - - //prefs.edit().putInt(EXPLORER_VIEW_TYPE, viewType).commit(); - Log.d(LOGTAG, "savedInstanceState"); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - // TODO Auto-generated method stub - super.onRestoreInstanceState(savedInstanceState); - if (savedInstanceState.isEmpty()){ - return; - } - if (documentProvider == null) { - Log.d(LOGTAG, "onRestoreInstanceState - documentProvider is null"); - documentProvider = DocumentProviderFactory.getInstance() - .getProvider(savedInstanceState.getInt(DOC_PROVIDER_KEY)); - } - try { - currentDirectory = documentProvider.createFromUri(this, new URI( - savedInstanceState.getString(CURRENT_DIRECTORY_KEY))); - } catch (URISyntaxException e) { - currentDirectory = documentProvider.getRootDirectory(this); - } - filterMode = savedInstanceState.getInt(FILTER_MODE_KEY, FileUtilities.ALL); - viewMode = savedInstanceState.getInt(EXPLORER_VIEW_TYPE_KEY, GRID_VIEW); - showHiddenFiles = savedInstanceState.getBoolean(ENABLE_SHOW_HIDDEN_FILES_KEY, false); - //openDirectory(currentDirectory); - Log.d(LOGTAG, "onRestoreInstanceState"); - Log.d(LOGTAG, currentDirectory.toString() + Integer.toString(filterMode) + Integer.toString(viewMode)); - } - - private final BroadcastReceiver mUSBReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { - Toast.makeText(context, R.string.usb_connected_configure, Toast.LENGTH_SHORT).show(); - startActivity(new Intent(context, DocumentProviderSettingsActivity.class)); - Log.d(LOGTAG, "USB device attached"); - } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { - Log.d(LOGTAG, "USB device detached"); - } - } - }; - @Override - protected void onPause() { - super.onPause(); - Log.d(LOGTAG, "onPause"); } @Override protected void onResume() { super.onResume(); Log.d(LOGTAG, "onResume"); - Log.d(LOGTAG, "sortMode="+ sortMode + " filterMode=" + filterMode); createUI(); } - @Override - protected void onStart() { - super.onStart(); - if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - Log.i(LOGTAG, "no permission to read external storage - asking for permission"); - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - PERMISSION_WRITE_EXTERNAL_STORAGE); - } else { - switchToDocumentProvider(documentProviderFactory.getDefaultProvider()); - setEditFABVisibility(View.VISIBLE); - } - Log.d(LOGTAG, "onStart"); - } - - @Override - protected void onStop() { - super.onStop(); - Log.d(LOGTAG, "onStop"); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - unregisterReceiver(mUSBReceiver); - Log.d(LOGTAG, "onDestroy"); - } - - private int dpToPx(int dp){ - final float scale = getApplicationContext().getResources().getDisplayMetrics().density; - return (int) (dp * scale + 0.5f); - } - private void addDocumentToRecents(Uri fileUri) { + SharedPreferences prefs = getSharedPreferences(EXPLORER_PREFS_KEY, MODE_PRIVATE); if (Build.VERSION.SDK_INT < 19) { // ContentResolver#takePersistableUriPermission only available from SDK level 19 on Log.i(LOGTAG, "Recently used files not supported, requires SDK version >= 19."); @@ -1211,141 +492,6 @@ public class LibreOfficeUIActivity extends AppCompatActivity implements Settings break; } } - - - class ExplorerItemAdapter extends RecyclerView.Adapter<ExplorerItemAdapter.ViewHolder> { - - private Activity mActivity; - private List<IFile> filePaths; - private final long KB = 1024; - private final long MB = 1048576; - - ExplorerItemAdapter(Activity activity, List<IFile> filePaths) { - this.mActivity = activity; - this.filePaths = filePaths; - } - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View item = LayoutInflater.from(parent.getContext()) - .inflate(isViewModeList() ? R.layout.file_list_item : R.layout.file_explorer_grid_item, parent, false); - return new ViewHolder(item); - } - - @Override - public void onBindViewHolder(final ViewHolder holder, final int position) { - final IFile file = filePaths.get(position); - - holder.itemView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - open(holder.getAdapterPosition()); - } - }); - holder.itemView.setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View view) { - //to be picked out by floating context menu (workaround-ish) - currentlySelectedFile = holder.getAdapterPosition(); - //must return false so the click is not consumed - return false; - } - }); - - holder.filenameView.setText(file.getName()); - switch (FileUtilities.getType(file.getName())) { - case FileUtilities.DOC: - holder.iconView.setImageResource(R.drawable.writer); - break; - case FileUtilities.CALC: - holder.iconView.setImageResource(R.drawable.calc); - break; - case FileUtilities.DRAWING: - holder.iconView.setImageResource(R.drawable.draw); - break; - case FileUtilities.IMPRESS: - holder.iconView.setImageResource(R.drawable.impress); - break; - } - - if (file.isDirectory()) { - //Eventually have thumbnails of each sub file on a black circle - //For now just a folder icon - holder.iconView.setImageResource(R.drawable.ic_folder_black_24dp); - holder.iconView.setColorFilter(ContextCompat.getColor(mActivity, R.color.text_color_secondary)); - } - - // Date and Size field only exist when we are displaying items in a list. - if(isViewModeList()) { - if (!file.isDirectory()) { - String size; - long length = filePaths.get(position).getSize(); - if (length < KB) { - size = Long.toString(length) + "B"; - } else if (length < MB) { - size = Long.toString(length / KB) + "KB"; - } else { - size = Long.toString(length / MB) + "MB"; - } - holder.fileSizeView.setText(size); - } - SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy hh:ss"); - Date date = file.getLastModified(); - //TODO format date - holder.fileDateView.setText(df.format(date)); - } - } - - @Override - public int getItemCount() { - return filePaths.size(); - } - - class ViewHolder extends RecyclerView.ViewHolder { - - View itemView; - TextView filenameView, fileSizeView, fileDateView; - ImageView iconView; - - ViewHolder(View itemView) { - super(itemView); - this.itemView = itemView; - filenameView = itemView.findViewById(R.id.file_item_name); - iconView = itemView.findViewById(R.id.file_item_icon); - // Check if view mode is List, only then initialise Size and Date field - if (isViewModeList()) { - fileSizeView = itemView.findViewById(R.id.file_item_size); - fileDateView = itemView.findViewById(R.id.file_item_date); - } - } - } - } - - private void setEditFABVisibility(final int visibility){ - LOKitShell.getMainHandler().post(new Runnable() { - @Override - public void run() { - editFAB.setVisibility(visibility); - } - }); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - switch(requestCode){ - case PERMISSION_WRITE_EXTERNAL_STORAGE: - if(permissions.length>0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ - switchToDocumentProvider(documentProviderFactory.getDefaultProvider()); - setEditFABVisibility(View.VISIBLE); - } else { - setEditFABVisibility(View.INVISIBLE); - } - break; - default: - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |