Просмотр исходного кода

Merge pull request #11031 from nextcloud/e2eUX

E2e ux
Tobias Kaminsky 2 лет назад
Родитель
Сommit
161bc98bde

+ 1124 - 0
app/schemas/com.nextcloud.client.database.NextcloudDatabase/66.json

@@ -0,0 +1,1124 @@
+{
+    "formatVersion": 1,
+    "database": {
+        "version": 66,
+        "identityHash": "97be4a2bf1d8d2a4db027a996a823010",
+        "entities": [
+            {
+                "tableName": "arbitrary_data",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "cloudId",
+                        "columnName": "cloud_id",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "key",
+                        "columnName": "key",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "value",
+                        "columnName": "value",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "capabilities",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "accountName",
+                        "columnName": "account",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "versionMajor",
+                        "columnName": "version_mayor",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "versionMinor",
+                        "columnName": "version_minor",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "versionMicro",
+                        "columnName": "version_micro",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "versionString",
+                        "columnName": "version_string",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "versionEditor",
+                        "columnName": "version_edition",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "extendedSupport",
+                        "columnName": "extended_support",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "corePollinterval",
+                        "columnName": "core_pollinterval",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingApiEnabled",
+                        "columnName": "sharing_api_enabled",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicEnabled",
+                        "columnName": "sharing_public_enabled",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicPasswordEnforced",
+                        "columnName": "sharing_public_password_enforced",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicExpireDateEnabled",
+                        "columnName": "sharing_public_expire_date_enabled",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicExpireDateDays",
+                        "columnName": "sharing_public_expire_date_days",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicExpireDateEnforced",
+                        "columnName": "sharing_public_expire_date_enforced",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicSendMail",
+                        "columnName": "sharing_public_send_mail",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicUpload",
+                        "columnName": "sharing_public_upload",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingUserSendMail",
+                        "columnName": "sharing_user_send_mail",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingResharing",
+                        "columnName": "sharing_resharing",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingFederationOutgoing",
+                        "columnName": "sharing_federation_outgoing",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingFederationIncoming",
+                        "columnName": "sharing_federation_incoming",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "filesBigfilechunking",
+                        "columnName": "files_bigfilechunking",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "filesUndelete",
+                        "columnName": "files_undelete",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "filesVersioning",
+                        "columnName": "files_versioning",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "externalLinks",
+                        "columnName": "external_links",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverName",
+                        "columnName": "server_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverColor",
+                        "columnName": "server_color",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverTextColor",
+                        "columnName": "server_text_color",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverElementColor",
+                        "columnName": "server_element_color",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverSlogan",
+                        "columnName": "server_slogan",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverLogo",
+                        "columnName": "server_logo",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverBackgroundUrl",
+                        "columnName": "background_url",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "endToEndEncryption",
+                        "columnName": "end_to_end_encryption",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "endToEndEncryptionKeysExist",
+                        "columnName": "end_to_end_encryption_keys_exist",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "activity",
+                        "columnName": "activity",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverBackgroundDefault",
+                        "columnName": "background_default",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "serverBackgroundPlain",
+                        "columnName": "background_plain",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocument",
+                        "columnName": "richdocument",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocumentMimetypeList",
+                        "columnName": "richdocument_mimetype_list",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocumentDirectEditing",
+                        "columnName": "richdocument_direct_editing",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocumentTemplates",
+                        "columnName": "richdocument_direct_templates",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocumentOptionalMimetypeList",
+                        "columnName": "richdocument_optional_mimetype_list",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharingPublicAskForOptionalPassword",
+                        "columnName": "sharing_public_ask_for_optional_password",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richdocumentProductName",
+                        "columnName": "richdocument_product_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "directEditingEtag",
+                        "columnName": "direct_editing_etag",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "userStatus",
+                        "columnName": "user_status",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "userStatusSupportsEmoji",
+                        "columnName": "user_status_supports_emoji",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "etag",
+                        "columnName": "etag",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "filesLockingVersion",
+                        "columnName": "files_locking_version",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "external_links",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `icon_url` TEXT, `language` TEXT, `type` INTEGER, `name` TEXT, `url` TEXT, `redirect` INTEGER)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "iconUrl",
+                        "columnName": "icon_url",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "language",
+                        "columnName": "language",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "type",
+                        "columnName": "type",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "name",
+                        "columnName": "name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "url",
+                        "columnName": "url",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "redirect",
+                        "columnName": "redirect",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "filelist",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `filename` TEXT, `encrypted_filename` TEXT, `path` TEXT, `path_decrypted` TEXT, `parent` INTEGER, `created` INTEGER, `modified` INTEGER, `content_type` TEXT, `content_length` INTEGER, `media_path` TEXT, `file_owner` TEXT, `last_sync_date` INTEGER, `last_sync_date_for_data` INTEGER, `modified_at_last_sync_for_data` INTEGER, `etag` TEXT, `etag_on_server` TEXT, `share_by_link` INTEGER, `permissions` TEXT, `remote_id` TEXT, `update_thumbnail` INTEGER, `is_downloading` INTEGER, `favorite` INTEGER, `is_encrypted` INTEGER, `etag_in_conflict` TEXT, `shared_via_users` INTEGER, `mount_type` INTEGER, `has_preview` INTEGER, `unread_comments_count` INTEGER, `owner_id` TEXT, `owner_display_name` TEXT, `note` TEXT, `sharees` TEXT, `rich_workspace` TEXT, `metadata_size` TEXT, `locked` INTEGER, `lock_type` INTEGER, `lock_owner` TEXT, `lock_owner_display_name` TEXT, `lock_owner_editor` TEXT, `lock_timestamp` INTEGER, `lock_timeout` INTEGER, `lock_token` TEXT)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "name",
+                        "columnName": "filename",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "encryptedName",
+                        "columnName": "encrypted_filename",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "path",
+                        "columnName": "path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "pathDecrypted",
+                        "columnName": "path_decrypted",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "parent",
+                        "columnName": "parent",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "creation",
+                        "columnName": "created",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "modified",
+                        "columnName": "modified",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "contentType",
+                        "columnName": "content_type",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "contentLength",
+                        "columnName": "content_length",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "storagePath",
+                        "columnName": "media_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "accountOwner",
+                        "columnName": "file_owner",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lastSyncDate",
+                        "columnName": "last_sync_date",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lastSyncDateForData",
+                        "columnName": "last_sync_date_for_data",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "modifiedAtLastSyncForData",
+                        "columnName": "modified_at_last_sync_for_data",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "etag",
+                        "columnName": "etag",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "etagOnServer",
+                        "columnName": "etag_on_server",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharedViaLink",
+                        "columnName": "share_by_link",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "permissions",
+                        "columnName": "permissions",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "remoteId",
+                        "columnName": "remote_id",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "updateThumbnail",
+                        "columnName": "update_thumbnail",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isDownloading",
+                        "columnName": "is_downloading",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "favorite",
+                        "columnName": "favorite",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isEncrypted",
+                        "columnName": "is_encrypted",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "etagInConflict",
+                        "columnName": "etag_in_conflict",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharedWithSharee",
+                        "columnName": "shared_via_users",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "mountType",
+                        "columnName": "mount_type",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "hasPreview",
+                        "columnName": "has_preview",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "unreadCommentsCount",
+                        "columnName": "unread_comments_count",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "ownerId",
+                        "columnName": "owner_id",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "ownerDisplayName",
+                        "columnName": "owner_display_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "note",
+                        "columnName": "note",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharees",
+                        "columnName": "sharees",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "richWorkspace",
+                        "columnName": "rich_workspace",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "metadataSize",
+                        "columnName": "metadata_size",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "locked",
+                        "columnName": "locked",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockType",
+                        "columnName": "lock_type",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockOwner",
+                        "columnName": "lock_owner",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockOwnerDisplayName",
+                        "columnName": "lock_owner_display_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockOwnerEditor",
+                        "columnName": "lock_owner_editor",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockTimestamp",
+                        "columnName": "lock_timestamp",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockTimeout",
+                        "columnName": "lock_timeout",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lockToken",
+                        "columnName": "lock_token",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "filesystem",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `is_folder` INTEGER, `found_at` INTEGER, `upload_triggered` INTEGER, `syncedfolder_id` TEXT, `crc32` TEXT, `modified_at` INTEGER)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "localPath",
+                        "columnName": "local_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileIsFolder",
+                        "columnName": "is_folder",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileFoundRecently",
+                        "columnName": "found_at",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileSentForUpload",
+                        "columnName": "upload_triggered",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "syncedFolderId",
+                        "columnName": "syncedfolder_id",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "crc32",
+                        "columnName": "crc32",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileModified",
+                        "columnName": "modified_at",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "ocshares",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` INTEGER, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileSource",
+                        "columnName": "file_source",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "itemSource",
+                        "columnName": "item_source",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "shareType",
+                        "columnName": "share_type",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "shareWith",
+                        "columnName": "shate_with",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "path",
+                        "columnName": "path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "permissions",
+                        "columnName": "permissions",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "sharedDate",
+                        "columnName": "shared_date",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "expirationDate",
+                        "columnName": "expiration_date",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "token",
+                        "columnName": "token",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "shareWithDisplayName",
+                        "columnName": "shared_with_display_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isDirectory",
+                        "columnName": "is_directory",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "userId",
+                        "columnName": "user_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "idRemoteShared",
+                        "columnName": "id_remote_shared",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "accountOwner",
+                        "columnName": "owner_share",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isPasswordProtected",
+                        "columnName": "is_password_protected",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "note",
+                        "columnName": "note",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "hideDownload",
+                        "columnName": "hide_download",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "shareLink",
+                        "columnName": "share_link",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "shareLabel",
+                        "columnName": "share_label",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "synced_folders",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `wifi_only` INTEGER, `charging_only` INTEGER, `existing` INTEGER, `enabled` INTEGER, `enabled_timestamp_ms` INTEGER, `subfolder_by_date` INTEGER, `account` TEXT, `upload_option` INTEGER, `name_collision_policy` INTEGER, `type` INTEGER, `hidden` INTEGER)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "localPath",
+                        "columnName": "local_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "remotePath",
+                        "columnName": "remote_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "wifiOnly",
+                        "columnName": "wifi_only",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "chargingOnly",
+                        "columnName": "charging_only",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "existing",
+                        "columnName": "existing",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "enabled",
+                        "columnName": "enabled",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "enabledTimestampMs",
+                        "columnName": "enabled_timestamp_ms",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "subfolderByDate",
+                        "columnName": "subfolder_by_date",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "account",
+                        "columnName": "account",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "uploadAction",
+                        "columnName": "upload_option",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "nameCollisionPolicy",
+                        "columnName": "name_collision_policy",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "type",
+                        "columnName": "type",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "hidden",
+                        "columnName": "hidden",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "list_of_uploads",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `account_name` TEXT, `file_size` INTEGER, `status` INTEGER, `local_behaviour` INTEGER, `upload_time` INTEGER, `name_collision_policy` INTEGER, `is_create_remote_folder` INTEGER, `upload_end_timestamp` INTEGER, `last_result` INTEGER, `is_while_charging_only` INTEGER, `is_wifi_only` INTEGER, `created_by` INTEGER, `folder_unlock_token` TEXT)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "localPath",
+                        "columnName": "local_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "remotePath",
+                        "columnName": "remote_path",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "accountName",
+                        "columnName": "account_name",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "fileSize",
+                        "columnName": "file_size",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "status",
+                        "columnName": "status",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "localBehaviour",
+                        "columnName": "local_behaviour",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "uploadTime",
+                        "columnName": "upload_time",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "nameCollisionPolicy",
+                        "columnName": "name_collision_policy",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isCreateRemoteFolder",
+                        "columnName": "is_create_remote_folder",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "uploadEndTimestamp",
+                        "columnName": "upload_end_timestamp",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "lastResult",
+                        "columnName": "last_result",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isWhileChargingOnly",
+                        "columnName": "is_while_charging_only",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "isWifiOnly",
+                        "columnName": "is_wifi_only",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "createdBy",
+                        "columnName": "created_by",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "folderUnlockToken",
+                        "columnName": "folder_unlock_token",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            },
+            {
+                "tableName": "virtual",
+                "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `ocfile_id` INTEGER)",
+                "fields": [
+                    {
+                        "fieldPath": "id",
+                        "columnName": "_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "type",
+                        "columnName": "type",
+                        "affinity": "TEXT",
+                        "notNull": false
+                    },
+                    {
+                        "fieldPath": "ocFileId",
+                        "columnName": "ocfile_id",
+                        "affinity": "INTEGER",
+                        "notNull": false
+                    }
+                ],
+                "primaryKey": {
+                    "columnNames": [
+                        "_id"
+                    ],
+                    "autoGenerate": true
+                },
+                "indices": [],
+                "foreignKeys": []
+            }
+        ],
+        "views": [],
+        "setupQueries": [
+            "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+            "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '97be4a2bf1d8d2a4db027a996a823010')"
+        ]
+    }
+}

BIN
app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_open.png


BIN
app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_showMnemonic_Error.png


+ 4 - 0
app/src/main/AndroidManifest.xml

@@ -194,6 +194,10 @@
             android:name=".ui.activity.TextEditorWebView"
             android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
             android:exported="false" />
+        <activity
+            android:name=".ui.activity.SetupEncryptionActivity"
+            android:theme="@style/Theme.NoBackground"
+            android:exported="false" />
         <activity
             android:name=".ui.activity.ContactsPreferenceActivity"
             android:exported="false"

+ 4 - 0
app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt

@@ -23,6 +23,7 @@
 package com.nextcloud.client.database
 
 import android.content.Context
+import androidx.room.AutoMigration
 import androidx.room.Database
 import androidx.room.Room
 import androidx.room.RoomDatabase
@@ -55,6 +56,9 @@ import com.owncloud.android.db.ProviderMeta
         VirtualEntity::class
     ],
     version = ProviderMeta.DB_VERSION,
+    autoMigrations = [
+        AutoMigration(from = 65, to = 66)
+    ],
     exportSchema = true
 )
 @Suppress("Detekt.UnnecessaryAbstractClass") // needed by Room

+ 2 - 0
app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt

@@ -96,6 +96,8 @@ data class CapabilityEntity(
     val serverBackgroundUrl: String?,
     @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION)
     val endToEndEncryption: Int?,
+    @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST)
+    val endToEndEncryptionKeysExist: Int?,
     @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_ACTIVITY)
     val activity: Int?,
     @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT)

+ 1 - 3
app/src/main/java/com/nextcloud/client/jobs/AccountRemovalWork.kt

@@ -114,9 +114,7 @@ class AccountRemovalWork(
         uploadsStorageManager.removeUserUploads(user)
 
         // delete stored E2E keys and mnemonic
-        arbitraryDataProvider.deleteKeyForAccount(user.accountName, EncryptionUtils.PRIVATE_KEY)
-        arbitraryDataProvider.deleteKeyForAccount(user.accountName, EncryptionUtils.PUBLIC_KEY)
-        arbitraryDataProvider.deleteKeyForAccount(user.accountName, EncryptionUtils.MNEMONIC)
+        EncryptionUtils.removeE2E(arbitraryDataProvider, user)
 
         // unset default account, if needed
         if (preferences.currentAccountName.equals(user.accountName)) {

+ 6 - 0
app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -1971,6 +1971,8 @@ public class FileDataStorageManager {
                           capability.getServerLogo());
         contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION,
                           capability.getEndToEndEncryption().getValue());
+        contentValues.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST,
+                          capability.getEndToEndEncryptionKeysExist().getValue());
         contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT,
                           capability.getServerBackgroundDefault().getValue());
         contentValues.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_PLAIN,
@@ -2117,6 +2119,10 @@ public class FileDataStorageManager {
             capability.setServerSlogan(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN));
             capability.setServerLogo(getString(cursor, ProviderTableMeta.CAPABILITIES_SERVER_LOGO));
             capability.setEndToEndEncryption(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION));
+            capability.setEndToEndEncryptionKeysExist(
+                getBoolean(cursor,
+                           ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST)
+                                                     );
             capability.setServerBackgroundDefault(
                 getBoolean(cursor, ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT));
             capability.setServerBackgroundPlain(getBoolean(cursor,

+ 2 - 1
app/src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -35,7 +35,7 @@ import java.util.List;
  */
 public class ProviderMeta {
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 65;
+    public static final int DB_VERSION = 66;
 
     private ProviderMeta() {
         // No instance
@@ -237,6 +237,7 @@ public class ProviderMeta {
         public static final String CAPABILITIES_SERVER_BACKGROUND_DEFAULT = "background_default";
         public static final String CAPABILITIES_SERVER_BACKGROUND_PLAIN = "background_plain";
         public static final String CAPABILITIES_END_TO_END_ENCRYPTION = "end_to_end_encryption";
+        public static final String CAPABILITIES_END_TO_END_ENCRYPTION_KEYS_EXIST = "end_to_end_encryption_keys_exist";
         public static final String CAPABILITIES_ACTIVITY = "activity";
         public static final String CAPABILITIES_RICHDOCUMENT = "richdocument";
         public static final String CAPABILITIES_RICHDOCUMENT_MIMETYPE_LIST = "richdocument_mimetype_list";

+ 96 - 1
app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java

@@ -72,10 +72,14 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.providers.DocumentsStorageProvider;
 import com.owncloud.android.ui.ThemeableSwitchPreference;
 import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask;
+import com.owncloud.android.ui.dialog.SetupEncryptionDialogFragment;
+import com.owncloud.android.ui.helpers.FileOperationsHelper;
+import com.owncloud.android.utils.ClipboardUtil;
 import com.owncloud.android.utils.DeviceCredentialUtils;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.EncryptionUtils;
 import com.owncloud.android.utils.MimeTypeUtil;
+import com.owncloud.android.utils.theme.CapabilityUtils;
 import com.owncloud.android.utils.theme.ViewThemeUtils;
 
 import java.util.ArrayList;
@@ -98,7 +102,8 @@ import androidx.core.content.res.ResourcesCompat;
  * It proxies the necessary calls via {@link androidx.appcompat.app.AppCompatDelegate} to be used with AppCompat.
  */
 public class SettingsActivity extends PreferenceActivity
-    implements StorageMigration.StorageMigrationProgressListener, LoadingVersionNumberTask.VersionDevInterface,
+    implements StorageMigration.StorageMigrationProgressListener,
+    LoadingVersionNumberTask.VersionDevInterface,
     Injectable {
 
     private static final String TAG = SettingsActivity.class.getSimpleName();
@@ -118,6 +123,7 @@ public class SettingsActivity extends PreferenceActivity
     private static final int ACTION_CONFIRM_DEVICE_CREDENTIALS = 7;
     private static final int ACTION_REQUEST_CODE_DAVDROID_SETUP = 10;
     private static final int ACTION_SHOW_MNEMONIC = 11;
+    private static final int ACTION_E2E = 12;
     private static final int TRUE_VALUE = 1;
 
     private static final String DAV_PATH = "/remote.php/dav";
@@ -323,8 +329,14 @@ public class SettingsActivity extends PreferenceActivity
 
         setupBackupPreference();
 
+        setupE2EPreference(preferenceCategoryMore);
+
+        setupE2EKeysExist(preferenceCategoryMore);
+
         setupE2EMnemonicPreference(preferenceCategoryMore);
 
+        removeE2E(preferenceCategoryMore);
+
         setupHelpPreference(preferenceCategoryMore);
 
         setupRecommendPreference(preferenceCategoryMore);
@@ -411,6 +423,47 @@ public class SettingsActivity extends PreferenceActivity
         }
     }
 
+    private void setupE2EPreference(PreferenceCategory preferenceCategoryMore) {
+        Preference preference = findPreference("setup_e2e");
+
+        if (preference != null) {
+            if (FileOperationsHelper.isEndToEndEncryptionSetup(this, user) ||
+                CapabilityUtils.getCapability(this).getEndToEndEncryptionKeysExist().isTrue()) {
+                preferenceCategoryMore.removePreference(preference);
+            } else {
+                preference.setOnPreferenceClickListener(p -> {
+                    Intent i = new Intent(MainApp.getAppContext(), SetupEncryptionActivity.class);
+                    i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+                    i.putExtra("EXTRA_USER", user);
+                    startActivityForResult(i, ACTION_E2E);
+
+                    return true;
+                });
+            }
+        }
+    }
+
+    private void setupE2EKeysExist(PreferenceCategory preferenceCategoryMore) {
+        Preference preference = findPreference("setup_e2e_keys_exist");
+
+        if (preference != null) {
+            if (!CapabilityUtils.getCapability(this).getEndToEndEncryptionKeysExist().isTrue() ||
+                (CapabilityUtils.getCapability(this).getEndToEndEncryptionKeysExist().isTrue() &&
+                    FileOperationsHelper.isEndToEndEncryptionSetup(this, user))) {
+                preferenceCategoryMore.removePreference(preference);
+            } else {
+                preference.setOnPreferenceClickListener(p -> {
+                    Intent i = new Intent(MainApp.getAppContext(), SetupEncryptionActivity.class);
+                    i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+                    i.putExtra("EXTRA_USER", user);
+                    startActivityForResult(i, ACTION_E2E);
+
+                    return true;
+                });
+            }
+        }
+    }
+
     private void setupE2EMnemonicPreference(PreferenceCategory preferenceCategoryMore) {
         String mnemonic = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.MNEMONIC);
 
@@ -436,6 +489,40 @@ public class SettingsActivity extends PreferenceActivity
         }
     }
 
+    private void removeE2E(PreferenceCategory preferenceCategoryMore) {
+        Preference preference = findPreference("remove_e2e");
+
+        if (preference != null) {
+            if (!FileOperationsHelper.isEndToEndEncryptionSetup(this, user)) {
+                preferenceCategoryMore.removePreference(preference);
+            } else {
+                preference.setOnPreferenceClickListener(p -> {
+                    AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.FallbackTheming_Dialog);
+                    AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic)
+                        .setMessage(getString(R.string.remove_e2e_message))
+                        .setCancelable(true)
+                        .setNegativeButton(R.string.common_cancel, ((dialog, i) -> dialog.dismiss()))
+                        .setPositiveButton(R.string.confirm_removal, (dialog, which) -> {
+                            EncryptionUtils.removeE2E(arbitraryDataProvider, user);
+                            preferenceCategoryMore.removePreference(preference);
+
+                            Preference pMnemonic = findPreference("mnemonic");
+                            if (pMnemonic != null) {
+                                preferenceCategoryMore.removePreference(pMnemonic);
+                            }
+
+                            dialog.dismiss();
+                        })
+                        .create();
+
+                    alertDialog.show();
+
+                    return true;
+                });
+            }
+        }
+    }
+
     private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) {
         boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled);
         Preference pHelp = findPreference("help");
@@ -861,6 +948,11 @@ public class SettingsActivity extends PreferenceActivity
             }
         } else if (requestCode == ACTION_SHOW_MNEMONIC && resultCode == RESULT_OK) {
             handleMnemonicRequest(data);
+        } else if (requestCode == ACTION_E2E && data != null && data.getBooleanExtra(SetupEncryptionDialogFragment.SUCCESS, false)) {
+            Intent i = new Intent(this, SettingsActivity.class);
+            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
+            startActivity(i);
         }
     }
 
@@ -879,6 +971,9 @@ public class SettingsActivity extends PreferenceActivity
                 AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.FallbackTheming_Dialog);
                 AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic)
                     .setMessage(mnemonic)
+                    .setNegativeButton(R.string.common_cancel, (dialog, i) -> dialog.dismiss())
+                    .setNeutralButton(R.string.common_copy, (dialog, i) ->
+                        ClipboardUtil.copyToClipboard(this, mnemonic, false))
                     .setPositiveButton(R.string.common_ok, (dialog, which) -> dialog.dismiss())
                     .create();
 

+ 74 - 0
app/src/main/java/com/owncloud/android/ui/activity/SetupEncryptionActivity.kt

@@ -0,0 +1,74 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2022 Tobias Kaminsky
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.ui.activity
+
+import android.content.Intent
+import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.nextcloud.client.account.User
+import com.owncloud.android.R
+import com.owncloud.android.ui.dialog.SetupEncryptionDialogFragment
+
+class SetupEncryptionActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        val user = intent?.getParcelableExtra("EXTRA_USER") as User?
+
+        if (user == null) {
+            Toast.makeText(this, getString(R.string.error_showing_encryption_dialog), Toast.LENGTH_LONG).show()
+            finish()
+        }
+
+        val setupEncryptionDialogFragment = SetupEncryptionDialogFragment.newInstance(user, -1)
+        supportFragmentManager.setFragmentResultListener(
+            SetupEncryptionDialogFragment.RESULT_REQUEST_KEY,
+            this
+        ) { requestKey, result ->
+            if (requestKey == SetupEncryptionDialogFragment.RESULT_REQUEST_KEY) {
+                if (!result.getBoolean(SetupEncryptionDialogFragment.RESULT_KEY_CANCELLED, false)) {
+                    setResult(
+                        SetupEncryptionDialogFragment.SETUP_ENCRYPTION_RESULT_CODE,
+                        buildResultIntentFromBundle(result)
+                    )
+                }
+            }
+            finish()
+        }
+        setupEncryptionDialogFragment.show(supportFragmentManager, "setup_encryption")
+    }
+
+    private fun buildResultIntentFromBundle(result: Bundle): Intent {
+        val intent = Intent()
+        intent.putExtra(
+            SetupEncryptionDialogFragment.SUCCESS,
+            result.getBoolean(SetupEncryptionDialogFragment.SUCCESS)
+        )
+        intent.putExtra(
+            SetupEncryptionDialogFragment.ARG_POSITION,
+            result.getInt(SetupEncryptionDialogFragment.ARG_POSITION)
+        )
+        return intent
+    }
+}

+ 100 - 81
app/src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java

@@ -62,6 +62,7 @@ import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AlertDialog;
 import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
 
 import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes;
 import static com.owncloud.android.utils.EncryptionUtils.decryptStringAsymmetric;
@@ -79,6 +80,9 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj
     public static final String SETUP_ENCRYPTION_DIALOG_TAG = "SETUP_ENCRYPTION_DIALOG_TAG";
     public static final String ARG_POSITION = "ARG_POSITION";
 
+    public static final String RESULT_REQUEST_KEY = "RESULT_REQUEST";
+    public static final String RESULT_KEY_CANCELLED = "IS_CANCELLED";
+
     private static final String ARG_USER = "ARG_USER";
     private static final String TAG = SetupEncryptionDialogFragment.class.getSimpleName();
 
@@ -149,7 +153,9 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj
     private Dialog createDialog(View v) {
         MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(v.getContext());
         builder.setView(v).setPositiveButton(R.string.common_ok, null)
-            .setNeutralButton(R.string.common_cancel, null)
+            .setNeutralButton(R.string.common_cancel, (dialog, which) -> {
+                dialog.cancel();
+            })
             .setTitle(R.string.end_to_end_encryption_title);
 
         viewThemeUtils.dialog.colorMaterialAlertDialogBackground(v.getContext(), builder);
@@ -157,103 +163,121 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj
         Dialog dialog = builder.create();
         dialog.setCanceledOnTouchOutside(false);
 
-        dialog.setOnShowListener(new DialogInterface.OnShowListener() {
-
-            @Override
-            public void onShow(final DialogInterface dialog) {
-
-                Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
-                button.setOnClickListener(new View.OnClickListener() {
+        dialog.setOnShowListener(dialog1 -> {
 
-                    @Override
-                    public void onClick(View view) {
-                        switch (keyResult) {
-                            case KEY_CREATED:
-                                Log_OC.d(TAG, "New keys generated and stored.");
+            Button button = ((AlertDialog) dialog1).getButton(AlertDialog.BUTTON_POSITIVE);
+            button.setOnClickListener(view -> {
+                switch (keyResult) {
+                    case KEY_CREATED:
+                        Log_OC.d(TAG, "New keys generated and stored.");
 
-                                dialog.dismiss();
+                        dialog1.dismiss();
 
-                                Intent intentCreated = new Intent();
-                                intentCreated.putExtra(SUCCESS, true);
-                                intentCreated.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
-                                getTargetFragment().onActivityResult(getTargetRequestCode(),
-                                                                     SETUP_ENCRYPTION_RESULT_CODE, intentCreated);
-                                break;
+                        notifyResult();
+                        break;
 
-                            case KEY_EXISTING_USED:
-                                Log_OC.d(TAG, "Decrypt private key");
+                    case KEY_EXISTING_USED:
+                        Log_OC.d(TAG, "Decrypt private key");
 
-                                binding.encryptionStatus.setText(R.string.end_to_end_encryption_decrypting);
+                        binding.encryptionStatus.setText(R.string.end_to_end_encryption_decrypting);
 
-                                try {
-                                    String privateKey = task.get();
-                                    String mnemonicUnchanged = binding.encryptionPasswordInput.getText().toString();
-                                    String mnemonic = binding.encryptionPasswordInput.getText().toString().replaceAll("\\s", "")
-                                        .toLowerCase(Locale.ROOT);
-                                    String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey,
-                                                                                                   mnemonic);
+                        try {
+                            String privateKey = task.get();
+                            String mnemonicUnchanged = binding.encryptionPasswordInput.getText().toString();
+                            String mnemonic = binding.encryptionPasswordInput.getText().toString().replaceAll("\\s", "")
+                                .toLowerCase(Locale.ROOT);
+                            String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey,
+                                                                                           mnemonic);
 
-                                    arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
-                                                                                EncryptionUtils.PRIVATE_KEY, decryptedPrivateKey);
+                            arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
+                                                                        EncryptionUtils.PRIVATE_KEY, decryptedPrivateKey);
 
-                                    dialog.dismiss();
-                                    Log_OC.d(TAG, "Private key successfully decrypted and stored");
+                            dialog1.dismiss();
+                            Log_OC.d(TAG, "Private key successfully decrypted and stored");
 
-                                    arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
-                                                                                EncryptionUtils.MNEMONIC,
-                                                                                mnemonicUnchanged);
+                            arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(),
+                                                                        EncryptionUtils.MNEMONIC,
+                                                                        mnemonicUnchanged);
 
-                                    // check if private key and public key match
-                                    String publicKey = arbitraryDataProvider.getValue(user.getAccountName(),
-                                                                                      EncryptionUtils.PUBLIC_KEY);
+                            // check if private key and public key match
+                            String publicKey = arbitraryDataProvider.getValue(user.getAccountName(),
+                                                                              EncryptionUtils.PUBLIC_KEY);
 
-                                    byte[] key1 = generateKey();
-                                    String base64encodedKey = encodeBytesToBase64String(key1);
+                            byte[] key1 = generateKey();
+                            String base64encodedKey = encodeBytesToBase64String(key1);
 
-                                    String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey,
-                                                                                                     publicKey);
-                                    String decryptedString = decryptStringAsymmetric(encryptedString,
-                                                                                     decryptedPrivateKey);
+                            String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey,
+                                                                                             publicKey);
+                            String decryptedString = decryptStringAsymmetric(encryptedString,
+                                                                             decryptedPrivateKey);
 
-                                    byte[] key2 = decodeStringToBase64Bytes(decryptedString);
+                            byte[] key2 = decodeStringToBase64Bytes(decryptedString);
 
-                                    if (!Arrays.equals(key1, key2)) {
-                                        throw new Exception("Keys do not match");
-                                    }
+                            if (!Arrays.equals(key1, key2)) {
+                                throw new Exception("Keys do not match");
+                            }
 
-                                    Intent intentExisting = new Intent();
-                                    intentExisting.putExtra(SUCCESS, true);
-                                    intentExisting.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
-                                    getTargetFragment().onActivityResult(getTargetRequestCode(),
-                                                                         SETUP_ENCRYPTION_RESULT_CODE, intentExisting);
+                            notifyResult();
 
-                                } catch (Exception e) {
-                                    binding.encryptionStatus.setText(R.string.end_to_end_encryption_wrong_password);
-                                    Log_OC.d(TAG, "Error while decrypting private key: " + e.getMessage());
-                                }
-                                break;
+                        } catch (Exception e) {
+                            binding.encryptionStatus.setText(R.string.end_to_end_encryption_wrong_password);
+                            Log_OC.d(TAG, "Error while decrypting private key: " + e.getMessage());
+                        }
+                        break;
 
-                            case KEY_GENERATE:
-                                binding.encryptionPassphrase.setVisibility(View.GONE);
-                                positiveButton.setVisibility(View.GONE);
-                                neutralButton.setVisibility(View.GONE);
-                                getDialog().setTitle(R.string.end_to_end_encryption_storing_keys);
+                    case KEY_GENERATE:
+                        binding.encryptionPassphrase.setVisibility(View.GONE);
+                        positiveButton.setVisibility(View.GONE);
+                        neutralButton.setVisibility(View.GONE);
+                        getDialog().setTitle(R.string.end_to_end_encryption_storing_keys);
 
-                                GenerateNewKeysAsyncTask newKeysTask = new GenerateNewKeysAsyncTask();
-                                newKeysTask.execute();
-                                break;
+                        GenerateNewKeysAsyncTask newKeysTask = new GenerateNewKeysAsyncTask();
+                        newKeysTask.execute();
+                        break;
 
-                            default:
-                                dialog.dismiss();
-                                break;
-                        }
-                    }
-                });
-            }
+                    default:
+                        dialog1.dismiss();
+                        break;
+                }
+            });
         });
         return dialog;
     }
 
+    private void notifyResult() {
+        final Fragment targetFragment = getTargetFragment();
+        if (targetFragment != null) {
+            targetFragment.onActivityResult(getTargetRequestCode(),
+                                            SETUP_ENCRYPTION_RESULT_CODE, getResultIntent());
+        }
+        getParentFragmentManager().setFragmentResult(RESULT_REQUEST_KEY, getResultBundle());
+    }
+
+    @NonNull
+    private Intent getResultIntent() {
+        Intent intentCreated = new Intent();
+        intentCreated.putExtra(SUCCESS, true);
+        intentCreated.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION));
+        return intentCreated;
+    }
+
+    @NonNull
+    private Bundle getResultBundle() {
+        final Bundle bundle = new Bundle();
+        bundle.putBoolean(SUCCESS, true);
+        bundle.putInt(ARG_POSITION, getArguments().getInt(ARG_POSITION));
+        return bundle;
+    }
+
+
+    @Override
+    public void onCancel(@NonNull DialogInterface dialog) {
+        super.onCancel(dialog);
+        final Bundle bundle = new Bundle();
+        bundle.putBoolean(RESULT_KEY_CANCELLED, true);
+        getParentFragmentManager().setFragmentResult(RESULT_REQUEST_KEY, bundle);
+    }
+
     public class DownloadKeysAsyncTask extends AsyncTask<Void, Void, String> {
         @Override
         protected void onPreExecute() {
@@ -395,12 +419,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj
                 errorSavingKeys();
             } else {
                 requireDialog().dismiss();
-
-                Intent intentExisting = new Intent();
-                intentExisting.putExtra(SUCCESS, true);
-                intentExisting.putExtra(ARG_POSITION, requireArguments().getInt(ARG_POSITION));
-                getTargetFragment().onActivityResult(getTargetRequestCode(),
-                                                     SETUP_ENCRYPTION_RESULT_CODE, intentExisting);
+                notifyResult();
             }
         }
     }

+ 7 - 0
app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java

@@ -851,4 +851,11 @@ public final class EncryptionUtils {
             return new RemoteOperationResult(new Exception("No token available"));
         }
     }
+
+    public static void removeE2E(ArbitraryDataProvider arbitraryDataProvider, User user) {
+        // delete stored E2E keys and mnemonic
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PRIVATE_KEY);
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.PUBLIC_KEY);
+        arbitraryDataProvider.deleteKeyForAccount(user.getAccountName(), EncryptionUtils.MNEMONIC);
+    }
 }

+ 11 - 0
app/src/main/res/values/strings.xml

@@ -124,6 +124,7 @@
     <string name="common_send">Send</string>
     <string name="common_share">Share</string>
     <string name="common_skip">Skip</string>
+    <string name="common_copy">Copy</string>
     <string name="about_title">About</string>
     <string name="delete_account">Remove account</string>
     <string name="delete_account_warning">Remove account %s and delete all local files?\n\nDeletion cannot be undone.</string>
@@ -1056,4 +1057,14 @@
     <string name="error_file_actions">Error showing file actions</string>
     <string name="pin_home">Pin to Home screen</string>
     <string name="pin_shortcut_label">Open %1$s</string>
+    <string name="displays_mnemonic">Displays your 12 word passphrase</string>
+    <string name="prefs_setup_e2e">Set up end to end encryption</string>
+    <string name="prefs_e2e_active">End to end encryption is set up!</string>
+    <string name="prefs_remove_e2e">Remove encryption locally</string>
+    <string name="remove_e2e">You can remove end to end encryption locally on this client</string>
+    <string name="confirm_removal">Remove local encryption</string>
+    <string name="remove_e2e_message">You can remove end to end encryption locally on this client. The encrypted files will remain on server, but will not be synced to this computer any longer.</string>
+    <string name="setup_e2e">During setup of end to end encryption, you will receive a random 12 word mnemonic, which you will need to open your files on other devices. This will only be stored on this device, and can be shown again in this screen. Please note it down in a secure place!</string>
+    <string name="error_showing_encryption_dialog">Error showing setup encryption dialog!</string>
+    <string name="prefs_keys_exist">Add end to end encryption to this client</string>
 </resources>

+ 9 - 0
app/src/main/res/values/styles.xml

@@ -342,6 +342,15 @@
         <item name="windowNoTitle">true</item>
     </style>
 
+    <style name="Theme.NoBackground" parent="Theme.ownCloud.Toolbar">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:backgroundDimEnabled">false</item>
+    </style>
+
     <!-- Text styles -->
     <style name="NextcloudTextAppearanceHeadline" parent="@style/TextAppearance.AppCompat.Headline">
         <item name="android:textSize">26sp</item>

+ 39 - 15
app/src/main/res/xml/preferences.xml

@@ -59,27 +59,51 @@
             android:key="show_media_scan_notifications"/>
 	</PreferenceCategory>
 
-	<PreferenceCategory android:title="@string/prefs_category_more" android:key="more">
+	<PreferenceCategory
+        android:title="@string/prefs_category_more"
+        android:key="more">
         <Preference
             android:title="@string/drawer_synced_folders"
             android:key="syncedFolders"
-            android:summary="@string/prefs_sycned_folders_summary"/>
-		<Preference android:title="@string/prefs_calendar_contacts"
-					android:key="calendar_contacts"
-					android:summary="@string/prefs_calendar_contacts_summary" />
-		<Preference
+            android:summary="@string/prefs_sycned_folders_summary" />
+        <Preference
+            android:title="@string/prefs_calendar_contacts"
+            android:key="calendar_contacts"
+            android:summary="@string/prefs_calendar_contacts_summary" />
+        <Preference
             android:title="@string/backup_title"
             android:key="backup"
             android:summary="@string/prefs_daily_backup_summary" />
-		<Preference
-			android:title="@string/prefs_e2e_mnemonic"
-			android:key="mnemonic"
-			android:summary="Displays your E2E 12 words passphrase" />
-		<Preference android:title="@string/prefs_help" android:key="help" />
-		<Preference android:title="@string/prefs_recommend" android:key="recommend" />
-		<Preference android:title="@string/logs_title" android:key="logger" />
-		<Preference android:title="@string/prefs_imprint" android:key="imprint" />
-	</PreferenceCategory>
+        <Preference
+            android:title="@string/prefs_setup_e2e"
+            android:key="setup_e2e"
+            android:summary="@string/setup_e2e" />
+        <Preference
+            android:title="@string/prefs_keys_exist"
+            android:key="setup_e2e_keys_exist"
+            android:summary="End to end encryption was already set up on another client. Please enter your mnemonic to allow this client to sync and decrypt the files." />
+        <Preference
+            android:title="@string/prefs_e2e_active"
+            android:key="mnemonic"
+            android:summary="@string/displays_mnemonic" />
+        <Preference
+            android:title="@string/prefs_remove_e2e"
+            android:key="remove_e2e"
+            android:summary="@string/remove_e2e" />
+
+        <Preference
+            android:title="@string/prefs_help"
+            android:key="help" />
+        <Preference
+            android:title="@string/prefs_recommend"
+            android:key="recommend" />
+        <Preference
+            android:title="@string/logs_title"
+            android:key="logger" />
+        <Preference
+            android:title="@string/prefs_imprint"
+            android:key="imprint" />
+    </PreferenceCategory>
 	<PreferenceCategory android:title="@string/prefs_category_about" android:key="about">
 		<Preference
 			android:title="@string/privacy"