RecentsCreateFragment.java revision 845fe50423acd8e279ef37888f674deb52fd5fe1
1b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey/*
2b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
4b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * you may not use this file except in compliance with the License.
6b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * You may obtain a copy of the License at
7b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
8b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey *
10b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * See the License for the specific language governing permissions and
14b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * limitations under the License.
15b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey */
16b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
17b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeypackage com.android.documentsui;
18b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
1958efce36cd1b26006e08ddd696292bf06fc34c81Steve McKayimport static com.android.documentsui.Shared.TAG;
20845fe50423acd8e279ef37888f674deb52fd5fe1Ben Linimport static com.android.documentsui.State.ACTION_CREATE;
210c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey
22b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.app.Fragment;
23b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.app.FragmentManager;
24b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.app.FragmentTransaction;
25b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks;
26b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.content.ContentResolver;
27b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.content.Context;
28b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.content.Loader;
29b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.database.Cursor;
303f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkeyimport android.graphics.drawable.Drawable;
31b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.net.Uri;
32b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.os.Bundle;
33b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.os.CancellationSignal;
34c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKayimport android.support.annotation.Nullable;
35c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKayimport android.support.v7.widget.LinearLayoutManager;
36c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKayimport android.support.v7.widget.RecyclerView;
373f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkeyimport android.text.Spannable;
383f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkeyimport android.text.SpannableStringBuilder;
39b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.text.TextUtils.TruncateAt;
403f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkeyimport android.text.style.ImageSpan;
410c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkeyimport android.util.Log;
42b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.view.LayoutInflater;
43c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKayimport android.view.MotionEvent;
44b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.view.View;
45b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.view.ViewGroup;
46b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.widget.ImageView;
47b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.widget.TextView;
48b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
49d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkeyimport com.android.documentsui.RecentsProvider.RecentColumns;
50b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport com.android.documentsui.model.DocumentStack;
516a20e574116af1072782c1e87cb03eb33f05ec50Jeff Sharkeyimport com.android.documentsui.model.DurableUtils;
52deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport com.android.documentsui.model.RootInfo;
53b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
54b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport libcore.io.IoUtils;
55b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
56b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport java.io.IOException;
57b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.ArrayList;
58deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkeyimport java.util.Collection;
59b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.List;
60b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
61b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey/**
62b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey * Display directories where recent creates took place.
63b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey */
64b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeypublic class RecentsCreateFragment extends Fragment {
65b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
666efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private View mEmptyView;
67c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay    private RecyclerView mRecView;
68b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private DocumentStackAdapter mAdapter;
69b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private LoaderCallbacks<List<DocumentStack>> mCallbacks;
70b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
71b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private static final int LOADER_RECENTS = 3;
72b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
73b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public static void show(FragmentManager fm) {
74b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final RecentsCreateFragment fragment = new RecentsCreateFragment();
75b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final FragmentTransaction ft = fm.beginTransaction();
76b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        ft.replace(R.id.container_directory, fragment);
77b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        ft.commitAllowingStateLoss();
78b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
79b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
80b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    @Override
81b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public View onCreateView(
82b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
83b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final Context context = inflater.getContext();
84b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
85b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final View view = inflater.inflate(R.layout.fragment_directory, container, false);
86b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
872036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa        mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
88c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        mRecView.setLayoutManager(new LinearLayoutManager(getContext()));
89c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        mRecView.addOnItemTouchListener(mItemListener);
906efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
91c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        mEmptyView = view.findViewById(android.R.id.empty);
92b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
93b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        mAdapter = new DocumentStackAdapter();
94c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        mRecView.setAdapter(mAdapter);
95b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
96deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        final RootsCache roots = DocumentsApplication.getRootsCache(context);
97e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final State state = ((BaseActivity) getActivity()).getDisplayState();
98deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
99b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        mCallbacks = new LoaderCallbacks<List<DocumentStack>>() {
100b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            @Override
101b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            public Loader<List<DocumentStack>> onCreateLoader(int id, Bundle args) {
102deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                return new RecentsCreateLoader(context, roots, state);
103b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
104b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
105b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            @Override
106b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            public void onLoadFinished(
107b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    Loader<List<DocumentStack>> loader, List<DocumentStack> data) {
108c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                mAdapter.update(data);
109a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey
110a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                // When launched into empty recents, show drawer
111845fe50423acd8e279ef37888f674deb52fd5fe1Ben Lin                if (mAdapter.isEmpty() && !state.hasLocationChanged()
112845fe50423acd8e279ef37888f674deb52fd5fe1Ben Lin                        && state.action != ACTION_CREATE
113845fe50423acd8e279ef37888f674deb52fd5fe1Ben Lin                        && context instanceof DocumentsActivity) {
114ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay                    ((DocumentsActivity) context).setRootsDrawerOpen(true);
115a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                }
116b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
117b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
118b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            @Override
119b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            public void onLoaderReset(Loader<List<DocumentStack>> loader) {
120c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                mAdapter.update(null);
121b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
122b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        };
123b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
124b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        return view;
125b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
126b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
127b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    @Override
128b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public void onStart() {
129b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        super.onStart();
130b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        getLoaderManager().restartLoader(LOADER_RECENTS, getArguments(), mCallbacks);
131b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
132b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
133b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    @Override
134b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public void onStop() {
135b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        super.onStop();
136b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        getLoaderManager().destroyLoader(LOADER_RECENTS);
137b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
138b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
139c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay    private RecyclerView.OnItemTouchListener mItemListener =
140c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            new RecyclerView.OnItemTouchListener() {
141c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                @Override
142c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
143c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                    Events.MotionInputEvent event = new Events.MotionInputEvent(e, mRecView);
144c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                    if (event.isOverItem() && event.isActionUp()) {
145c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                        final DocumentStack stack = mAdapter.getItem(event.getItemPosition());
146c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                        ((BaseActivity) getActivity()).onStackPicked(stack);
147c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                        return true;
148c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                    }
149c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                    return false;
150c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                }
151c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay
152c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                @Override
153c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
154c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                @Override
155c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
156c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            };
157b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
158b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey    public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> {
159deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        private final RootsCache mRoots;
160deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        private final State mState;
161deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
162deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey        public RecentsCreateLoader(Context context, RootsCache roots, State state) {
163d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey            super(context, RecentsProvider.buildRecent());
164deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            mRoots = roots;
165deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            mState = state;
166b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        }
167b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
168b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        @Override
169b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
170deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey            final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
17158efce36cd1b26006e08ddd696292bf06fc34c81Steve McKay            final ArrayList<DocumentStack> result = new ArrayList<>();
172b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
173b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final ContentResolver resolver = getContext().getContentResolver();
174b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final Cursor cursor = resolver.query(
175d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    uri, null, null, null, RecentColumns.TIMESTAMP + " DESC", signal);
176b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            try {
177b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                while (cursor != null && cursor.moveToNext()) {
178d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                    final byte[] rawStack = cursor.getBlob(
179d182bb641f228b2d28527a6aa86075f6358ab838Jeff Sharkey                            cursor.getColumnIndex(RecentColumns.STACK));
1800c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey                    try {
181b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                        final DocumentStack stack = new DocumentStack();
1826a20e574116af1072782c1e87cb03eb33f05ec50Jeff Sharkey                        DurableUtils.readFromArray(rawStack, stack);
183deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey
184deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                        // Only update root here to avoid spinning up all
185deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                        // providers; we update the stack during the actual
186deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                        // restore. This also filters away roots that don't
187deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                        // match current filter.
188deffadeb7485e8660ecce12822e259d96fa06dceJeff Sharkey                        stack.updateRoot(matchingRoots);
1890c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey                        result.add(stack);
190b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey                    } catch (IOException e) {
1910c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey                        Log.w(TAG, "Failed to resolve stack: " + e);
1920c2d31bfa113c2848620ac05c916802410b71da1Jeff Sharkey                    }
193b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                }
194b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            } finally {
195b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                IoUtils.closeQuietly(cursor);
196b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
197b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
198b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            return result;
199b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        }
200b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
201b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
202c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay    private static final class StackHolder extends RecyclerView.ViewHolder {
203c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        public View view;
204c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        public StackHolder(View view) {
205c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            super(view);
206c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            this.view = view;
207c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        }
208c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay    }
209c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay
210c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay    private class DocumentStackAdapter extends RecyclerView.Adapter<StackHolder> {
211c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        @Nullable private List<DocumentStack> mItems;
212c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay
213c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        DocumentStack getItem(int position) {
214c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            return mItems.get(position);
215c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        }
216c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay
217c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        @Override
218c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        public int getItemCount() {
219c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            return mItems == null ? 0 : mItems.size();
220c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        }
221b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
222c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        boolean isEmpty() {
223c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            return mItems == null ? true : mItems.isEmpty();
224b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        }
225b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
226c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        void update(@Nullable List<DocumentStack> items) {
227c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            mItems = items;
2286efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2296efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (isEmpty()) {
2306efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                mEmptyView.setVisibility(View.VISIBLE);
2316efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            } else {
2326efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                mEmptyView.setVisibility(View.GONE);
2336efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            }
2346efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
235b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            notifyDataSetChanged();
236b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        }
237b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
238b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        @Override
239c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        public StackHolder onCreateViewHolder(ViewGroup parent, int viewType) {
240c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay          final Context context = parent.getContext();
241b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
242c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay          final LayoutInflater inflater = LayoutInflater.from(context);
243c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay          return new StackHolder(
244c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay                  (View) inflater.inflate(R.layout.item_doc_list, parent, false));
245c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        }
246c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay
247c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        @Override
248c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay        public void onBindViewHolder(StackHolder holder, int position) {
249c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            Context context = getContext();
250c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            View view = holder.view;
251b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
252c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            final ImageView iconMime = (ImageView) view.findViewById(R.id.icon_mime);
253c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            final TextView title = (TextView) view.findViewById(android.R.id.title);
254c643386e2801b7bb7f3ba79c4474a5b05a224d4fSteve McKay            final View line2 = view.findViewById(R.id.line2);
255b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
256b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final DocumentStack stack = getItem(position);
2574ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey            iconMime.setImageDrawable(stack.root.loadIcon(context));
258b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
25903d30a573b8bc8e169e153a0fffa053ffedcd5eeAlan Viverette            final Drawable crumb = context.getDrawable(R.drawable.ic_breadcrumb_arrow);
2603f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey            crumb.setBounds(0, 0, crumb.getIntrinsicWidth(), crumb.getIntrinsicHeight());
2613f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey
2623f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey            final SpannableStringBuilder builder = new SpannableStringBuilder();
2633f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey            builder.append(stack.root.title);
2643f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey            for (int i = stack.size() - 2; i >= 0; i--) {
2655545f56f7561810187545a1817b6001dd1f9931bJeff Sharkey                appendDrawable(builder, crumb);
266b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                builder.append(stack.get(i).displayName);
267b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
2683f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey            title.setText(builder);
269b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            title.setEllipsize(TruncateAt.MIDDLE);
270b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
271f8abf2e387681f2ed7631783418972972379d740Jeff Sharkey            if (line2 != null) line2.setVisibility(View.GONE);
272b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        }
273b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
2743f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey
2753f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey    private static void appendDrawable(SpannableStringBuilder b, Drawable d) {
2763f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey        final int length = b.length();
2773f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey        b.append("\u232a");
2783f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey        b.setSpan(new ImageSpan(d), length, b.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
2793f4c205fd3110345241e690f2a2e7c1b477eac76Jeff Sharkey    }
280b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey}
281