diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index c2d6e3930ff0..2faf6944ba22 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -61,16 +61,31 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper private RemoteFile createdRemoteFolder; private User user; private Context context; + private boolean encrypted; /** * Constructor */ - public CreateFolderOperation(String remotePath, User user, Context context, FileDataStorageManager storageManager) { + public CreateFolderOperation(String remotePath, + User user, + Context context, + FileDataStorageManager storageManager + ) { + this(remotePath, false, user, context, storageManager); + } + + public CreateFolderOperation(String remotePath, + boolean encrypted, + User user, + Context context, + FileDataStorageManager storageManager + ) { super(storageManager); this.remotePath = remotePath; this.user = user; this.context = context; + this.encrypted = encrypted; } @Override @@ -106,7 +121,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } return new RemoteOperationResult(new IllegalStateException("E2E not supported")); } else { - return normalCreate(client); + return normalCreate(client, encrypted); } } @@ -490,7 +505,7 @@ private String createRandomFileName(DecryptedFolderMetadataFileV1 metadata) { return encryptedFileName; } - private RemoteOperationResult normalCreate(OwnCloudClient client) { + private RemoteOperationResult normalCreate(OwnCloudClient client, boolean encrypted) { RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client); if (result.isSuccess()) { @@ -499,6 +514,21 @@ private RemoteOperationResult normalCreate(OwnCloudClient client) { createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0); saveFolderInDB(); + + if (encrypted) { + final OCFile folder = getStorageManager().getFileByDecryptedRemotePath(remotePath); + + final RemoteOperationResult remoteOperationResult = + new ToggleEncryptionRemoteOperation(folder.getLocalId(), + remotePath, + true) + .execute(client); + + if (remoteOperationResult.isSuccess()) { + folder.setEncrypted(true); + getStorageManager().saveFile(folder); + } + } } else { Log_OC.e(TAG, remotePath + " hasn't been created"); } diff --git a/app/src/main/java/com/owncloud/android/services/OperationsService.java b/app/src/main/java/com/owncloud/android/services/OperationsService.java index 6923606819af..79ffdf92499b 100644 --- a/app/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/app/src/main/java/com/owncloud/android/services/OperationsService.java @@ -85,6 +85,7 @@ public class OperationsService extends Service { public static final String EXTRA_POST_DIALOG_EVENT = "EXTRA_POST_DIALOG_EVENT"; public static final String EXTRA_SERVER_URL = "SERVER_URL"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; + public static final String EXTRA_ENCRYPTED = "ENCRYPTED"; public static final String EXTRA_NEWNAME = "NEWNAME"; public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY"; public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS"; @@ -708,7 +709,9 @@ private Pair newOperation(Intent operationIntent) { case ACTION_CREATE_FOLDER: remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH); + boolean encrypted = operationIntent.getBooleanExtra(EXTRA_ENCRYPTED, false); operation = new CreateFolderOperation(remotePath, + encrypted, user, getApplicationContext(), fileDataStorageManager); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt index 106c22183bbf..9b209807c245 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt @@ -323,7 +323,7 @@ open class FolderPickerActivity : val itemId = item.itemId if (itemId == R.id.action_create_dir) { - val dialog = CreateFolderDialogFragment.newInstance(currentFolder) + val dialog = CreateFolderDialogFragment.newInstance(currentFolder, false) dialog.show(supportFragmentManager, CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT) } else if (itemId == android.R.id.home) { val currentDir = currentFolder diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 2e8a6a27cdbf..cb16a185d8b0 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -1099,7 +1099,7 @@ public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.action_create_dir) { - CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile); + CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile, false); dialog.show(getSupportFragmentManager(), CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT); } else if (itemId == android.R.id.home) { if (mParents.size() > SINGLE_PARENT) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt index f3078dce73cb..1f22e20962ef 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt @@ -35,6 +35,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.status.OCCapability +import com.owncloud.android.services.OperationsService.EXTRA_ENCRYPTED import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.utils.DisplayUtils @@ -69,6 +70,7 @@ class CreateFolderDialogFragment : lateinit var accountProvider: CurrentAccountProvider private var parentFolder: OCFile? = null + private var encrypted = false private var positiveButton: MaterialButton? = null private lateinit var binding: EditBoxDialogBinding @@ -104,6 +106,7 @@ class CreateFolderDialogFragment : @Suppress("EmptyFunctionBlock") override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { parentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) + encrypted = arguments?.getBoolean(EXTRA_ENCRYPTED, false) ?: false val inflater = requireActivity().layoutInflater binding = EditBoxDialogBinding.inflate(inflater, null, false) @@ -190,7 +193,7 @@ class CreateFolderDialogFragment : val path = parentFolder?.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR connectivityService.isNetworkAndServerAvailable { result -> if (result) { - typedActivity()?.fileOperationsHelper?.createFolder(path) + typedActivity()?.fileOperationsHelper?.createFolder(path, encrypted) } else { Log_OC.d(TAG, "Network not available, creating offline operation") fileDataStorageManager.addCreateFolderOfflineOperation( @@ -217,9 +220,10 @@ class CreateFolderDialogFragment : * @return Dialog ready to show. */ @JvmStatic - fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment { + fun newInstance(parentFolder: OCFile?, encrypted: Boolean): CreateFolderDialogFragment { val bundle = Bundle().apply { putParcelable(ARG_PARENT_FOLDER, parentFolder) + putBoolean(EXTRA_ENCRYPTED, encrypted) } return CreateFolderDialogFragment().apply { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java index c28f1e9837f9..801ceb628d08 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java @@ -9,8 +9,7 @@ import com.owncloud.android.lib.common.Creator; /** - * Actions interface to be implemented by any class that makes use of - * {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}. + * Actions interface to be implemented by any class that makes use of {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}. */ public interface OCFileListBottomSheetActions { /** @@ -18,6 +17,11 @@ public interface OCFileListBottomSheetActions { */ void createFolder(); + /** + * creates an encrypted folder within the actual folder + */ + void createEncryptedFolder(); + /** * offers a file upload with the Android OS file picker to the current folder. */ diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 981a234510b0..15af03ef336a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -513,10 +513,18 @@ public void registerFabListener() { @Override public void createFolder() { - CreateFolderDialogFragment.newInstance(mFile) + CreateFolderDialogFragment.newInstance(mFile, false) .show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER); } + @Override + public void createEncryptedFolder() { + if (checkEncryptionIsSetup(null)) { + CreateFolderDialogFragment.newInstance(mFile, true) + .show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER); + } + } + @Override public void uploadFromApp() { Intent action = new Intent(Intent.ACTION_GET_CONTENT); @@ -1259,10 +1267,17 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { int position = data.getIntExtra(SetupEncryptionDialogFragment.ARG_POSITION, -1); OCFile file = mAdapter.getItem(position); + // TODO needed? if (file != null) { mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true); mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true); + } + + if (file == null) { + return; } + + encryptFolder(file.getLocalId(), file.getRemoteId(), file.getRemotePath(), true); // update state and view of this fragment searchFragment = false; @@ -1883,56 +1898,62 @@ protected RemoteOperation getSearchRemoteOperation(final User currentUser, final @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(EncryptionEvent event) { - new Thread(() -> {{ - final User user = accountManager.getUser(); + if (checkEncryptionIsSetup(event.getRemoteId())) { + encryptFolder(event.getLocalId(), + event.getRemoteId(), + event.getRemotePath(), + event.getShouldBeEncrypted()); + } + } - // check if keys are stored - String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY); - String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY); + private boolean checkEncryptionIsSetup(@Nullable String remoteId) { + final User user = accountManager.getUser(); - FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); - OCFile file = storageManager.getFileByRemoteId(event.getRemoteId()); + // check if keys are stored + String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY); + String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY); - if (publicKey.isEmpty() || privateKey.isEmpty()) { - Log_OC.d(TAG, "no public key for " + user.getAccountName()); + FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); + + if (publicKey.isEmpty() || privateKey.isEmpty()) { + Log_OC.d(TAG, "no public key for " + user.getAccountName()); - int position; + int position; + if (remoteId != null) { + OCFile file = storageManager.getFileByRemoteId(remoteId); if (file != null) { position = mAdapter.getItemPosition(file); } else { position = -1; } - - requireActivity().runOnUiThread(() -> { - SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position); - dialog.setTargetFragment(OCFileListFragment.this, SETUP_ENCRYPTION_REQUEST_CODE); - dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG); - }); } else { - // TODO E2E: if encryption fails, to not set it as encrypted! - encryptFolder(file, - event.getLocalId(), - event.getRemoteId(), - event.getRemotePath(), - event.getShouldBeEncrypted(), - publicKey, - privateKey, - storageManager); + position = -1; } - }}).start(); + + requireActivity().runOnUiThread(() -> { + SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position); + dialog.setTargetFragment(OCFileListFragment.this, SETUP_ENCRYPTION_REQUEST_CODE); + dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG); + }); + return false; + } else { + return true; + } } - private void encryptFolder(OCFile folder, - long localId, + private void encryptFolder(long localId, String remoteId, String remotePath, - boolean shouldBeEncrypted, - String publicKeyString, - String privateKeyString, - FileDataStorageManager storageManager) { + boolean shouldBeEncrypted) { try { + final User user = accountManager.getUser(); + String publicKeyString = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY); + String privateKeyString = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY); + + FileDataStorageManager storageManager = mContainerActivity.getStorageManager(); + OCFile folder = storageManager.getFileByRemoteId(remoteId); + Log_OC.d(TAG, "encrypt folder " + folder.getRemoteId()); - User user = accountManager.getUser(); OwnCloudClient client = clientFactory.create(user); RemoteOperationResult remoteOperationResult = new ToggleEncryptionRemoteOperation(localId, remotePath, diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index b071a92a9eff..0bb024f305e4 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -970,6 +970,10 @@ public void removeFiles(Collection files, boolean onlyLocalCopy, boolean for (OCFile file : files) { removeFile(file, onlyLocalCopy, inBackground); } + + if (!inBackground) { + fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment)); + } } public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground) { @@ -983,11 +987,16 @@ public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground) } public void createFolder(String remotePath) { + createFolder(remotePath, false); + } + + public void createFolder(String remotePath, boolean encrypted) { // Create Folder Intent service = new Intent(fileActivity, OperationsService.class); service.setAction(OperationsService.ACTION_CREATE_FOLDER); service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount()); service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath); + service.putExtra(OperationsService.EXTRA_ENCRYPTED, encrypted); mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service); fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment)); diff --git a/app/src/main/res/drawable/ic_action_create_dir.xml b/app/src/main/res/drawable/ic_action_create_dir.xml index 09a6106a3308..c08565cb8d8a 100644 --- a/app/src/main/res/drawable/ic_action_create_dir.xml +++ b/app/src/main/res/drawable/ic_action_create_dir.xml @@ -13,4 +13,6 @@ + + diff --git a/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml b/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml new file mode 100644 index 000000000000..f773d9553771 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_create_encrypted_dir.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml index 5fb7cfc03894..cd6da296005a 100644 --- a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml +++ b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml @@ -202,6 +202,37 @@ + + + + + + + Failed to create conflict dialog Cannot open file chooser + Create new encrypted folder