From 8ac92809b813ae120e59e05b2b1425ff557c8e10 Mon Sep 17 00:00:00 2001 From: xplodwild Date: Mon, 11 Nov 2013 02:07:32 +0100 Subject: [PATCH] DocumentsUI: Add a standalone File Manager This commit adds a standalone mode to the DocumentsUI, to let it act as a file manager/explorer. You can browse your storage contents, open files, and delete them, as well as do everything that the DocumentsUI can do (ie. sort by name/size/type, list and grid view, recents, search, ...). This gives us a consistent file browsing UX accross all apps that uses the new documents API. Change-Id: I630467664b445d0d011555b84fa3d50abdb666f3 --- packages/DocumentsUI/AndroidManifest.xml | 8 +- .../res/drawable-hdpi/ic_filemanager.png | Bin 0 -> 3071 bytes .../res/drawable-mdpi/ic_filemanager.png | Bin 0 -> 2377 bytes .../res/drawable-xhdpi/ic_filemanager.png | Bin 0 -> 3706 bytes .../res/drawable-xxhdpi/ic_filemanager.png | Bin 0 -> 17805 bytes packages/DocumentsUI/res/menu/activity.xml | 5 + .../DocumentsUI/res/menu/mode_directory.xml | 10 + .../DocumentsUI/res/values/custom_strings.xml | 60 ++++++ .../documentsui/DirectoryFragment.java | 167 +++++++++++++++- .../documentsui/DocumentsActivity.java | 187 +++++++++++++++++- 10 files changed, 424 insertions(+), 13 deletions(-) create mode 100644 packages/DocumentsUI/res/drawable-hdpi/ic_filemanager.png create mode 100644 packages/DocumentsUI/res/drawable-mdpi/ic_filemanager.png create mode 100644 packages/DocumentsUI/res/drawable-xhdpi/ic_filemanager.png create mode 100644 packages/DocumentsUI/res/drawable-xxhdpi/ic_filemanager.png create mode 100644 packages/DocumentsUI/res/values/custom_strings.xml diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index e95e5ec322ef8..93c117a79d9d2 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -7,12 +7,18 @@ + android:icon="@drawable/ic_filemanager"> + + + + + diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_filemanager.png b/packages/DocumentsUI/res/drawable-hdpi/ic_filemanager.png new file mode 100644 index 0000000000000000000000000000000000000000..e88fdef69d321d4d48206851acd4988c475ce7f0 GIT binary patch literal 3071 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 GCGp==hTK5_ literal 0 HcmV?d00001 diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_filemanager.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_filemanager.png new file mode 100644 index 0000000000000000000000000000000000000000..54e849b4811e36c6bf9bc65b8102bf5bdf95547b GIT binary patch literal 3706 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 YfLhv1NeC-{cI$7@*2*4VVR16%Uv(va4gdfE literal 0 HcmV?d00001 diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_filemanager.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_filemanager.png new file mode 100644 index 0000000000000000000000000000000000000000..6f3bc7f850e03c77a0994a489cb6d5eb8722d4bb GIT binary patch literal 17805 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

fB$)6$V!8WB>m9AZh zvzdJ>Evh;Y3ScL2S&NLIR>{yWXoq`FQG4-LE4mIu?(kQ$HeWwIOIE3$ED#yI<5$B4 z)d$DSaqLq+WFXiS9^-5QYK(x%b%%8lqS?%Qk+;d_!V#I^coz|Y!K&*MN3rxq~|8B*>$PRVDmUn&sO%Ly=8l$8E??d z+|iQV79A&M|E(Asu%#(Z&V#rWjl@DEpLL{3B;6?p6D* z4of`?Uf&Kk@bs1`7w1O9D{|2zfriPnT2GVaMqY4>U8_v3q^>Wae5$lP1&F&n_`EBv-iVbU}0uotY6iH$IP~IDp*Xy~N5NICNT2$O~N(g!=_kj;_LNRHXR-E{i6o=+ zfYuLT@x)&pwYb9JKp#(HhiKKW;)iHyW6Put2~gOy+9PIIXC^m4R{8jYuwicMkM$Xn z2ru3#a6ccZ+(PpmTmB&3dBqImVzCRKrR`6zUAp0RatM#Ccq)ZN(S2`P%`7?Enb+N1 zL|3iLnNzBgkN$)my5jS(8Fn2~FlEz7DLnN7ZJg0r{z-j)eHnA6C^ zYUVJK5=5jq?;CkpZR^L7(2rthI3CXGH3vJSV+GWA=X*6&)uI|<=YTlDcDm9pcmon0bGCy zc~!D|v%-Mf%LL$d#?)I_!RF60q#ug?fT1U_10;(xisdlfP!wU15s{r6l3a;yFRF5^NT9o zc%6fouuM<$iMMVlg-*w&5Xr7P^uE>*qG^r5Dz#w&tZ3lH68DoQuBYR=W-k!)bT%&# z-CadFGhSV2+(ClV~>XR%(b2*LSi{rAoMCYH% zic(qf&x#^GgIkEb9j^=a&<9ZDjYXX}m(^iczKWhZn$b4&2($Jg1+%+tCR8B@drp1= zX)oNBp7Cc4N&WG8?P|#arcP5G83wMR(RY~?GM-b9hSbX+Y_Dx2MKB>|$02xu-stZU z=5l=r$~J?bybEf74@yMtXHP6g9~PFfD1H2aS>H;PQ^y0iGb|zNh}OKsrw7?!-P+$V z7~WSHL+tPcww0XMF!>L^2ACWtzebvc%o&jJNWeu}0rvurh_5GtNU<#i?xr?*+F&2!$cn+At z0b%~m?*BKyFittx-xU7`;J`nCc=gBoXTdQr@Q;ehN`k028q`v)A`RhO0BTgpbo);_ z+WniM&`*`p49&T5oEwB0AOuV2{@rZ@2nXA0dcAUFj@t$ z`dn7dN_n9N#@|*77yz(Ou1Kl$=Y)<)idq9u{zW)fp#y1k9AHq8!CsC@`~|t7n)@)o z^ElD~EGXVNu0tu&f*oRA&!q86}(C~sgDNmFu;mKVTC;=)}0>4KD=TGCSK|VX2q?S127}zuQ$abrg z9RTG_)f~A2B{*hkic|Lo33}RBn}Z^y?AggxG)^e!0*62sn1ETca|fxx;D}Rww4D3B zPh1I>M`wO)-J;wXyj$E}GWWq7{3J~wlW-JBPyEr&*FAW*@qzG?{=O)2F6wd29q=oS zk5M0fL4755skF6}B<-t@ZcS4J7o*Bkztf&|Q)sT+CC14X@Yq;d`g*0MGjkMw@vAkqGfCy3D>w$~qi#tA_A4V;OB{&t+d^<%+;V}iuV z>l1rGTVvv02sv4eUD*};=^xN!j>G+h@(xyAQsaEJkZ!;30G#75I|6LKquB|=FNHt~ zcrbwDUyv0C%KzK#|IKf6l7TqiNBvD`8vy(#0PjEC{yR*#O<_B>a7_Adm~flIpH{v- zJKGn|^7Fm^z%aEGy+p{g2L(bz$qeGqm8nQ@4yhlUdc~l}#IAw>SHF0HRqovEtZ-?& zdX(|*T*&ND&$ozmutDblq^ zM8)zGNj<$K+=t^?1WuK9K??l{OryCwlRTis>F)wUKmJY0#+TF4o5dEdWr>P4qOz z|M4|-M5Zpw(Tw5l1ES(Wbwtdla_37$A1cZ*vAY%=KPBs~08^VSPwrhBV%6pFX;K@vwt)+jMK1)Xuaf;vnE&pnu8a6W z%79$#*Er{(7hJ#}h$NlpA!m8yHJxa;oHdR=ynWX^ zP$ZQhq)AICxqMwz^=<`l+JwH2=FB-57Xy?8L4hU}=fNzt4G-@{ten7toh>1X$k|E% z(f&X>3ViEd*8kn2xBGrK-+yz6|1jV06#ro(`v; + + + + + + + + Files + + + Files deleted + + + Delete files? + + + Copy + + Cut + + Paste + + + + + The file has been put in the clipboard + %d files have been put in the clipboard + + + + + The file has been pasted. Upload might be finishing in background. + %d files have been pasted. Upload might be finishing in background. + + + + Copying... + + + Deleting... + + + This file will be permanently deleted! + This will permanently delete the %d files selected! + + + OK + Cancel + \ No newline at end of file diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 39c2252799d3f..bdb6ce4ba0a30 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -12,6 +12,20 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Per article 5 of the Apache 2.0 License, some modifications to this code + * were made by the OmniROM Project. + * + * Modifications Copyright (C) 2013 The OmniROM Project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.android.documentsui; @@ -19,6 +33,7 @@ import static com.android.documentsui.DocumentsActivity.TAG; import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE; import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE; +import static com.android.documentsui.DocumentsActivity.State.ACTION_STANDALONE; import static com.android.documentsui.DocumentsActivity.State.MODE_GRID; import static com.android.documentsui.DocumentsActivity.State.MODE_LIST; import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN; @@ -28,14 +43,17 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString; import android.app.ActivityManager; +import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; +import android.app.ProgressDialog; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; import android.content.res.Resources; @@ -84,7 +102,10 @@ import com.google.android.collect.Lists; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.Executor; /** * Display the documents inside a single directory. @@ -463,11 +484,16 @@ public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 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 MenuItem copy = menu.findItem(R.id.menu_copy); + final MenuItem cut = menu.findItem(R.id.menu_cut); final boolean manageMode = state.action == ACTION_MANAGE; - open.setVisible(!manageMode); - share.setVisible(manageMode); - delete.setVisible(manageMode); + final boolean stdMode = state.action == ACTION_STANDALONE; + open.setVisible(!manageMode && !stdMode); + share.setVisible(manageMode || stdMode); + delete.setVisible(manageMode || stdMode); + copy.setVisible(stdMode); + cut.setVisible(stdMode); return true; } @@ -501,6 +527,16 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) { mode.finish(); return true; + } else if (id == R.id.menu_copy) { + onCopyDocuments(docs); + mode.finish(); + return true; + + } else if (id == R.id.menu_cut) { + onCutDocuments(docs); + mode.finish(); + return true; + } else { return false; } @@ -517,16 +553,29 @@ public void onItemCheckedStateChanged( if (checked) { // Directories and footer items cannot be checked boolean valid = false; + boolean hasFolder = false; final Cursor cursor = mAdapter.getItem(position); if (cursor != null) { final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); - if (!Document.MIME_TYPE_DIR.equals(docMimeType)) { + final State state = getDisplayState(DirectoryFragment.this); + if (Document.MIME_TYPE_DIR.equals(docMimeType)) { + hasFolder = true; + } + if (!Document.MIME_TYPE_DIR.equals(docMimeType) || state.action == ACTION_STANDALONE) { valid = isDocumentEnabled(docMimeType, docFlags); } } + if (hasFolder) { + final Menu menu = mode.getMenu(); + final MenuItem copy = menu.findItem(R.id.menu_copy); + final MenuItem cut = menu.findItem(R.id.menu_cut); + copy.setVisible(false); + cut.setVisible(false); + } + if (!valid) { mCurrentView.setItemChecked(position, false); } @@ -585,7 +634,33 @@ private void onShareDocuments(List docs) { startActivity(intent); } - private void onDeleteDocuments(List docs) { + private void onDeleteDocuments(final List docs) { + final Context context = getActivity(); + final ContentResolver resolver = context.getContentResolver(); + final Resources resources = context.getResources(); + + // Open a confirmation dialog + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + + builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + new DeleteFilesTask(docs.toArray(new DocumentInfo[0])).executeOnExecutor(getCurrentExecutor()); + } + }); + builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog, ignore actions + } + }); + + builder.setTitle(R.string.dialog_delete_confirm_title) + .setMessage(resources.getQuantityString(R.plurals.dialog_delete_confirm_message, docs.size(), docs.size())); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private boolean onDeleteDocumentsImpl(final List docs) { final Context context = getActivity(); final ContentResolver resolver = context.getContentResolver(); @@ -601,6 +676,33 @@ private void onDeleteDocuments(List docs) { try { client = DocumentsApplication.acquireUnstableProviderOrThrow( resolver, doc.derivedUri.getAuthority()); + + if (Document.MIME_TYPE_DIR.equals(doc.mimeType)) { + // In order to delete a directory, we must delete its contents first. We + // recursively do so. + Uri contentsUri = DocumentsContract.buildChildDocumentsUri( + doc.authority, doc.documentId); + final RootInfo root = getArguments().getParcelable(EXTRA_ROOT); + + // We get the contents of the directory + DirectoryLoader loader = new DirectoryLoader( + context, mType, root, doc, contentsUri, SORT_ORDER_UNKNOWN); + + DirectoryResult result = loader.loadInBackground(); + Cursor cursor = result.cursor; + + // Build a list of the docs to delete, and delete them + ArrayList docsToDelete = new ArrayList(); + for (int i = 0; i < cursor.getCount(); i++) { + cursor.moveToPosition(i); + final DocumentInfo subDoc = DocumentInfo.fromDirectoryCursor(cursor); + docsToDelete.add(subDoc); + } + + onDeleteDocumentsImpl(docsToDelete); + } + + DocumentsContract.deleteDocument(client, doc.derivedUri); } catch (Exception e) { Log.w(TAG, "Failed to delete " + doc); @@ -610,9 +712,15 @@ private void onDeleteDocuments(List docs) { } } - if (hadTrouble) { - Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); - } + return !hadTrouble; + } + + private void onCopyDocuments(final List docs) { + ((DocumentsActivity) getActivity()).setClipboardDocuments(docs, true); + } + + private void onCutDocuments(final List docs) { + ((DocumentsActivity) getActivity()).setClipboardDocuments(docs, false); } private static State getDisplayState(Fragment fragment) { @@ -989,6 +1097,45 @@ public int getItemViewType(int position) { } } + private class DeleteFilesTask extends AsyncTask { + private final DocumentInfo[] mDocs; + private ProgressDialog mProgressDialog; + + public DeleteFilesTask(DocumentInfo... docs) { + mDocs = docs; + mProgressDialog = new ProgressDialog(getActivity()); + mProgressDialog.setMessage(getString(R.string.delete_in_progress)); + mProgressDialog.setIndeterminate(true); + mProgressDialog.setCanceledOnTouchOutside(false); + + mProgressDialog.show(); + } + + @Override + protected Boolean doInBackground(Void... params) { + ArrayList docs = new ArrayList(); + Collections.addAll(docs, mDocs); + boolean result = onDeleteDocumentsImpl(docs); + + return result; + } + + @Override + protected void onPostExecute(Boolean result) { + mProgressDialog.dismiss(); + + if (result == false) { + Toast.makeText(getActivity(), R.string.toast_failed_delete, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getActivity(), R.string.toast_success_delete, Toast.LENGTH_SHORT).show(); + } + + // Reload files in the current folder + getLoaderManager().restartLoader(mLoaderId, null, mCallbacks); + updateDisplayState(); + } + } + private static class ThumbnailAsyncTask extends AsyncTask implements Preemptable { private final Uri mUri; @@ -1129,4 +1276,8 @@ private boolean isDocumentEnabled(String docMimeType, int docFlags) { return MimePredicate.mimeMatches(state.acceptMimes, docMimeType); } + + public Executor getCurrentExecutor() { + return ((DocumentsActivity) getActivity()).getCurrentExecutor(); + } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index fef1f4a2871bf..aef2f1da74718 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Modifications Copyright (C) 2013 The OmniROM Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +13,20 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * + * Per article 5 of the Apache 2.0 License, some modifications to this code + * were made by the OmniROM Project. + * + * Modifications Copyright (C) 2013 The OmniROM Project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.android.documentsui; @@ -25,12 +40,14 @@ import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE; import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN; import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN_TREE; +import static com.android.documentsui.DocumentsActivity.State.ACTION_STANDALONE; import static com.android.documentsui.DocumentsActivity.State.MODE_GRID; import static com.android.documentsui.DocumentsActivity.State.MODE_LIST; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; +import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ComponentName; @@ -83,9 +100,15 @@ import libcore.io.IoUtils; +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Arrays; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -122,6 +145,10 @@ public class DocumentsActivity extends Activity { private RootsCache mRoots; private State mState; + private List mClipboardFiles; + /* true if copy, false if cut */ + private boolean mClipboardIsCopy; + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -204,14 +231,18 @@ public void onCreate(Bundle icicle) { moreApps.setPackage(null); RootsFragment.show(getFragmentManager(), moreApps); } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE - || mState.action == ACTION_OPEN_TREE) { + || mState.action == ACTION_OPEN_TREE || mState.action == ACTION_STANDALONE) { RootsFragment.show(getFragmentManager(), null); } if (!mState.restored) { if (mState.action == ACTION_MANAGE) { final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); + if (rootUri != null) { + new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); + } else { + new RestoreStackTask().execute(); + } } else { new RestoreStackTask().execute(); } @@ -235,11 +266,15 @@ private void buildDefaultState() { mState.action = ACTION_OPEN_TREE; } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) { mState.action = ACTION_MANAGE; + } else if (Intent.ACTION_MAIN.equals(action)) { + mState.action = ACTION_STANDALONE; } if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { mState.allowMultiple = intent.getBooleanExtra( Intent.EXTRA_ALLOW_MULTIPLE, false); + } else if (mState.action == ACTION_STANDALONE) { + mState.allowMultiple = true; } if (mState.action == ACTION_MANAGE) { @@ -413,6 +448,8 @@ public void updateActionBar() { mRootsToolbar.setTitle(R.string.title_open); } else if (mState.action == ACTION_CREATE) { mRootsToolbar.setTitle(R.string.title_save); + } else if (mState.action == ACTION_STANDALONE) { + mRootsToolbar.setTitle(R.string.title_standalone); } } @@ -548,6 +585,12 @@ public boolean onPrepareOptionsMenu(Menu menu) { final MenuItem list = menu.findItem(R.id.menu_list); final MenuItem advanced = menu.findItem(R.id.menu_advanced); final MenuItem fileSize = menu.findItem(R.id.menu_file_size); + final MenuItem paste = menu.findItem(R.id.menu_paste); + + // Paste is visible only if we have files in the clipboard, and if + // we can paste in this directory + paste.setVisible(mClipboardFiles != null && mClipboardFiles.size() > 0 + && cwd != null && cwd.isCreateSupported()); sort.setVisible(cwd != null); grid.setVisible(mState.derivedMode != MODE_GRID); @@ -575,7 +618,9 @@ public boolean onPrepareOptionsMenu(Menu menu) { sortSize.setVisible(mState.showSize); final boolean searchVisible; - if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) { + if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE + || mState.action == ACTION_STANDALONE) { + createDir.setVisible(cwd != null && cwd.isCreateSupported()); searchVisible = false; @@ -622,6 +667,9 @@ public boolean onOptionsItemSelected(MenuItem item) { } else if (id == R.id.menu_create_dir) { CreateDirectoryFragment.show(getFragmentManager()); return true; + } else if (id == R.id.menu_paste) { + onPasteRequested(); + return true; } else if (id == R.id.menu_search) { return false; } else if (id == R.id.menu_sort_name) { @@ -867,7 +915,7 @@ private void onCurrentDirectoryChanged(int anim) { } // Forget any replacement target - if (mState.action == ACTION_CREATE) { + if (mState.action == ACTION_CREATE || mState.action == ACTION_STANDALONE) { final SaveFragment save = SaveFragment.get(fm); if (save != null) { save.setReplaceTarget(null); @@ -1015,6 +1063,16 @@ public void onDocumentPicked(DocumentInfo doc) { Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); } } + } else if (mState.action == ACTION_STANDALONE) { + final Intent view = new Intent(Intent.ACTION_VIEW); + view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + view.setData(doc.derivedUri); + + try { + startActivity(view); + } catch (ActivityNotFoundException ex2) { + Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); + } } } @@ -1029,6 +1087,30 @@ public void onDocumentsPicked(List docs) { } } + public void setClipboardDocuments(List docs, boolean copy) { + mClipboardFiles = docs; + mClipboardIsCopy = copy; + final Resources r = getResources(); + Toast.makeText(this, + r.getQuantityString(R.plurals.files_copied, docs.size(), docs.size()), + Toast.LENGTH_SHORT).show(); + + // Update the action bar buttons + invalidateOptionsMenu(); + } + + public void onPasteRequested() { + if (mClipboardFiles == null) { + return; + } + + // Run the corresponding asynctask + new CopyOrCutFilesTask(mClipboardFiles.toArray(new DocumentInfo[0])).executeOnExecutor(getCurrentExecutor()); + + // Clear the copy buffer + mClipboardFiles = null; + } + public void onSaveRequested(DocumentInfo replaceTarget) { new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); } @@ -1096,6 +1178,17 @@ private void onFinished(Uri... uris) { finish(); } + public void copyFile(Uri input, Uri output) throws IOException { + OutputStream os = getContentResolver().openOutputStream(output); + InputStream is = getContentResolver().openInputStream(input); + + byte[] buffer = new byte[1024]; + int len; + while ((len = is.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + } + private class CreateFinishTask extends AsyncTask { private final String mMimeType; private final String mDisplayName; @@ -1148,6 +1241,91 @@ protected void onPostExecute(Uri result) { } } + private class CopyOrCutFilesTask extends AsyncTask { + private final DocumentInfo[] mDocs; + private boolean mIsCopy; + private ProgressDialog mProgressDialog; + + public CopyOrCutFilesTask(DocumentInfo... docs) { + mDocs = docs; + mIsCopy = mClipboardIsCopy; + mProgressDialog = new ProgressDialog(DocumentsActivity.this); + mProgressDialog.setMessage(getString(R.string.copy_in_progress)); + mProgressDialog.setIndeterminate(false); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + mProgressDialog.setMax(docs.length); + mProgressDialog.setProgress(0); + mProgressDialog.setCanceledOnTouchOutside(false); + + mProgressDialog.show(); + } + + @Override + protected Void doInBackground(Void... params) { + final ContentResolver resolver = getContentResolver(); + ContentProviderClient client = null; + + int count = 0; + for (DocumentInfo doc : mDocs) { + try { + final DocumentInfo cwd = getCurrentDirectory(); + client = DocumentsApplication.acquireUnstableProviderOrThrow( + resolver, cwd.derivedUri.getAuthority()); + + // Create a new file of the same MIME type as the original + final Uri childUri = DocumentsContract.createDocument( + client, cwd.derivedUri, doc.mimeType, doc.displayName); + + ContentProviderClient.releaseQuietly(client); + + if (childUri == null) { + Log.e(TAG, "Failed to create a new document (uri is null)"); + continue; + } + + final DocumentInfo copy = DocumentInfo.fromUri(resolver, childUri); + + // Push data to the new file + copyFile(doc.derivedUri, copy.derivedUri); + + // If we cut, delete the original file + if (!mIsCopy) { + DocumentsContract.deleteDocument(client, doc.derivedUri); + } + + count++; + publishProgress((Integer) count); + } catch (Exception e) { + Log.w(TAG, "Failed to copy " + doc, e); + } + } + + return null; + } + + protected void onProgressUpdate(Integer... progress) { + mProgressDialog.setProgress(progress[0]); + } + + @Override + protected void onPostExecute(Void result) { + mProgressDialog.dismiss(); + + // Notify that files were copied + final Resources r = getResources(); + Toast.makeText(DocumentsActivity.this, + r.getQuantityString(R.plurals.files_pasted, mDocs.length, mDocs.length), + Toast.LENGTH_SHORT).show(); + + // Update the action bar buttons + invalidateOptionsMenu(); + + // Hack to refresh the contents. + DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged(); + } + } + + private class ExistingFinishTask extends AsyncTask { private final Uri[] mUris; @@ -1221,6 +1399,7 @@ public static class State implements android.os.Parcelable { public static final int ACTION_GET_CONTENT = 3; public static final int ACTION_OPEN_TREE = 4; public static final int ACTION_MANAGE = 5; + public static final int ACTION_STANDALONE = 6; public static final int MODE_UNKNOWN = 0; public static final int MODE_LIST = 1;