瀏覽代碼

Show file locking status on list

Also includes a refactor of how ContentValues are created in FileDataStorageManager.

The code for that was triplicated. now it's not.

Signed-off-by: Álvaro Brey Vilas <alvaro.brey@nextcloud.com>
Álvaro Brey Vilas 3 年之前
父節點
當前提交
f5ecaf91d1

+ 63 - 98
app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -208,44 +208,10 @@ public class FileDataStorageManager {
 
     public boolean saveFile(OCFile ocFile) {
         boolean overridden = false;
-        ContentValues cv = new ContentValues();
-        cv.put(ProviderTableMeta.FILE_MODIFIED, ocFile.getModificationTimestamp());
-        cv.put(
-            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
-            ocFile.getModificationTimestampAtLastSyncForData()
-        );
-        cv.put(ProviderTableMeta.FILE_CREATION, ocFile.getCreationTimestamp());
-        cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, ocFile.getFileLength());
-        cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, ocFile.getMimeType());
-        cv.put(ProviderTableMeta.FILE_NAME, ocFile.getFileName());
-        cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, ocFile.getEncryptedFileName());
-        cv.put(ProviderTableMeta.FILE_PARENT, ocFile.getParentId());
-        cv.put(ProviderTableMeta.FILE_PATH, ocFile.getRemotePath());
-        cv.put(ProviderTableMeta.FILE_PATH_DECRYPTED, ocFile.getDecryptedRemotePath());
-        cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, ocFile.isEncrypted());
-        if (!ocFile.isFolder()) {
-            cv.put(ProviderTableMeta.FILE_STORAGE_PATH, ocFile.getStoragePath());
+        final ContentValues cv = createContentValuesForFile(ocFile);
+        if (ocFile.isFolder()) {
+            cv.remove(ProviderTableMeta.FILE_STORAGE_PATH);
         }
-        cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, user.getAccountName());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, ocFile.getLastSyncDateForProperties());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, ocFile.getLastSyncDateForData());
-        cv.put(ProviderTableMeta.FILE_ETAG, ocFile.getEtag());
-        cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, ocFile.getEtagOnServer());
-        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, ocFile.isSharedViaLink() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, ocFile.isSharedWithSharee() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_PERMISSIONS, ocFile.getPermissions());
-        cv.put(ProviderTableMeta.FILE_REMOTE_ID, ocFile.getRemoteId());
-        cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, ocFile.isUpdateThumbnailNeeded());
-        cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, ocFile.isDownloading());
-        cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, ocFile.getEtagInConflict());
-        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, ocFile.getUnreadCommentsCount());
-        cv.put(ProviderTableMeta.FILE_OWNER_ID, ocFile.getOwnerId());
-        cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, ocFile.getOwnerDisplayName());
-        cv.put(ProviderTableMeta.FILE_NOTE, ocFile.getNote());
-        cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(ocFile.getSharees()));
-        cv.put(ProviderTableMeta.FILE_RICH_WORKSPACE, ocFile.getRichWorkspace());
-        cv.put(ProviderTableMeta.FILE_HAS_PREVIEW, ocFile.isPreviewAvailable() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_FAVORITE, ocFile.isFavorite());
 
         boolean sameRemotePath = fileExists(ocFile.getRemotePath());
         if (sameRemotePath ||
@@ -369,7 +335,8 @@ public class FileDataStorageManager {
 
         // prepare operations to insert or update files to save in the given folder
         for (OCFile ocFile : updatedFiles) {
-            ContentValues contentValues = createContentValueForFile(ocFile, folder);
+            ContentValues contentValues = createContentValuesForFile(ocFile);
+            contentValues.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
 
             if (fileExists(ocFile.getFileId()) || fileExists(ocFile.getRemotePath())) {
                 long fileId;
@@ -423,7 +390,7 @@ public class FileDataStorageManager {
         }
 
         // update metadata of folder
-        ContentValues contentValues = createContentValueForFile(folder);
+        ContentValues contentValues = createContentValuesForFolder(folder);
 
         operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI)
                            .withValues(contentValues)
@@ -467,77 +434,70 @@ public class FileDataStorageManager {
         }
     }
 
-    private ContentValues createContentValueForFile(OCFile folder) {
-        ContentValues cv = new ContentValues();
-        cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
-        cv.put(
-            ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
-            folder.getModificationTimestampAtLastSyncForData()
-        );
-        cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
-        cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
-        cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimeType());
-        cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
-        cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
-        cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
-        cv.put(ProviderTableMeta.FILE_PATH_DECRYPTED, folder.getDecryptedRemotePath());
+    /**
+     * Returns a {@link ContentValues} filled with values that are common to both files and folders
+     * @see #createContentValuesForFile(OCFile)
+     * @see #createContentValuesForFolder(OCFile)
+     */
+    private ContentValues createContentValuesBase(OCFile fileOrFolder) {
+        final ContentValues cv = new ContentValues();
+        cv.put(ProviderTableMeta.FILE_MODIFIED, fileOrFolder.getModificationTimestamp());
+        cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, fileOrFolder.getModificationTimestampAtLastSyncForData());
+        cv.put(ProviderTableMeta.FILE_PARENT, fileOrFolder.getParentId());
+        cv.put(ProviderTableMeta.FILE_CREATION, fileOrFolder.getCreationTimestamp());
+        cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, fileOrFolder.getMimeType());
+        cv.put(ProviderTableMeta.FILE_NAME, fileOrFolder.getFileName());
+        cv.put(ProviderTableMeta.FILE_PATH, fileOrFolder.getRemotePath());
+        cv.put(ProviderTableMeta.FILE_PATH_DECRYPTED, fileOrFolder.getDecryptedRemotePath());
         cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, user.getAccountName());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
-        cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
-        cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer());
-        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
-        cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
-        cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite());
-        cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, folder.isEncrypted());
-        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, folder.getUnreadCommentsCount());
-        cv.put(ProviderTableMeta.FILE_OWNER_ID, folder.getOwnerId());
-        cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, folder.getOwnerDisplayName());
-        cv.put(ProviderTableMeta.FILE_NOTE, folder.getNote());
-        cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(folder.getSharees()));
-        cv.put(ProviderTableMeta.FILE_RICH_WORKSPACE, folder.getRichWorkspace());
+        cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, fileOrFolder.isEncrypted());
+        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, fileOrFolder.getLastSyncDateForProperties());
+        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, fileOrFolder.getLastSyncDateForData());
+        cv.put(ProviderTableMeta.FILE_ETAG, fileOrFolder.getEtag());
+        cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, fileOrFolder.getEtagOnServer());
+        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, fileOrFolder.isSharedViaLink() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, fileOrFolder.isSharedWithSharee() ? 1 : 0);
+        cv.put(ProviderTableMeta.FILE_PERMISSIONS, fileOrFolder.getPermissions());
+        cv.put(ProviderTableMeta.FILE_REMOTE_ID, fileOrFolder.getRemoteId());
+        cv.put(ProviderTableMeta.FILE_FAVORITE, fileOrFolder.isFavorite());
+        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, fileOrFolder.getUnreadCommentsCount());
+        cv.put(ProviderTableMeta.FILE_OWNER_ID, fileOrFolder.getOwnerId());
+        cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, fileOrFolder.getOwnerDisplayName());
+        cv.put(ProviderTableMeta.FILE_NOTE, fileOrFolder.getNote());
+        cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(fileOrFolder.getSharees()));
+        cv.put(ProviderTableMeta.FILE_RICH_WORKSPACE, fileOrFolder.getRichWorkspace());
+        return cv;
+    }
 
+    /**
+     * Returns a {@link ContentValues} filled with values for a folder
+     * @see #createContentValuesForFile(OCFile)
+     * @see #createContentValuesBase(OCFile)
+     */
+    private ContentValues createContentValuesForFolder(OCFile folder) {
+        final ContentValues cv = createContentValuesBase(folder);
+        cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
         return cv;
     }
 
-    private ContentValues createContentValueForFile(OCFile file, OCFile folder) {
-        ContentValues cv = new ContentValues();
-        cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
-        cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
-        cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
+    /**
+     * Returns a {@link ContentValues} filled with values for a file
+     * @see #createContentValuesForFolder(OCFile)
+     * @see #createContentValuesBase(OCFile)
+     */
+    private ContentValues createContentValuesForFile(OCFile file) {
+        final ContentValues cv = createContentValuesBase(file);
         cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
-        cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
-        cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
         cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, file.getEncryptedFileName());
-        cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
-        cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
-        cv.put(ProviderTableMeta.FILE_PATH_DECRYPTED, file.getDecryptedRemotePath());
         cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
-        cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, user.getAccountName());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
-        cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
-        cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
-        cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
-        cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
-        cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
         cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded());
         cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
         cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
-        cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite());
-        cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, file.isEncrypted());
-        cv.put(ProviderTableMeta.FILE_MOUNT_TYPE, file.getMountType().ordinal());
         cv.put(ProviderTableMeta.FILE_HAS_PREVIEW, file.isPreviewAvailable() ? 1 : 0);
-        cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, file.getUnreadCommentsCount());
-        cv.put(ProviderTableMeta.FILE_OWNER_ID, file.getOwnerId());
-        cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, file.getOwnerDisplayName());
-        cv.put(ProviderTableMeta.FILE_NOTE, file.getNote());
-        cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(file.getSharees()));
-        cv.put(ProviderTableMeta.FILE_RICH_WORKSPACE, file.getRichWorkspace());
-
+        cv.put(ProviderTableMeta.FILE_LOCKED, file.isLocked());
+        cv.put(ProviderTableMeta.FILE_LOCK_OWNER, file.getLockOwnerId());
+        cv.put(ProviderTableMeta.FILE_LOCK_OWNER_DISPLAY_NAME, file.getLockOwnerDisplayName());
+        cv.put(ProviderTableMeta.FILE_LOCK_TIMESTAMP, file.getLockTimestamp());
         return cv;
     }
 
@@ -1030,6 +990,11 @@ public class FileDataStorageManager {
             ocFile.setOwnerDisplayName(cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME)));
             ocFile.setNote(cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_NOTE)));
             ocFile.setRichWorkspace(cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_RICH_WORKSPACE)));
+            ocFile.setLocked(cursor.getInt(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_LOCKED)) == 1);
+            ocFile.setLockOwnerId(cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_LOCK_OWNER)));
+            ocFile.setLockOwnerDisplayName(cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_LOCK_OWNER_DISPLAY_NAME)));
+            ocFile.setLockTimestamp(cursor.getInt(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_LOCK_TIMESTAMP)));
+
 
             String sharees = cursor.getString(cursor.getColumnIndexOrThrow(ProviderTableMeta.FILE_SHAREES));
 

+ 48 - 0
app/src/main/java/com/owncloud/android/datamodel/OCFile.java

@@ -95,6 +95,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
     String note;
     private List<ShareeUser> sharees;
     private String richWorkspace;
+    private boolean isLocked;
+    private String lockOwnerId;
+    private String lockOwnerDisplayName;
+    private long lockTimestamp;
 
     /**
      * URI to the local path of the file contents, if stored in the device; cached after first call
@@ -162,6 +166,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
         richWorkspace = source.readString();
         previewAvailable = source.readInt() == 1;
         firstShareTimestamp = source.readLong();
+        isLocked =  source.readInt() == 1;
+        lockOwnerId = source.readString();
+        lockOwnerDisplayName = source.readString();
+        lockTimestamp = source.readLong();
     }
 
     @Override
@@ -196,6 +204,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
         dest.writeString(richWorkspace);
         dest.writeInt(previewAvailable ? 1 : 0);
         dest.writeLong(firstShareTimestamp);
+        dest.writeInt(isLocked ? 1:0);
+        dest.writeString(lockOwnerId);
+        dest.writeString(lockOwnerDisplayName);
+        dest.writeLong(lockTimestamp);
     }
 
     public void setDecryptedRemotePath(String path) {
@@ -459,6 +471,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
         mountType = WebdavEntry.MountType.INTERNAL;
         richWorkspace = "";
         firstShareTimestamp = 0;
+        isLocked = false;
+        lockOwnerId = null;
+        lockOwnerDisplayName = null;
+        lockTimestamp = 0;
     }
 
     /**
@@ -831,4 +847,36 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
     public void setFirstShareTimestamp(long firstShareTimestamp) {
         this.firstShareTimestamp = firstShareTimestamp;
     }
+
+    public boolean isLocked() {
+        return isLocked;
+    }
+
+    public void setLocked(boolean locked) {
+        isLocked = locked;
+    }
+
+    public String getLockOwnerId() {
+        return lockOwnerId;
+    }
+
+    public void setLockOwnerId(String lockOwnerId) {
+        this.lockOwnerId = lockOwnerId;
+    }
+
+    public String getLockOwnerDisplayName() {
+        return lockOwnerDisplayName;
+    }
+
+    public void setLockOwnerDisplayName(String lockOwnerDisplayName) {
+        this.lockOwnerDisplayName = lockOwnerDisplayName;
+    }
+
+    public long getLockTimestamp() {
+        return lockTimestamp;
+    }
+
+    public void setLockTimestamp(long lockTimestamp) {
+        this.lockTimestamp = lockTimestamp;
+    }
 }

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

@@ -117,6 +117,10 @@ public class ProviderMeta {
         public static final String FILE_NOTE = "note";
         public static final String FILE_SHAREES = "sharees";
         public static final String FILE_RICH_WORKSPACE = "rich_workspace";
+        public static final String FILE_LOCKED = "locked";
+        public static final String FILE_LOCK_OWNER = "lock_owner";
+        public static final String FILE_LOCK_OWNER_DISPLAY_NAME = "lock_owner_display_name";
+        public static final String FILE_LOCK_TIMESTAMP = "lock_timestamp";
 
         public static final List<String> FILE_ALL_COLUMNS = Collections.unmodifiableList(Arrays.asList(
             _ID,
@@ -153,8 +157,11 @@ public class ProviderMeta {
             FILE_OWNER_DISPLAY_NAME,
             FILE_NOTE,
             FILE_SHAREES,
-            FILE_RICH_WORKSPACE));
-
+            FILE_RICH_WORKSPACE,
+            FILE_LOCKED,
+            FILE_LOCK_OWNER,
+            FILE_LOCK_OWNER_DISPLAY_NAME,
+            FILE_LOCK_TIMESTAMP));
         public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc";
 
         // Columns of ocshares table

+ 18 - 2
app/src/main/java/com/owncloud/android/providers/FileContentProvider.java

@@ -753,7 +753,11 @@ public class FileContentProvider extends ContentProvider {
                        + ProviderTableMeta.FILE_OWNER_DISPLAY_NAME + TEXT
                        + ProviderTableMeta.FILE_NOTE + TEXT
                        + ProviderTableMeta.FILE_SHAREES + TEXT
-                       + ProviderTableMeta.FILE_RICH_WORKSPACE + " TEXT);"
+                       + ProviderTableMeta.FILE_RICH_WORKSPACE + TEXT
+                       + ProviderTableMeta.FILE_LOCKED + INTEGER // boolean
+                       + ProviderTableMeta.FILE_LOCK_OWNER + TEXT
+                       + ProviderTableMeta.FILE_LOCK_OWNER_DISPLAY_NAME + TEXT
+                       + ProviderTableMeta.FILE_LOCK_TIMESTAMP + " INTEGER );"
         );
     }
 
@@ -2456,12 +2460,24 @@ public class FileContentProvider extends ContentProvider {
             }
 
             if (oldVersion < 63 && newVersion >= 63) {
-                Log_OC.i(SQL, "Adding file locking version to capability");
+                Log_OC.i(SQL, "Adding file locking columns");
                 db.beginTransaction();
                 try {
+                    // locking capabilities
                     db.execSQL(ALTER_TABLE + ProviderTableMeta.CAPABILITIES_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION + " TEXT ");
                     // force refresh
                     db.execSQL("UPDATE capabilities SET etag = '' WHERE 1=1");
+                    // locking properties
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.FILE_LOCKED + " INTEGER "); // boolean
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.FILE_LOCK_OWNER + " TEXT ");
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.FILE_LOCK_OWNER_DISPLAY_NAME + " TEXT ");
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.FILE_LOCK_TIMESTAMP + " INTEGER ");
+                    db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + " SET " + ProviderTableMeta.FILE_ETAG + " = '' WHERE 1=1");
+
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();

+ 1 - 0
app/src/main/java/com/owncloud/android/ui/adapter/ListItemViewHolder.kt

@@ -32,4 +32,5 @@ internal interface ListItemViewHolder : ListGridItemViewHolder {
     val lastModification: TextView
     val overflowMenu: ImageView
     val sharedAvatars: AvatarGroupLayout
+    val lockIndicator: View
 }

+ 6 - 0
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -466,6 +466,12 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             holder.getOverflowMenu().setOnClickListener(view -> ocFileListFragmentInterface
                 .onOverflowIconClicked(file, view));
         }
+
+        if (file.isLocked()) {
+            holder.getLockIndicator().setVisibility(View.VISIBLE);
+        } else {
+            holder.getLockIndicator().setVisibility(View.GONE);
+        }
     }
 
     private void bindListGridItemViewHolder(ListGridItemViewHolder holder, OCFile file) {

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt

@@ -62,6 +62,8 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) :
         get() = binding.ListItemLayout
     override val unreadComments: ImageView
         get() = binding.unreadComments
+    override val lockIndicator: View
+        get() = binding.lockIndicator
 
     init {
         binding.favoriteAction.drawable.mutate()

+ 4 - 0
app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java

@@ -233,6 +233,10 @@ public final class FileStorageUtils {
         file.setNote(remote.getNote());
         file.setSharees(new ArrayList<>(Arrays.asList(remote.getSharees())));
         file.setRichWorkspace(remote.getRichWorkspace());
+        file.setLocked(remote.isLocked());
+        file.setLockOwnerId(remote.getLockOwner());
+        file.setLockOwnerDisplayName(remote.getLockOwnerDisplayName());
+        file.setLockTimestamp(remote.getLockTimestamp());
 
         return file;
     }

+ 16 - 0
app/src/main/res/layout/list_item.xml

@@ -18,6 +18,7 @@
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/ListItemLayout"
     android:layout_width="match_parent"
     android:layout_height="@dimen/standard_list_item_size"
@@ -79,6 +80,21 @@
             app:layout_constraintStart_toEndOf="@+id/thumbnail_layout"
             app:layout_constraintTop_toTopOf="@+id/thumbnail_layout" />
 
+        <ImageView
+            android:id="@+id/lock_indicator"
+            android:layout_width="@dimen/list_item_local_file_indicator_layout_width"
+            android:layout_height="@dimen/list_item_local_file_indicator_layout_width"
+            android:contentDescription="@string/file_locked"
+            android:src="@drawable/ic_lock_white"
+            android:visibility="gone"
+            app:tint="@color/secondary_text_color"
+            tools:visibility="visible"
+            app:layout_constraintBottom_toBottomOf="@+id/thumbnail_layout"
+            app:layout_constraintEnd_toStartOf="@+id/thumbnail_layout"
+            app:layout_constraintStart_toStartOf="@+id/thumbnail_layout"
+            app:layout_constraintTop_toBottomOf="@+id/thumbnail_layout" />
+
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
     <LinearLayout

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

@@ -1008,4 +1008,5 @@
     <string name="pdf_zoom_tip">Tap on a page to zoom in</string>
     <string name="storage_permission_full_access">Full access</string>
     <string name="storage_permission_media_read_only">Media read-only</string>
+    <string name="file_locked">This file is locked</string>
 </resources>