Skip to content

Commit 7b38627

Browse files
committed
Allow to create encrypted folder directly from bottom sheet dialog from NC PR: nextcloud#10782
1 parent 028c308 commit 7b38627

File tree

10 files changed

+128
-32
lines changed

10 files changed

+128
-32
lines changed

app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,11 @@ public void createFolder() {
357357

358358
}
359359

360+
@Override
361+
public void createEncryptedFolder() {
362+
363+
}
364+
360365
@Override
361366
public void uploadFromApp() {
362367

app/src/main/java/com/owncloud/android/files/FileMenuFilter.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ private void filterUnlock(List<Integer> toHide, boolean fileLockingEnabled) {
243243

244244
private void filterEncrypt(List<Integer> toHide, boolean endToEndEncryptionEnabled) {
245245
if (files.isEmpty() || !isSingleSelection() || isSingleFile() || isEncryptedFolder() || isGroupFolder()
246-
|| !endToEndEncryptionEnabled || !isEmptyFolder() || isShared()) {
246+
|| !endToEndEncryptionEnabled || !isEmptyFolder() || isShared() || isInSubFolder()) {
247247
toHide.add(R.id.action_encrypted);
248248
}
249249
}
@@ -566,4 +566,15 @@ private boolean isShared() {
566566
}
567567
return false;
568568
}
569+
570+
private boolean isInSubFolder() {
571+
OCFile folder = files.iterator().next();
572+
OCFile parent = storageManager.getFileById(folder.getParentId());
573+
574+
if (parent == null) {
575+
return false;
576+
}
577+
578+
return !OCFile.ROOT_PATH.equals(parent.getRemotePath());
579+
}
569580
}

app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,31 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper
6565
private RemoteFile createdRemoteFolder;
6666
private User user;
6767
private Context context;
68+
private boolean encrypted;
6869

6970
/**
7071
* Constructor
7172
*/
72-
public CreateFolderOperation(String remotePath, User user, Context context, FileDataStorageManager storageManager) {
73+
public CreateFolderOperation(String remotePath,
74+
User user,
75+
Context context,
76+
FileDataStorageManager storageManager
77+
) {
78+
this(remotePath, false, user, context, storageManager);
79+
}
80+
81+
public CreateFolderOperation(String remotePath,
82+
boolean encrypted,
83+
User user,
84+
Context context,
85+
FileDataStorageManager storageManager
86+
) {
7387
super(storageManager);
7488

7589
this.remotePath = remotePath;
7690
this.user = user;
7791
this.context = context;
92+
this.encrypted = encrypted;
7893
}
7994

8095
@Override
@@ -102,7 +117,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
102117
if (encryptedAncestor) {
103118
return encryptedCreate(parent, client);
104119
} else {
105-
return normalCreate(client);
120+
return normalCreate(client, encrypted);
106121
}
107122
}
108123

@@ -288,7 +303,7 @@ private String createRandomFileName(DecryptedFolderMetadata metadata) {
288303
return encryptedFileName;
289304
}
290305

291-
private RemoteOperationResult normalCreate(OwnCloudClient client) {
306+
private RemoteOperationResult normalCreate(OwnCloudClient client, boolean encrypted) {
292307
RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client);
293308

294309
if (result.isSuccess()) {
@@ -297,6 +312,21 @@ private RemoteOperationResult normalCreate(OwnCloudClient client) {
297312

298313
createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0);
299314
saveFolderInDB();
315+
316+
if (encrypted) {
317+
final OCFile folder = getStorageManager().getFileByDecryptedRemotePath(remotePath);
318+
319+
final RemoteOperationResult remoteOperationResult =
320+
new ToggleEncryptionRemoteOperation(folder.getLocalId(),
321+
remotePath,
322+
true)
323+
.execute(client);
324+
325+
if (remoteOperationResult.isSuccess()) {
326+
folder.setEncrypted(true);
327+
getStorageManager().saveFile(folder);
328+
}
329+
}
300330
} else {
301331
Log_OC.e(TAG, remotePath + " hasn't been created");
302332
}

app/src/main/java/com/owncloud/android/services/OperationsService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public class OperationsService extends Service {
9393
public static final String EXTRA_ACCOUNT = "ACCOUNT";
9494
public static final String EXTRA_SERVER_URL = "SERVER_URL";
9595
public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
96+
public static final String EXTRA_ENCRYPTED = "ENCRYPTED";
9697
public static final String EXTRA_NEWNAME = "NEWNAME";
9798
public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY";
9899
public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
@@ -685,7 +686,9 @@ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) {
685686

686687
case ACTION_CREATE_FOLDER:
687688
remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
689+
boolean encrypted = operationIntent.getBooleanExtra(EXTRA_ENCRYPTED, false);
688690
operation = new CreateFolderOperation(remotePath,
691+
encrypted,
689692
user,
690693
getApplicationContext(),
691694
fileDataStorageManager);

app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,10 @@ private String generateFooterText(int filesCount, int foldersCount) {
570570

571571
public @Nullable
572572
OCFile getItem(int position) {
573+
if (position == -1) {
574+
return null;
575+
}
576+
573577
int newPosition = position;
574578

575579
if (shouldShowHeader() && position > 0) {

app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
6262
@JvmField
6363
@Inject
6464
var keyboardUtils: KeyboardUtils? = null
65-
private var mParentFolder: OCFile? = null
65+
private var parentFolder: OCFile? = null
6666
private var positiveButton: MaterialButton? = null
67+
private var encrypted = false
6768

6869
private lateinit var binding: EditBoxDialogBinding
6970

@@ -92,7 +93,8 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
9293

9394
@Suppress("EmptyFunctionBlock")
9495
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
95-
mParentFolder = arguments?.getParcelable(ARG_PARENT_FOLDER)
96+
parentFolder = arguments?.getParcelable(ARG_PARENT_FOLDER)
97+
encrypted = arguments?.getBoolean(ARG_ENCRYPTED) ?: false
9698

9799
// Inflate the layout for the dialog
98100
val inflater = requireActivity().layoutInflater
@@ -176,26 +178,32 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
176178
DisplayUtils.showSnackMessage(requireActivity(), R.string.filename_forbidden_charaters_from_server)
177179
return
178180
}
179-
val path = mParentFolder!!.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
180-
(requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path)
181+
val path = parentFolder!!.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
182+
(requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path, encrypted)
181183
}
182184
}
183185

184186
companion object {
185187
private const val ARG_PARENT_FOLDER = "PARENT_FOLDER"
188+
private const val ARG_ENCRYPTED = "ENCRYPTED"
186189
const val CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT"
187190

191+
@JvmStatic
192+
fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment {
193+
return newInstance(parentFolder, false)
194+
}
188195
/**
189196
* Public factory method to create new CreateFolderDialogFragment instances.
190197
*
191198
* @param parentFolder Folder to create
192199
* @return Dialog ready to show.
193200
*/
194201
@JvmStatic
195-
fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment {
202+
fun newInstance(parentFolder: OCFile?, encrypted: Boolean): CreateFolderDialogFragment {
196203
val frag = CreateFolderDialogFragment()
197204
val args = Bundle()
198205
args.putParcelable(ARG_PARENT_FOLDER, parentFolder)
206+
args.putBoolean(ARG_ENCRYPTED, encrypted)
199207
frag.arguments = args
200208
return frag
201209
}

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetActions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public interface OCFileListBottomSheetActions {
3232
*/
3333
void createFolder();
3434

35+
/**
36+
* creates an encrypted folder within the actual folder
37+
*/
38+
void createEncryptedFolder();
39+
3540
/**
3641
* offers a file upload with the Android OS file picker to the current folder.
3742
*/

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,8 @@ protected void onCreate(Bundle savedInstanceState) {
9999
binding.addToCloud.setText(getContext().getResources().getString(R.string.add_to_cloud,
100100
themeUtils.getDefaultDisplayNameForRootFolder(getContext())));
101101

102-
OCCapability capability = fileActivity.getCapabilities();
103-
if (capability != null &&
104-
capability.getRichDocuments().isTrue() &&
102+
OCCapability capability = fileActivity.getStorageManager().getCapability(user.getAccountName());
103+
if (capability.getRichDocuments().isTrue() &&
105104
capability.getRichDocumentsDirectEditing().isTrue() &&
106105
capability.getRichDocumentsTemplatesAvailable().isTrue() &&
107106
!file.isEncrypted()) {
@@ -149,6 +148,12 @@ protected void onCreate(Bundle savedInstanceState) {
149148
binding.menuDirectCameraUpload.setVisibility(View.GONE);
150149
}
151150

151+
if (capability.getEndToEndEncryption().isTrue() && OCFile.ROOT_PATH.equals(file.getRemotePath())) {
152+
binding.menuEncryptedMkdir.setVisibility(View.VISIBLE);
153+
} else {
154+
binding.menuEncryptedMkdir.setVisibility(View.GONE);
155+
}
156+
152157
// create rich workspace
153158
if (editorUtils.isEditorAvailable(user,
154159
MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
@@ -183,6 +188,11 @@ private void setupClickListener() {
183188
dismiss();
184189
});
185190

191+
binding.menuEncryptedMkdir.setOnClickListener(v -> {
192+
actions.createEncryptedFolder();
193+
dismiss();
194+
});
195+
186196
binding.menuUploadFromApp.setOnClickListener(v -> {
187197
actions.uploadFromApp();
188198
dismiss();

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,14 @@ public void createFolder() {
511511
.show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
512512
}
513513

514+
@Override
515+
public void createEncryptedFolder() {
516+
if (checkEncryptionIsSetup(null)) {
517+
CreateFolderDialogFragment.newInstance(mFile, true)
518+
.show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
519+
}
520+
}
521+
514522
@Override
515523
public void uploadFromApp() {
516524
Intent action = new Intent(Intent.ACTION_GET_CONTENT);
@@ -1125,10 +1133,11 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
11251133
int position = data.getIntExtra(SetupEncryptionDialogFragment.ARG_POSITION, -1);
11261134
OCFile file = mAdapter.getItem(position);
11271135

1128-
if (file != null) {
1129-
mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true);
1130-
mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true);
1136+
if (file == null) {
1137+
return;
11311138
}
1139+
mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true);
1140+
mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true);
11321141

11331142
// update state and view of this fragment
11341143
searchFragment = false;
@@ -1685,45 +1694,51 @@ protected RemoteOperation getSearchRemoteOperation(final User currentUser, final
16851694

16861695
@Subscribe(threadMode = ThreadMode.BACKGROUND)
16871696
public void onMessageEvent(EncryptionEvent event) {
1697+
if (checkEncryptionIsSetup(event.remoteId)) {
1698+
encryptFolder(event.localId, event.remoteId, event.remotePath, event.shouldBeEncrypted);
1699+
}
1700+
}
1701+
1702+
private boolean checkEncryptionIsSetup(@Nullable String remoteId) {
16881703
final User user = accountManager.getUser();
16891704

16901705
// check if keys are stored
16911706
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
16921707
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);
16931708

1694-
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
1695-
OCFile file = storageManager.getFileByRemoteId(event.getRemoteId());
1696-
16971709
if (publicKey.isEmpty() || privateKey.isEmpty()) {
16981710
Log_OC.d(TAG, "no public key for " + user.getAccountName());
16991711

1712+
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
17001713
int position = -1;
1701-
if (file != null) {
1702-
position = mAdapter.getItemPosition(file);
1714+
if (remoteId != null) {
1715+
OCFile file = storageManager.getFileByRemoteId(remoteId);
1716+
if (file != null) {
1717+
position = mAdapter.getItemPosition(file);
1718+
}
17031719
}
17041720
SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position);
17051721
dialog.setTargetFragment(this, SETUP_ENCRYPTION_REQUEST_CODE);
17061722
dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG);
1723+
1724+
return false;
17071725
} else {
1708-
encryptFolder(file,
1709-
event.getLocalId(),
1710-
event.getRemoteId(),
1711-
event.getRemotePath(),
1712-
event.getShouldBeEncrypted(),
1713-
publicKey,
1714-
privateKey);
1726+
return true;
17151727
}
17161728
}
17171729

1718-
private void encryptFolder(OCFile folder,
1719-
long localId,
1730+
private void encryptFolder(long localId,
17201731
String remoteId,
17211732
String remotePath,
1722-
boolean shouldBeEncrypted,
1723-
String publicKey,
1724-
String privateKey) {
1733+
boolean shouldBeEncrypted) {
17251734
try {
17261735
User user = accountManager.getUser();
1736+
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
1737+
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);
1738+
1739+
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
1740+
OCFile folder = storageManager.getFileByRemoteId(remoteId);
1741+
17271742
OwnCloudClient client = clientFactory.create(user);
17281743
RemoteOperationResult remoteOperationResult = new ToggleEncryptionRemoteOperation(localId,
17291744
remotePath,

app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,11 +971,16 @@ public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy, boolean
971971

972972

973973
public void createFolder(String remotePath) {
974+
createFolder(remotePath, false);
975+
}
976+
977+
public void createFolder(String remotePath, boolean encrypted) {
974978
// Create Folder
975979
Intent service = new Intent(fileActivity, OperationsService.class);
976980
service.setAction(OperationsService.ACTION_CREATE_FOLDER);
977981
service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
978982
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
983+
service.putExtra(OperationsService.EXTRA_ENCRYPTED, encrypted);
979984
mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);
980985

981986
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));

0 commit comments

Comments
 (0)