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

Commit 4eb407a8 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Management actions, invalidate caches.

In manage mode, touching launches a VIEW intent for the file.  Also
adds actions for sharing and deleting.

Move roots and thumbnail caches into Application object, and flush
cache when thumbnail size changes.  Listen for package changes and
broadcasts that should invalidate our roots cache.

Pick default grid/list mode based on provider hint.

Bug: 10329983, 10330210, 10378834, 10330069
Change-Id: I75afb1c58ab71bb9d55852b1059da7257a376248
parent 58514937
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import libcore.io.IoUtils;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
+9 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
    <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />

    <application
        android:name=".DocumentsApplication"
        android:label="@string/app_label"
        android:supportsRtl="true">

@@ -51,6 +52,14 @@
            android:authorities="com.android.documentsui.recents"
            android:exported="false" />

        <receiver android:name=".DocumentChangedReceiver">
            <intent-filter>
                <action android:name="android.provider.action.DOCUMENT_CHANGED" />
                <data android:mimeType="vnd.android.cursor.dir/root" />
                <data android:mimeType="vnd.android.cursor.item/root" />
            </intent-filter>
        </receiver>

        <!-- TODO: remove when we have real clients -->
        <activity android:name=".TestActivity" android:enabled="false">
            <intent-filter>
+10 −0
Original line number Diff line number Diff line
@@ -19,4 +19,14 @@
        android:id="@+id/menu_open"
        android:title="@string/menu_open"
        android:showAsAction="always" />
    <item
        android:id="@+id/menu_share"
        android:icon="@android:drawable/ic_menu_share"
        android:title="@string/menu_share"
        android:showAsAction="always" />
    <item
        android:id="@+id/menu_delete"
        android:icon="@android:drawable/ic_menu_delete"
        android:title="@string/menu_delete"
        android:showAsAction="always" />
</menu>
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@

    <string name="menu_open">Open</string>
    <string name="menu_save">Save</string>
    <string name="menu_share">Share</string>
    <string name="menu_delete">Delete</string>

    <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>

@@ -55,4 +57,7 @@

    <string name="empty">No items</string>

    <string name="toast_no_application">Can\'t open file</string>
    <string name="toast_failed_delete">Unable to delete some documents</string>

</resources>
+115 −30
Original line number Diff line number Diff line
@@ -17,12 +17,20 @@
package com.android.documentsui;

import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_DATE;
import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_NAME;
import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_SIZE;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.Point;
@@ -50,6 +58,7 @@ import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.documentsui.DocumentsActivity.DisplayState;
import com.android.documentsui.model.Document;
@@ -57,7 +66,6 @@ import com.android.documentsui.model.Root;
import com.android.internal.util.Predicate;
import com.google.android.collect.Lists;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -167,11 +175,11 @@ public class DirectoryFragment extends Fragment {
                }

                final Comparator<Document> sortOrder;
                if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
                if (state.sortOrder == SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
                    sortOrder = new Document.DateComparator();
                } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
                } else if (state.sortOrder == SORT_ORDER_NAME) {
                    sortOrder = new Document.NameComparator();
                } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) {
                } else if (state.sortOrder == SORT_ORDER_SIZE) {
                    sortOrder = new Document.SizeComparator();
                } else {
                    throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
@@ -216,8 +224,8 @@ public class DirectoryFragment extends Fragment {
        mListView.smoothScrollToPosition(0);
        mGridView.smoothScrollToPosition(0);

        mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
        mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
        mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE);
        mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE);

        final int choiceMode;
        if (state.allowMultiple) {
@@ -227,7 +235,7 @@ public class DirectoryFragment extends Fragment {
        }

        final int thumbSize;
        if (state.mode == DisplayState.MODE_GRID) {
        if (state.mode == MODE_GRID) {
            thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
            mListView.setAdapter(null);
            mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -236,7 +244,7 @@ public class DirectoryFragment extends Fragment {
            mGridView.setNumColumns(GridView.AUTO_FIT);
            mGridView.setChoiceMode(choiceMode);
            mCurrentView = mGridView;
        } else if (state.mode == DisplayState.MODE_LIST) {
        } else if (state.mode == MODE_LIST) {
            thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
            mGridView.setAdapter(null);
            mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
@@ -269,16 +277,24 @@ public class DirectoryFragment extends Fragment {

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            final DisplayState state = getDisplayState(DirectoryFragment.this);

            final MenuItem open = menu.findItem(R.id.menu_open);
            final MenuItem share = menu.findItem(R.id.menu_share);
            final MenuItem delete = menu.findItem(R.id.menu_delete);

            final boolean manageMode = state.action == ACTION_MANAGE;
            open.setVisible(!manageMode);
            share.setVisible(manageMode);
            delete.setVisible(manageMode);

            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            if (item.getItemId() == R.id.menu_open) {
                final Uri uri = getArguments().getParcelable(EXTRA_URI);
            final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
            final ArrayList<Document> docs = Lists.newArrayList();

            final int size = checked.size();
            for (int i = 0; i < size; i++) {
                if (checked.valueAt(i)) {
@@ -287,8 +303,19 @@ public class DirectoryFragment extends Fragment {
                }
            }

                ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
            final int id = item.getItemId();
            if (id == R.id.menu_open) {
                DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
                return true;

            } else if (id == R.id.menu_share) {
                onShareDocuments(docs);
                return true;

            } else if (id == R.id.menu_delete) {
                onDeleteDocuments(docs);
                return true;

            } else {
                return false;
            }
@@ -315,6 +342,58 @@ public class DirectoryFragment extends Fragment {
        }
    };

    private void onShareDocuments(List<Document> docs) {
        final ArrayList<Uri> uris = Lists.newArrayList();
        for (Document doc : docs) {
            uris.add(doc.uri);
        }

        final Intent intent;
        if (uris.size() > 1) {
            intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            // TODO: find common mimetype
            intent.setType("*/*");
            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
        } else {
            intent = new Intent(Intent.ACTION_SEND);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(uris.get(0));
        }

        startActivity(intent);
    }

    private void onDeleteDocuments(List<Document> docs) {
        final Context context = getActivity();
        final ContentResolver resolver = context.getContentResolver();

        boolean hadTrouble = false;
        for (Document doc : docs) {
            if (!doc.isDeleteSupported()) {
                Log.w(TAG, "Skipping " + doc);
                hadTrouble = true;
                continue;
            }

            try {
                if (resolver.delete(doc.uri, null, null) != 1) {
                    Log.w(TAG, "Failed to delete " + doc);
                    hadTrouble = true;
                }
            } catch (Exception e) {
                Log.w(TAG, "Failed to delete " + doc + ": " + e);
                hadTrouble = true;
            }
        }

        if (hadTrouble) {
            Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show();
        }
    }

    private static DisplayState getDisplayState(Fragment fragment) {
        return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
    }
@@ -342,11 +421,15 @@ public class DirectoryFragment extends Fragment {
            final Context context = parent.getContext();
            final DisplayState state = getDisplayState(DirectoryFragment.this);

            final RootsCache roots = DocumentsApplication.getRootsCache(context);
            final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                    context, mThumbSize);

            if (convertView == null) {
                final LayoutInflater inflater = LayoutInflater.from(context);
                if (state.mode == DisplayState.MODE_LIST) {
                if (state.mode == MODE_LIST) {
                    convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
                } else if (state.mode == DisplayState.MODE_GRID) {
                } else if (state.mode == MODE_GRID) {
                    convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
                } else {
                    throw new IllegalStateException();
@@ -369,7 +452,7 @@ public class DirectoryFragment extends Fragment {
            }

            if (doc.isThumbnailSupported()) {
                final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri);
                final Bitmap cachedResult = thumbs.get(doc.uri);
                if (cachedResult != null) {
                    icon.setImageBitmap(cachedResult);
                } else {
@@ -379,7 +462,7 @@ public class DirectoryFragment extends Fragment {
                    task.execute(doc.uri);
                }
            } else {
                icon.setImageDrawable(RootsCache.resolveDocumentIcon(
                icon.setImageDrawable(roots.resolveDocumentIcon(
                        context, doc.uri.getAuthority(), doc.mimeType));
            }

@@ -394,7 +477,7 @@ public class DirectoryFragment extends Fragment {
                    summary.setVisibility(View.INVISIBLE);
                }
            } else if (mType == TYPE_RECENT_OPEN) {
                final Root root = RootsCache.findRoot(context, doc);
                final Root root = roots.findRoot(doc);
                icon1.setVisibility(View.VISIBLE);
                icon1.setImageDrawable(root.icon);
                summary.setText(root.getDirectoryString());
@@ -444,11 +527,11 @@ public class DirectoryFragment extends Fragment {

    private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> {
        private final ImageView mTarget;
        private final Point mSize;
        private final Point mThumbSize;

        public ThumbnailAsyncTask(ImageView target, Point size) {
        public ThumbnailAsyncTask(ImageView target, Point thumbSize) {
            mTarget = target;
            mSize = size;
            mThumbSize = thumbSize;
        }

        @Override
@@ -464,9 +547,11 @@ public class DirectoryFragment extends Fragment {
            Bitmap result = null;
            try {
                result = DocumentsContract.getThumbnail(
                        context.getContentResolver(), uri, mSize);
                        context.getContentResolver(), uri, mThumbSize);
                if (result != null) {
                    ThumbnailCache.get(context).put(uri, result);
                    final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                            context, mThumbSize);
                    thumbs.put(uri, result);
                }
            } catch (Exception e) {
                Log.w(TAG, "Failed to load thumbnail: " + e);
Loading