Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 777efaea authored by Tomasz Mikolajewski's avatar Tomasz Mikolajewski
Browse files

Open archives in different modes separately.

If an archive is opened for writing, and then for reading, we
have to keep both opened. Until now, we'd only open one, and reuse
the first instance for both, causing exceptions.

Test: Tested manually.
Bug: 20822019
Change-Id: I28eb2a67ca43ecc2d35fa9cfae4e20200e8a46bc
parent 85ef1a21
Loading
Loading
Loading
Loading
+43 −9
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.Lock;

/**
@@ -64,10 +65,10 @@ public class ArchivesProvider extends DocumentsProvider implements Closeable {
    };

    @GuardedBy("mArchives")
    private final LruCache<Uri, Loader> mArchives =
            new LruCache<Uri, Loader>(OPENED_ARCHIVES_CACHE_SIZE) {
    private final LruCache<Key, Loader> mArchives =
            new LruCache<Key, Loader>(OPENED_ARCHIVES_CACHE_SIZE) {
                @Override
                public void entryRemoved(boolean evicted, Uri key,
                public void entryRemoved(boolean evicted, Key key,
                        Loader oldValue, Loader newValue) {
                    oldValue.getWriteLock().lock();
                    try {
@@ -274,8 +275,10 @@ public class ArchivesProvider extends DocumentsProvider implements Closeable {

    private Loader getInstanceUncheckedLocked(String documentId) throws FileNotFoundException {
        final ArchiveId id = ArchiveId.fromDocumentId(documentId);
        if (mArchives.get(id.mArchiveUri) != null) {
            return mArchives.get(id.mArchiveUri);
        final Key key = Key.fromArchiveId(id);
        final Loader existingLoader = mArchives.get(key);
        if (existingLoader != null) {
            return existingLoader;
        }

        final Cursor cursor = getContext().getContentResolver().query(
@@ -294,23 +297,54 @@ public class ArchivesProvider extends DocumentsProvider implements Closeable {

        // Remove the instance from mArchives collection once the archive file changes.
        if (notificationUri != null) {
            final LruCache<Uri, Loader> finalArchives = mArchives;
            final LruCache<Key, Loader> finalArchives = mArchives;
            getContext().getContentResolver().registerContentObserver(notificationUri,
                    false,
                    new ContentObserver(null) {
                        @Override
                        public void onChange(boolean selfChange, Uri uri) {
                            synchronized (mArchives) {
                                final Loader currentLoader = mArchives.get(id.mArchiveUri);
                                final Loader currentLoader = mArchives.get(key);
                                if (currentLoader == loader) {
                                    mArchives.remove(id.mArchiveUri);
                                    mArchives.remove(key);
                                }
                            }
                        }
                    });
        }

        mArchives.put(id.mArchiveUri, loader);
        mArchives.put(key, loader);
        return loader;
    }

    private static class Key {
        Uri archiveUri;
        int accessMode;

        public Key(Uri archiveUri, int accessMode) {
            this.archiveUri = archiveUri;
            this.accessMode = accessMode;
        }

        public static Key fromArchiveId(ArchiveId id) {
            return new Key(id.mArchiveUri, id.mAccessMode);
        }

        @Override
        public boolean equals(Object other) {
            if (other == null) {
                return false;
            }
            if (!(other instanceof Key)) {
                return false;
            }
            return archiveUri.equals(((Key) other).archiveUri) &&
                accessMode == ((Key) other).accessMode;
        }

        @Override
        public int hashCode() {
            return Objects.hash(archiveUri, accessMode);
        }
    }
}