Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New, overhauled data storage management #1954

Merged
merged 11 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions src/gplay/java/com/owncloud/android/utils/PushUtils.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Nextcloud Android client application
*
* @author Mario Danic
Expand Down Expand Up @@ -26,6 +26,7 @@
import android.content.Context;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.google.gson.Gson;
import com.owncloud.android.MainApp;
Expand Down Expand Up @@ -99,8 +100,9 @@ public static String bytesToHex(byte[] bytes) {
}

private static int generateRsa2048KeyPair() {
String keyPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator
+ KEYPAIR_FOLDER;
migratePushKeys();
String keyPath = MainApp.getAppContext().getFilesDir().getAbsolutePath() + File.separator +
MainApp.getDataFolder() + File.separator + KEYPAIR_FOLDER;

String privateKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PRIV_EXTENSION;
String publicKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PUB_EXTENSION;
Expand Down Expand Up @@ -227,8 +229,8 @@ public static void pushRegistrationToServer() {
publicKey,
context.getResources().getString(R.string.push_server_url));

RemoteOperationResult remoteOperationResult = registerAccountDeviceForNotificationsOperation.
execute(mClient);
RemoteOperationResult remoteOperationResult =
registerAccountDeviceForNotificationsOperation.execute(mClient);

if (remoteOperationResult.isSuccess()) {
PushResponse pushResponse = remoteOperationResult.getPushResponseData();
Expand Down Expand Up @@ -271,8 +273,8 @@ public static void pushRegistrationToServer() {
}

public static Key readKeyFromFile(boolean readPublicKey) {
String keyPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder() + File.separator
+ KEYPAIR_FOLDER;
String keyPath = MainApp.getAppContext().getFilesDir().getAbsolutePath() + File.separator +
MainApp.getDataFolder() + File.separator + KEYPAIR_FOLDER;

String privateKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PRIV_EXTENSION;
String publicKeyPath = keyPath + File.separator + KEYPAIR_FILE_NAME + KEYPAIR_PUB_EXTENSION;
Expand Down Expand Up @@ -334,4 +336,44 @@ private static int saveKeyToFile(Key key, String path) {

return -1;
}

private static void migratePushKeys() {
Context context = MainApp.getAppContext();

if (!PreferenceManager.getKeysMigration(context)) {
String oldKeyPath = MainApp.getStoragePath() + File.separator + MainApp.getDataFolder()
+ File.separator + "nc-keypair";
File oldPrivateKeyFile = new File(oldKeyPath, "push_key.priv");
File oldPublicKeyFile = new File(oldKeyPath, "push_key.pub");

String keyPath = context.getDir("nc-keypair", Context.MODE_PRIVATE).getAbsolutePath();
File privateKeyFile = new File(keyPath, "push_key.priv");
File publicKeyFile = new File(keyPath, "push_key.pub");

if ((privateKeyFile.exists() && publicKeyFile.exists()) ||
(!oldPrivateKeyFile.exists() && !oldPublicKeyFile.exists())) {
PreferenceManager.setKeysMigration(context, true);
} else {
if (oldPrivateKeyFile.exists()) {
try {
FileStorageUtils.moveFile(oldPrivateKeyFile, privateKeyFile);
} catch (IOException e) {
Log.e(TAG, "Failed to move old private key to new location");
}
}

if (oldPublicKeyFile.exists()) {
try {
FileStorageUtils.moveFile(oldPublicKeyFile, publicKeyFile);
} catch (IOException e) {
Log.e(TAG, "Failed to move old public key to new location");
}
}

if (privateKeyFile.exists() && publicKeyFile.exists()) {
PreferenceManager.setKeysMigration(context, true);
}
}
}
}
}
5 changes: 2 additions & 3 deletions src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.support.annotation.StringRes;
import android.support.multidex.MultiDexApplication;
Expand Down Expand Up @@ -115,8 +114,8 @@ public void onCreate() {

SharedPreferences appPrefs =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
MainApp.storagePath = appPrefs.getString(Preferences.PreferenceKeys.STORAGE_PATH, Environment.
getExternalStorageDirectory().getAbsolutePath());
MainApp.storagePath = appPrefs.getString(Preferences.PreferenceKeys.STORAGE_PATH,
getApplicationContext().getFilesDir().getAbsolutePath());

boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));

Expand Down
42 changes: 24 additions & 18 deletions src/main/java/com/owncloud/android/datamodel/OCFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.content.FileProvider;

import com.owncloud.android.R;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.utils.MimeType;
Expand Down Expand Up @@ -316,6 +318,19 @@ public Uri getStorageUri() {
return mLocalUri;
}


public Uri getLegacyExposedFileUri(Context context) {
if (mLocalPath == null || mLocalPath.length() == 0) {
return null;
}

if (mExposedFileUri == null) {
return Uri.parse(ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(mLocalPath));
}

return mExposedFileUri;

}
/*
Partly disabled because not all apps understand paths that we get via this method for now
*/
Expand All @@ -324,25 +339,16 @@ public Uri getExposedFileUri(Context context) {
return null;
}
if (mExposedFileUri == null) {
/*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// TODO - use FileProvider with any Android version, with deeper testing -> 2.2.0
mExposedFileUri = Uri.parse(
ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(mLocalPath)
);
} else {
// Use the FileProvider to get a content URI
try {
mExposedFileUri = FileProvider.getUriForFile(
context,
context.getString(R.string.file_provider_authority),
new File(mLocalPath)
);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "File can't be exported");
}
try {
mExposedFileUri = FileProvider.getUriForFile(
context,
context.getString(R.string.file_provider_authority),
new File(mLocalPath));
} catch (IllegalArgumentException ex) {
// Could not share file using FileProvider URI scheme.
// Fall back to legacy URI parsing.
getLegacyExposedFileUri(context);
}
}*/
return Uri.parse(ContentResolver.SCHEME_FILE + "://" + WebdavUtils.encodePath(mLocalPath));
}

return mExposedFileUri;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

package com.owncloud.android.datastorage;

import android.os.Build;
import android.os.Environment;

import com.owncloud.android.MainApp;
import com.owncloud.android.datastorage.providers.EnvironmentStoragePointProvider;
Expand All @@ -31,7 +31,6 @@
import com.owncloud.android.datastorage.providers.SystemDefaultStoragePointProvider;
import com.owncloud.android.datastorage.providers.VDCStoragePointProvider;

import java.io.File;
import java.util.Vector;

/**
Expand Down Expand Up @@ -63,18 +62,15 @@ public StoragePoint[] getAvailableStoragePoints() {
return mCachedStoragePoints.toArray(new StoragePoint[mCachedStoragePoints.size()]);
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
for (File f : MainApp.getAppContext().getExternalMediaDirs()) {
if (f != null) {
mCachedStoragePoints.add(new StoragePoint(f.getAbsolutePath(), f.getAbsolutePath()));
}
}
} else {
for (IStoragePointProvider p : mStorageProviders) {
if (p.canProvideStoragePoints()) {
mCachedStoragePoints.addAll(p.getAvailableStoragePoint());
}
}
// Add internal storage directory
mCachedStoragePoints.add(new StoragePoint(MainApp.getAppContext().getFilesDir().getAbsolutePath(),
MainApp.getAppContext().getFilesDir().getAbsolutePath()));

// Add external storage directory if available.
if (isExternalStorageWritable()) {
mCachedStoragePoints.add(new StoragePoint(
MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath(),
MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath()));
}

return mCachedStoragePoints.toArray(new StoragePoint[mCachedStoragePoints.size()]);
Expand All @@ -97,4 +93,11 @@ public void addStoragePointProvider(IStoragePointProvider provider) {
public void removeStoragePointProvider(IStoragePointProvider provider) {
mStorageProviders.remove(provider);
}

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@
import com.owncloud.android.R;
import com.owncloud.android.datastorage.StoragePoint;

import java.io.File;
import java.util.Vector;

import static android.os.Environment.getExternalStorageDirectory;

/**
* @author Bartosz Przybylski
*/
Expand All @@ -44,16 +41,9 @@ public Vector<StoragePoint> getAvailableStoragePoint() {
Vector<StoragePoint> result = new Vector<>();

final String defaultStringDesc = MainApp.getAppContext().getString(R.string.storage_description_default);
File path;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
path = MainApp.getAppContext().getExternalMediaDirs()[0];
} else {
path = getExternalStorageDirectory();
}

if (path != null && path.canWrite()) {
result.add(new StoragePoint(defaultStringDesc, path.getAbsolutePath()));
}
// Add private internal storage data directory.
result.add(new StoragePoint(defaultStringDesc,
MainApp.getAppContext().getFilesDir().getAbsolutePath()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a fan of this storage point using context. IMO there should be a method in MainApp which directly returns the files dir and use that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we use this at a couple other places, so not worried about this much.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would indeed be better to centralize this, but I agree with @mario that this does not need to be done now.


return result;
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/owncloud/android/db/PreferenceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public abstract class PreferenceManager {
private static final String PREF__INSTANT_VIDEO_UPLOAD_PATH_USE_SUBFOLDERS
= "instant_video_upload_path_use_subfolders";
private static final String PREF__LEGACY_CLEAN = "legacyClean";
private static final String PREF__KEYS_MIGRATION = "keysMigration";
private static final String PREF__AUTO_UPLOAD_UPDATE_PATH = "autoUploadPathUpdate";
private static final String PREF__PUSH_TOKEN = "pushToken";
private static final String PREF__AUTO_UPLOAD_SPLIT_OUT = "autoUploadEntriesSplitOut";
Expand Down Expand Up @@ -286,6 +287,11 @@ public static boolean getLegacyClean(Context context) {
return getDefaultSharedPreferences(context).getBoolean(PREF__LEGACY_CLEAN, false);
}

public static boolean getKeysMigration(Context context) {
return getDefaultSharedPreferences(context).getBoolean(PREF__KEYS_MIGRATION, false);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we wanted to start using ArbitraryDataProvider for stuff like this instead of shared preferences?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but later. Not less than a day before RC :P



/**
* Gets the auto upload paths flag last set.
*
Expand Down Expand Up @@ -316,6 +322,10 @@ public static void setLegacyClean(Context context, boolean legacyClean) {
saveBooleanPreference(context, PREF__LEGACY_CLEAN, legacyClean);
}

public static void setKeysMigration(Context context, boolean keysMigration) {
saveBooleanPreference(context, PREF__KEYS_MIGRATION, keysMigration);
}

public static void setAutoUploadInit(Context context, boolean autoUploadInit) {
saveBooleanPreference(context, PREF__AUTO_UPLOAD_INIT, autoUploadInit);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,9 @@ private void saveStoragePath(String newStoragePath) {
private void loadStoragePath() {
SharedPreferences appPrefs =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mStoragePath = appPrefs.getString(PreferenceKeys.STORAGE_PATH, Environment.getExternalStorageDirectory()
.getAbsolutePath());
// Load storage path from shared preferences. Use private internal storage by default.
mStoragePath = appPrefs.getString(PreferenceKeys.STORAGE_PATH,
getApplicationContext().getFilesDir().getAbsolutePath());
String storageDescription = DataStorageProvider.getInstance().getStorageDescriptionByPath(mStoragePath);
mPrefStoragePath.setSummary(storageDescription);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -197,15 +198,30 @@ public void openFile(OCFile file) {
if (file != null) {
String storagePath = file.getStoragePath();

String[] officeExtensions = MainApp.getAppContext().getResources().getStringArray(R.array
.ms_office_extensions);

Uri fileUri;

if (file.getFileName().contains(".") &&
Arrays.asList(officeExtensions).contains(file.getFileName().substring(file.getFileName().
lastIndexOf(".") + 1, file.getFileName().length())) &&
!file.getStoragePath().startsWith(MainApp.getAppContext().getFilesDir().getAbsolutePath())) {
fileUri = file.getLegacyExposedFileUri(mFileActivity);
} else {
fileUri = file.getExposedFileUri(mFileActivity);
}

Intent openFileWithIntent = null;
int lastIndexOfDot = storagePath.lastIndexOf('.');
if (lastIndexOfDot >= 0) {
String fileExt = storagePath.substring(lastIndexOfDot + 1);
String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExt);
if (guessedMimeType != null) {
openFileWithIntent = new Intent(Intent.ACTION_VIEW);
openFileWithIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
openFileWithIntent.setDataAndType(
file.getExposedFileUri(mFileActivity),
fileUri,
guessedMimeType
);
}
Expand All @@ -218,7 +234,7 @@ public void openFile(OCFile file) {
if (openFileWithIntent == null) {
openFileWithIntent = new Intent(Intent.ACTION_VIEW);
openFileWithIntent.setDataAndType(
file.getExposedFileUri(mFileActivity),
fileUri,
file.getMimetype()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ public static boolean copyFile(File src, File target) {
return ret;
}

public static boolean moveFile(File sourceFile, File targetFile) throws IOException {
if (copyFile(sourceFile, targetFile)) {
return sourceFile.delete();
} else {
return false;
}
}

public static void deleteRecursively(File file, FileDataStorageManager storageManager) {
if (file.isDirectory()) {
for (File child : file.listFiles()) {
Expand Down
Loading