Merge "Populate quick view intent w/ file uris."
This commit is contained in:
@@ -3815,6 +3815,9 @@ public class Intent implements Parcelable, Cloneable {
|
||||
public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
|
||||
"android.intent.extra.SIM_ACTIVATION_RESPONSE";
|
||||
|
||||
/** {@hide} */
|
||||
public static final String EXTRA_INDEX = "android.intent.extra.INDEX";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
// Intent flags (see mFlags variable).
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
@@ -79,8 +82,9 @@ abstract class BaseActivity extends Activity {
|
||||
private final String mTag;
|
||||
|
||||
public abstract State getDisplayState();
|
||||
public abstract void onDocumentPicked(DocumentInfo doc);
|
||||
public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
|
||||
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
|
||||
|
||||
abstract void onTaskFinished(Uri... uris);
|
||||
abstract void onDirectoryChanged(int anim);
|
||||
abstract void updateActionBar();
|
||||
@@ -258,6 +262,17 @@ abstract class BaseActivity extends Activity {
|
||||
&& !root.isDownloads();
|
||||
}
|
||||
|
||||
void onDirectoryCreated(DocumentInfo doc) {
|
||||
checkArgument(doc.isDirectory());
|
||||
openDirectory(doc);
|
||||
}
|
||||
|
||||
void openDirectory(DocumentInfo doc) {
|
||||
getDisplayState().stack.push(doc);
|
||||
getDisplayState().stackTouched = true;
|
||||
onCurrentDirectoryChanged(ANIM_DOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when directory changes. Prior to root fragment update
|
||||
* the (abstract) directoryChanged method will be called.
|
||||
@@ -605,7 +620,6 @@ abstract class BaseActivity extends Activity {
|
||||
if (isDestroyed()) return;
|
||||
getDisplayState().restored = true;
|
||||
onCurrentDirectoryChanged(ANIM_NONE);
|
||||
|
||||
onStackRestored(mRestoredStack, mExternal);
|
||||
}
|
||||
}
|
||||
@@ -843,4 +857,17 @@ abstract class BaseActivity extends Activity {
|
||||
updateActionBar();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface providing access to current view of documents
|
||||
* even when all documents are not homed to the same parent.
|
||||
*/
|
||||
interface DocumentContext {
|
||||
/**
|
||||
* Returns the cursor for the selected document. The cursor can be used to retrieve
|
||||
* details about a document and its siblings.
|
||||
* @return
|
||||
*/
|
||||
Cursor getCursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public class CreateDirectoryFragment extends DialogFragment {
|
||||
protected void onPostExecute(DocumentInfo result) {
|
||||
if (result != null) {
|
||||
// Navigate into newly created child
|
||||
mActivity.onDocumentPicked(result);
|
||||
mActivity.onDirectoryCreated(result);
|
||||
} else {
|
||||
Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.documentsui.BaseActivity.DocumentContext;
|
||||
import com.android.documentsui.BaseActivity.State;
|
||||
import com.android.documentsui.MultiSelectManager.Selection;
|
||||
import com.android.documentsui.ProviderExecutor.Preemptable;
|
||||
@@ -457,7 +458,7 @@ public class DirectoryFragment extends Fragment {
|
||||
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
|
||||
if (isDocumentEnabled(docMimeType, docFlags)) {
|
||||
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
|
||||
((BaseActivity) getActivity()).onDocumentPicked(doc);
|
||||
((BaseActivity) getActivity()).onDocumentPicked(doc, mAdapter);
|
||||
mSelectionManager.clearSelection();
|
||||
return true;
|
||||
}
|
||||
@@ -949,7 +950,8 @@ public class DirectoryFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
|
||||
private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder>
|
||||
implements DocumentContext {
|
||||
|
||||
private final Context mContext;
|
||||
private final LayoutInflater mInflater;
|
||||
@@ -1213,6 +1215,14 @@ public class DirectoryFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor getCursor() {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
throw new IllegalStateException("Can't call getCursor from non-main thread.");
|
||||
}
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
private Cursor getItem(int position) {
|
||||
if (position < mCursorCount) {
|
||||
mCursor.moveToPosition(position);
|
||||
|
||||
@@ -26,12 +26,8 @@ import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
|
||||
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
@@ -608,12 +604,10 @@ public class DocumentsActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDocumentPicked(DocumentInfo doc) {
|
||||
public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
|
||||
final FragmentManager fm = getFragmentManager();
|
||||
if (doc.isDirectory()) {
|
||||
mState.stack.push(doc);
|
||||
mState.stackTouched = true;
|
||||
onCurrentDirectoryChanged(ANIM_DOWN);
|
||||
openDirectory(doc);
|
||||
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||
// Explicit file picked, return
|
||||
new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import static com.android.documentsui.model.DocumentInfo.getCursorString;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.documentsui.BaseActivity.DocumentContext;
|
||||
import com.android.documentsui.model.DocumentInfo;
|
||||
|
||||
/**
|
||||
* Provides support for gather a list of quick-viewable files into a quick view intent.
|
||||
*/
|
||||
final class QuickViewIntentBuilder {
|
||||
|
||||
private static final String TAG = "QvIntentBuilder";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final DocumentInfo mDocument;
|
||||
private final DocumentContext mContext;
|
||||
|
||||
public ClipData mClipData;
|
||||
public int mDocumentLocation;
|
||||
private PackageManager mPkgManager;
|
||||
|
||||
public QuickViewIntentBuilder(
|
||||
PackageManager pkgManager, DocumentInfo doc, DocumentContext context) {
|
||||
mPkgManager = pkgManager;
|
||||
mDocument = doc;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the intent for quick viewing. Short circuits building if a handler cannot
|
||||
* be resolved; in this case {@code null} is returned.
|
||||
*/
|
||||
@Nullable Intent build() {
|
||||
if (DEBUG) Log.d(TAG, "Preparing intent for doc:" + mDocument.documentId);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
|
||||
intent.setDataAndType(mDocument.derivedUri, mDocument.mimeType);
|
||||
|
||||
// Try to resolve the intent. If a matching app isn't installed, it won't resolve.
|
||||
ComponentName handler = intent.resolveActivity(mPkgManager);
|
||||
if (handler == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Cursor cursor = mContext.getCursor();
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
onNextItem(i, cursor);
|
||||
}
|
||||
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.putExtra(Intent.EXTRA_INDEX, mDocumentLocation);
|
||||
intent.setClipData(mClipData);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
private void onNextItem(int index, Cursor cursor) {
|
||||
cursor.moveToPosition(index);
|
||||
|
||||
String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
|
||||
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String id = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
|
||||
String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
|
||||
Uri uri = DocumentsContract.buildDocumentUri(authority, id);
|
||||
if (DEBUG) Log.d(TAG, "Including file[" + id + "] @ " + uri);
|
||||
|
||||
if (id.equals(mDocument.documentId)) {
|
||||
if (DEBUG) Log.d(TAG, "Found starting point for QV. " + index);
|
||||
mDocumentLocation = index;
|
||||
}
|
||||
|
||||
ClipData.Item item = new ClipData.Item(uri);
|
||||
if (mClipData == null) {
|
||||
mClipData = new ClipData(
|
||||
"URIs", new String[]{ClipDescription.MIMETYPE_TEXT_URILIST}, item);
|
||||
} else {
|
||||
mClipData.addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ClipData;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
@@ -61,6 +60,7 @@ import java.util.List;
|
||||
public class StandaloneActivity extends BaseActivity {
|
||||
|
||||
public static final String TAG = "StandaloneFileManagement";
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
private Toolbar mToolbar;
|
||||
private Spinner mToolbarStack;
|
||||
@@ -284,31 +284,41 @@ public class StandaloneActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDocumentPicked(DocumentInfo doc) {
|
||||
if (doc.isDirectory()) {
|
||||
openFolder(doc);
|
||||
} else {
|
||||
openDocument(doc);
|
||||
}
|
||||
public void onDocumentsPicked(List<DocumentInfo> docs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void openFolder(DocumentInfo doc) {
|
||||
mState.stack.push(doc);
|
||||
mState.stackTouched = true;
|
||||
onCurrentDirectoryChanged(ANIM_DOWN);
|
||||
@Override
|
||||
public void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings) {
|
||||
if (doc.isDirectory()) {
|
||||
openDirectory(doc);
|
||||
} else {
|
||||
openDocument(doc, siblings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches an intent to view the specified document.
|
||||
*/
|
||||
private void openDocument(DocumentInfo doc) {
|
||||
Intent intent = getQuickViewIntent(doc);
|
||||
private void openDocument(DocumentInfo doc, @Nullable DocumentContext siblings) {
|
||||
Intent intent = null;
|
||||
if (siblings != null) {
|
||||
QuickViewIntentBuilder builder =
|
||||
new QuickViewIntentBuilder(getPackageManager(), doc, siblings);
|
||||
intent = builder.build();
|
||||
}
|
||||
|
||||
// fallback to traditional VIEW action...
|
||||
if (intent == null) {
|
||||
intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setData(doc.derivedUri);
|
||||
}
|
||||
|
||||
if (DEBUG && intent.getClipData() != null) {
|
||||
Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
|
||||
}
|
||||
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (ActivityNotFoundException ex2) {
|
||||
@@ -316,24 +326,6 @@ public class StandaloneActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Intent getQuickViewIntent(DocumentInfo doc) {
|
||||
Intent intent = new Intent(Intent.ACTION_QUICK_VIEW);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setData(doc.derivedUri);
|
||||
|
||||
ComponentName handler = intent.resolveActivity(getPackageManager());
|
||||
if (handler != null) {
|
||||
return intent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDocumentsPicked(List<DocumentInfo> docs) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyShortcut(int keyCode, KeyEvent event) {
|
||||
DirectoryFragment dir;
|
||||
|
||||
Reference in New Issue
Block a user