am c22acf6f: Merge "Instance state, fix sharing, Durable objects." into klp-dev
* commit 'c22acf6f1fc001ad0f1c23c5261f371d63e4106e': Instance state, fix sharing, Durable objects.
This commit is contained in:
@@ -11,10 +11,7 @@
|
|||||||
<!-- TODO: allow rotation when state saving is in better shape -->
|
<!-- TODO: allow rotation when state saving is in better shape -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".DocumentsActivity"
|
android:name=".DocumentsActivity"
|
||||||
android:finishOnCloseSystemDialogs="true"
|
android:theme="@android:style/Theme.Holo.Light">
|
||||||
android:excludeFromRecents="true"
|
|
||||||
android:theme="@android:style/Theme.Holo.Light"
|
|
||||||
android:screenOrientation="nosensor">
|
|
||||||
<intent-filter android:priority="100">
|
<intent-filter android:priority="100">
|
||||||
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
<action android:name="android.intent.action.OPEN_DOCUMENT" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
@@ -37,7 +34,7 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.provider.action.MANAGE_DOCUMENTS" />
|
<action android:name="android.provider.action.MANAGE_DOCUMENTS" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="vnd.android.doc/dir" />
|
<data android:mimeType="vnd.android.document/directory" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|||||||
@@ -63,4 +63,6 @@
|
|||||||
<string name="more">More</string>
|
<string name="more">More</string>
|
||||||
<string name="loading">Loading\u2026</string>
|
<string name="loading">Loading\u2026</string>
|
||||||
|
|
||||||
|
<string name="share_via">Share via</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
package com.android.documentsui;
|
package com.android.documentsui;
|
||||||
|
|
||||||
import static com.android.documentsui.DocumentsActivity.TAG;
|
import static com.android.documentsui.DocumentsActivity.TAG;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
|
import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
|
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
|
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
|
||||||
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
|
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
|
||||||
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
|
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
|
||||||
import static com.android.documentsui.model.DocumentInfo.getCursorString;
|
import static com.android.documentsui.model.DocumentInfo.getCursorString;
|
||||||
@@ -62,7 +62,7 @@ import android.widget.ListView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.documentsui.DocumentsActivity.DisplayState;
|
import com.android.documentsui.DocumentsActivity.State;
|
||||||
import com.android.documentsui.model.DocumentInfo;
|
import com.android.documentsui.model.DocumentInfo;
|
||||||
import com.android.internal.util.Predicate;
|
import com.android.internal.util.Predicate;
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
@@ -168,7 +168,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
|
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
|
||||||
@Override
|
@Override
|
||||||
public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
|
public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
|
||||||
final DisplayState state = getDisplayState(DirectoryFragment.this);
|
final State state = getDisplayState(DirectoryFragment.this);
|
||||||
|
|
||||||
Uri contentsUri;
|
Uri contentsUri;
|
||||||
if (mType == TYPE_NORMAL) {
|
if (mType == TYPE_NORMAL) {
|
||||||
@@ -196,7 +196,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateDisplayState() {
|
public void updateDisplayState() {
|
||||||
final DisplayState state = getDisplayState(this);
|
final State state = getDisplayState(this);
|
||||||
|
|
||||||
if (mLastSortOrder != state.sortOrder) {
|
if (mLastSortOrder != state.sortOrder) {
|
||||||
getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
|
getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
|
||||||
@@ -263,7 +263,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||||
final DisplayState state = getDisplayState(DirectoryFragment.this);
|
final State state = getDisplayState(DirectoryFragment.this);
|
||||||
|
|
||||||
final MenuItem open = menu.findItem(R.id.menu_open);
|
final MenuItem open = menu.findItem(R.id.menu_open);
|
||||||
final MenuItem share = menu.findItem(R.id.menu_share);
|
final MenuItem share = menu.findItem(R.id.menu_share);
|
||||||
@@ -294,14 +294,17 @@ public class DirectoryFragment extends Fragment {
|
|||||||
final int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
if (id == R.id.menu_open) {
|
if (id == R.id.menu_open) {
|
||||||
DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
|
DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
|
||||||
|
mode.finish();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else if (id == R.id.menu_share) {
|
} else if (id == R.id.menu_share) {
|
||||||
onShareDocuments(docs);
|
onShareDocuments(docs);
|
||||||
|
mode.finish();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else if (id == R.id.menu_delete) {
|
} else if (id == R.id.menu_delete) {
|
||||||
onDeleteDocuments(docs);
|
onDeleteDocuments(docs);
|
||||||
|
mode.finish();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -332,26 +335,36 @@ public class DirectoryFragment extends Fragment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void onShareDocuments(List<DocumentInfo> docs) {
|
private void onShareDocuments(List<DocumentInfo> docs) {
|
||||||
final ArrayList<Uri> uris = Lists.newArrayList();
|
Intent intent;
|
||||||
for (DocumentInfo doc : docs) {
|
if (docs.size() == 1) {
|
||||||
uris.add(doc.uri);
|
final DocumentInfo doc = docs.get(0);
|
||||||
}
|
|
||||||
|
|
||||||
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 = new Intent(Intent.ACTION_SEND);
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
intent.setData(uris.get(0));
|
intent.setType(doc.mimeType);
|
||||||
|
intent.putExtra(Intent.EXTRA_STREAM, doc.uri);
|
||||||
|
|
||||||
|
} else if (docs.size() > 1) {
|
||||||
|
intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
intent.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
|
||||||
|
final ArrayList<String> mimeTypes = Lists.newArrayList();
|
||||||
|
final ArrayList<Uri> uris = Lists.newArrayList();
|
||||||
|
for (DocumentInfo doc : docs) {
|
||||||
|
mimeTypes.add(doc.mimeType);
|
||||||
|
uris.add(doc.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
intent.setType(findCommonMimeType(mimeTypes));
|
||||||
|
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +396,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DisplayState getDisplayState(Fragment fragment) {
|
private static State getDisplayState(Fragment fragment) {
|
||||||
return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
|
return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +424,7 @@ public class DirectoryFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
final Context context = parent.getContext();
|
final Context context = parent.getContext();
|
||||||
final DisplayState state = getDisplayState(DirectoryFragment.this);
|
final State state = getDisplayState(DirectoryFragment.this);
|
||||||
|
|
||||||
final RootsCache roots = DocumentsApplication.getRootsCache(context);
|
final RootsCache roots = DocumentsApplication.getRootsCache(context);
|
||||||
final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
|
final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
|
||||||
@@ -586,4 +599,28 @@ public class DirectoryFragment extends Fragment {
|
|||||||
|
|
||||||
return DateUtils.formatDateTime(context, when, flags);
|
return DateUtils.formatDateTime(context, when, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String findCommonMimeType(List<String> mimeTypes) {
|
||||||
|
String[] commonType = mimeTypes.get(0).split("/");
|
||||||
|
if (commonType.length != 2) {
|
||||||
|
return "*/*";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < mimeTypes.size(); i++) {
|
||||||
|
String[] type = mimeTypes.get(i).split("/");
|
||||||
|
if (type.length != 2) continue;
|
||||||
|
|
||||||
|
if (!commonType[1].equals(type[1])) {
|
||||||
|
commonType[1] = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commonType[0].equals(type[0])) {
|
||||||
|
commonType[0] = "*";
|
||||||
|
commonType[1] = "*";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commonType[0] + "/" + commonType[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.documentsui;
|
package com.android.documentsui;
|
||||||
|
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
|
||||||
|
|
||||||
import android.content.AsyncTaskLoader;
|
import android.content.AsyncTaskLoader;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -25,8 +29,6 @@ import android.os.CancellationSignal;
|
|||||||
import android.os.OperationCanceledException;
|
import android.os.OperationCanceledException;
|
||||||
import android.provider.DocumentsContract.Document;
|
import android.provider.DocumentsContract.Document;
|
||||||
|
|
||||||
import com.android.documentsui.DocumentsActivity.DisplayState;
|
|
||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
class DirectoryResult implements AutoCloseable {
|
class DirectoryResult implements AutoCloseable {
|
||||||
@@ -149,11 +151,11 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
|
|||||||
|
|
||||||
private String getQuerySortOrder() {
|
private String getQuerySortOrder() {
|
||||||
switch (mSortOrder) {
|
switch (mSortOrder) {
|
||||||
case DisplayState.SORT_ORDER_DISPLAY_NAME:
|
case SORT_ORDER_DISPLAY_NAME:
|
||||||
return Document.COLUMN_DISPLAY_NAME + " ASC";
|
return Document.COLUMN_DISPLAY_NAME + " ASC";
|
||||||
case DisplayState.SORT_ORDER_LAST_MODIFIED:
|
case SORT_ORDER_LAST_MODIFIED:
|
||||||
return Document.COLUMN_LAST_MODIFIED + " DESC";
|
return Document.COLUMN_LAST_MODIFIED + " DESC";
|
||||||
case DisplayState.SORT_ORDER_SIZE:
|
case SORT_ORDER_SIZE:
|
||||||
return Document.COLUMN_SIZE + " DESC";
|
return Document.COLUMN_SIZE + " DESC";
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
package com.android.documentsui;
|
package com.android.documentsui;
|
||||||
|
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_CREATE;
|
import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_GET_CONTENT;
|
import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_MANAGE;
|
import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.ACTION_OPEN;
|
import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_GRID;
|
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.MODE_LIST;
|
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
|
||||||
import static com.android.documentsui.DocumentsActivity.DisplayState.SORT_ORDER_LAST_MODIFIED;
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
|
||||||
|
|
||||||
import android.app.ActionBar;
|
import android.app.ActionBar;
|
||||||
import android.app.ActionBar.OnNavigationListener;
|
import android.app.ActionBar.OnNavigationListener;
|
||||||
@@ -41,6 +41,7 @@ import android.database.Cursor;
|
|||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcel;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
import android.support.v4.app.ActionBarDrawerToggle;
|
import android.support.v4.app.ActionBarDrawerToggle;
|
||||||
import android.support.v4.view.GravityCompat;
|
import android.support.v4.view.GravityCompat;
|
||||||
@@ -61,31 +62,27 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.android.documentsui.model.DocumentInfo;
|
import com.android.documentsui.model.DocumentInfo;
|
||||||
import com.android.documentsui.model.DocumentStack;
|
import com.android.documentsui.model.DocumentStack;
|
||||||
|
import com.android.documentsui.model.DurableUtils;
|
||||||
import com.android.documentsui.model.RootInfo;
|
import com.android.documentsui.model.RootInfo;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DocumentsActivity extends Activity {
|
public class DocumentsActivity extends Activity {
|
||||||
public static final String TAG = "Documents";
|
public static final String TAG = "Documents";
|
||||||
|
|
||||||
private int mAction;
|
|
||||||
|
|
||||||
private SearchView mSearchView;
|
private SearchView mSearchView;
|
||||||
|
|
||||||
private View mRootsContainer;
|
private View mRootsContainer;
|
||||||
private DrawerLayout mDrawerLayout;
|
private DrawerLayout mDrawerLayout;
|
||||||
private ActionBarDrawerToggle mDrawerToggle;
|
private ActionBarDrawerToggle mDrawerToggle;
|
||||||
|
|
||||||
private final DisplayState mDisplayState = new DisplayState();
|
private static final String EXTRA_STATE = "state";
|
||||||
|
|
||||||
private RootsCache mRoots;
|
private RootsCache mRoots;
|
||||||
|
private State mState;
|
||||||
/** Current user navigation stack; empty implies recents. */
|
|
||||||
private DocumentStack mStack = new DocumentStack();
|
|
||||||
/** Currently active search, overriding any stack. */
|
|
||||||
private String mCurrentSearch;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
@@ -93,59 +90,9 @@ public class DocumentsActivity extends Activity {
|
|||||||
|
|
||||||
mRoots = DocumentsApplication.getRootsCache(this);
|
mRoots = DocumentsApplication.getRootsCache(this);
|
||||||
|
|
||||||
final Intent intent = getIntent();
|
|
||||||
final String action = intent.getAction();
|
|
||||||
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
|
|
||||||
mAction = ACTION_OPEN;
|
|
||||||
} else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
|
|
||||||
mAction = ACTION_CREATE;
|
|
||||||
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
|
|
||||||
mAction = ACTION_GET_CONTENT;
|
|
||||||
} else if (DocumentsContract.ACTION_MANAGE_DOCUMENTS.equals(action)) {
|
|
||||||
mAction = ACTION_MANAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: unify action in single place
|
|
||||||
mDisplayState.action = mAction;
|
|
||||||
|
|
||||||
if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
|
|
||||||
mDisplayState.allowMultiple = intent.getBooleanExtra(
|
|
||||||
Intent.EXTRA_ALLOW_MULTIPLE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAction == ACTION_MANAGE) {
|
|
||||||
mDisplayState.acceptMimes = new String[] { "*/*" };
|
|
||||||
mDisplayState.allowMultiple = true;
|
|
||||||
} else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
|
|
||||||
mDisplayState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
|
|
||||||
} else {
|
|
||||||
mDisplayState.acceptMimes = new String[] { intent.getType() };
|
|
||||||
}
|
|
||||||
|
|
||||||
mDisplayState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
|
|
||||||
|
|
||||||
setResult(Activity.RESULT_CANCELED);
|
setResult(Activity.RESULT_CANCELED);
|
||||||
setContentView(R.layout.activity);
|
setContentView(R.layout.activity);
|
||||||
|
|
||||||
if (mAction == ACTION_CREATE) {
|
|
||||||
final String mimeType = getIntent().getType();
|
|
||||||
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
|
|
||||||
SaveFragment.show(getFragmentManager(), mimeType, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAction == ACTION_GET_CONTENT) {
|
|
||||||
final Intent moreApps = new Intent(getIntent());
|
|
||||||
moreApps.setComponent(null);
|
|
||||||
moreApps.setPackage(null);
|
|
||||||
RootsFragment.show(getFragmentManager(), moreApps);
|
|
||||||
} else if (mAction == ACTION_OPEN || mAction == ACTION_CREATE) {
|
|
||||||
RootsFragment.show(getFragmentManager(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAction == ACTION_MANAGE) {
|
|
||||||
mDisplayState.sortOrder = SORT_ORDER_LAST_MODIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
mRootsContainer = findViewById(R.id.container_roots);
|
mRootsContainer = findViewById(R.id.container_roots);
|
||||||
|
|
||||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||||
@@ -156,9 +103,70 @@ public class DocumentsActivity extends Activity {
|
|||||||
mDrawerLayout.setDrawerListener(mDrawerListener);
|
mDrawerLayout.setDrawerListener(mDrawerListener);
|
||||||
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
|
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
|
||||||
|
|
||||||
if (mAction == ACTION_MANAGE) {
|
if (icicle != null) {
|
||||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
mState = icicle.getParcelable(EXTRA_STATE);
|
||||||
|
} else {
|
||||||
|
buildDefaultState();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_MANAGE) {
|
||||||
|
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_CREATE) {
|
||||||
|
final String mimeType = getIntent().getType();
|
||||||
|
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
|
||||||
|
SaveFragment.show(getFragmentManager(), mimeType, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_GET_CONTENT) {
|
||||||
|
final Intent moreApps = new Intent(getIntent());
|
||||||
|
moreApps.setComponent(null);
|
||||||
|
moreApps.setPackage(null);
|
||||||
|
RootsFragment.show(getFragmentManager(), moreApps);
|
||||||
|
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE) {
|
||||||
|
RootsFragment.show(getFragmentManager(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentDirectoryChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultState() {
|
||||||
|
mState = new State();
|
||||||
|
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
final String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
|
||||||
|
mState.action = ACTION_OPEN;
|
||||||
|
} else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
|
||||||
|
mState.action = ACTION_CREATE;
|
||||||
|
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
|
||||||
|
mState.action = ACTION_GET_CONTENT;
|
||||||
|
} else if (DocumentsContract.ACTION_MANAGE_DOCUMENTS.equals(action)) {
|
||||||
|
mState.action = ACTION_MANAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||||
|
mState.allowMultiple = intent.getBooleanExtra(
|
||||||
|
Intent.EXTRA_ALLOW_MULTIPLE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_MANAGE) {
|
||||||
|
mState.acceptMimes = new String[] { "*/*" };
|
||||||
|
mState.allowMultiple = true;
|
||||||
|
} else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
|
||||||
|
mState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
|
||||||
|
} else {
|
||||||
|
mState.acceptMimes = new String[] { intent.getType() };
|
||||||
|
}
|
||||||
|
|
||||||
|
mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
|
||||||
|
|
||||||
|
if (mState.action == ACTION_MANAGE) {
|
||||||
|
mState.sortOrder = SORT_ORDER_LAST_MODIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mState.action == ACTION_MANAGE) {
|
||||||
final Uri rootUri = intent.getData();
|
final Uri rootUri = intent.getData();
|
||||||
final RootInfo root = mRoots.findRoot(rootUri);
|
final RootInfo root = mRoots.findRoot(rootUri);
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
@@ -169,8 +177,6 @@ public class DocumentsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mDrawerLayout.openDrawer(mRootsContainer);
|
|
||||||
|
|
||||||
// Restore last stack for calling package
|
// Restore last stack for calling package
|
||||||
// TODO: move into async loader
|
// TODO: move into async loader
|
||||||
final String packageName = getCallingPackage();
|
final String packageName = getCallingPackage();
|
||||||
@@ -178,17 +184,17 @@ public class DocumentsActivity extends Activity {
|
|||||||
.query(RecentsProvider.buildResume(packageName), null, null, null, null);
|
.query(RecentsProvider.buildResume(packageName), null, null, null, null);
|
||||||
try {
|
try {
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
final String raw = cursor.getString(
|
final byte[] rawStack = cursor.getBlob(
|
||||||
cursor.getColumnIndex(RecentsProvider.COL_PATH));
|
cursor.getColumnIndex(RecentsProvider.COL_PATH));
|
||||||
mStack = DocumentStack.deserialize(getContentResolver(), raw);
|
DurableUtils.readFromArray(rawStack, mState.stack);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Failed to resume", e);
|
Log.w(TAG, "Failed to resume", e);
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentDirectoryChanged();
|
mDrawerLayout.openDrawer(mRootsContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,10 +202,10 @@ public class DocumentsActivity extends Activity {
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
if (mAction == ACTION_MANAGE) {
|
if (mState.action == ACTION_MANAGE) {
|
||||||
mDisplayState.showSize = true;
|
mState.showSize = true;
|
||||||
} else {
|
} else {
|
||||||
mDisplayState.showSize = SettingsActivity.getDisplayFileSize(this);
|
mState.showSize = SettingsActivity.getDisplayFileSize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,9 +248,9 @@ public class DocumentsActivity extends Activity {
|
|||||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||||
actionBar.setIcon(new ColorDrawable());
|
actionBar.setIcon(new ColorDrawable());
|
||||||
|
|
||||||
if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
|
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||||
actionBar.setTitle(R.string.title_open);
|
actionBar.setTitle(R.string.title_open);
|
||||||
} else if (mAction == ACTION_CREATE) {
|
} else if (mState.action == ACTION_CREATE) {
|
||||||
actionBar.setTitle(R.string.title_save);
|
actionBar.setTitle(R.string.title_save);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,13 +268,13 @@ public class DocumentsActivity extends Activity {
|
|||||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
||||||
actionBar.setTitle(null);
|
actionBar.setTitle(null);
|
||||||
actionBar.setListNavigationCallbacks(mSortAdapter, mSortListener);
|
actionBar.setListNavigationCallbacks(mSortAdapter, mSortListener);
|
||||||
actionBar.setSelectedNavigationItem(mDisplayState.sortOrder);
|
actionBar.setSelectedNavigationItem(mState.sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStack.size() > 1) {
|
if (mState.stack.size() > 1) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
||||||
} else if (mAction == ACTION_MANAGE) {
|
} else if (mState.action == ACTION_MANAGE) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
mDrawerToggle.setDrawerIndicatorEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
@@ -288,7 +294,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
|
mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextSubmit(String query) {
|
public boolean onQueryTextSubmit(String query) {
|
||||||
mCurrentSearch = query;
|
mState.currentSearch = query;
|
||||||
onCurrentDirectoryChanged();
|
onCurrentDirectoryChanged();
|
||||||
mSearchView.setIconified(true);
|
mSearchView.setIconified(true);
|
||||||
return true;
|
return true;
|
||||||
@@ -303,7 +309,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
mSearchView.setOnCloseListener(new OnCloseListener() {
|
mSearchView.setOnCloseListener(new OnCloseListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onClose() {
|
public boolean onClose() {
|
||||||
mCurrentSearch = null;
|
mState.currentSearch = null;
|
||||||
onCurrentDirectoryChanged();
|
onCurrentDirectoryChanged();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -325,11 +331,11 @@ public class DocumentsActivity extends Activity {
|
|||||||
final MenuItem list = menu.findItem(R.id.menu_list);
|
final MenuItem list = menu.findItem(R.id.menu_list);
|
||||||
final MenuItem settings = menu.findItem(R.id.menu_settings);
|
final MenuItem settings = menu.findItem(R.id.menu_settings);
|
||||||
|
|
||||||
grid.setVisible(mDisplayState.mode != MODE_GRID);
|
grid.setVisible(mState.mode != MODE_GRID);
|
||||||
list.setVisible(mDisplayState.mode != MODE_LIST);
|
list.setVisible(mState.mode != MODE_LIST);
|
||||||
|
|
||||||
final boolean searchVisible;
|
final boolean searchVisible;
|
||||||
if (mAction == ACTION_CREATE) {
|
if (mState.action == ACTION_CREATE) {
|
||||||
createDir.setVisible(cwd != null && cwd.isCreateSupported());
|
createDir.setVisible(cwd != null && cwd.isCreateSupported());
|
||||||
searchVisible = false;
|
searchVisible = false;
|
||||||
|
|
||||||
@@ -348,7 +354,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
// TODO: close any search in-progress when hiding
|
// TODO: close any search in-progress when hiding
|
||||||
search.setVisible(searchVisible);
|
search.setVisible(searchVisible);
|
||||||
|
|
||||||
settings.setVisible(mAction != ACTION_MANAGE);
|
settings.setVisible(mState.action != ACTION_MANAGE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -370,13 +376,13 @@ public class DocumentsActivity extends Activity {
|
|||||||
return false;
|
return false;
|
||||||
} else if (id == R.id.menu_grid) {
|
} else if (id == R.id.menu_grid) {
|
||||||
// TODO: persist explicit user mode for cwd
|
// TODO: persist explicit user mode for cwd
|
||||||
mDisplayState.mode = MODE_GRID;
|
mState.mode = MODE_GRID;
|
||||||
updateDisplayState();
|
updateDisplayState();
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.menu_list) {
|
} else if (id == R.id.menu_list) {
|
||||||
// TODO: persist explicit user mode for cwd
|
// TODO: persist explicit user mode for cwd
|
||||||
mDisplayState.mode = MODE_LIST;
|
mState.mode = MODE_LIST;
|
||||||
updateDisplayState();
|
updateDisplayState();
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
return true;
|
return true;
|
||||||
@@ -390,9 +396,9 @@ public class DocumentsActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
final int size = mStack.size();
|
final int size = mState.stack.size();
|
||||||
if (size > 1) {
|
if (size > 1) {
|
||||||
mStack.pop();
|
mState.stack.pop();
|
||||||
onCurrentDirectoryChanged();
|
onCurrentDirectoryChanged();
|
||||||
} else if (size == 1 && !mDrawerLayout.isDrawerOpen(mRootsContainer)) {
|
} else if (size == 1 && !mDrawerLayout.isDrawerOpen(mRootsContainer)) {
|
||||||
// TODO: open root drawer once we can capture back key
|
// TODO: open root drawer once we can capture back key
|
||||||
@@ -402,11 +408,23 @@ public class DocumentsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle state) {
|
||||||
|
super.onSaveInstanceState(state);
|
||||||
|
state.putParcelable(EXTRA_STATE, mState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle state) {
|
||||||
|
super.onRestoreInstanceState(state);
|
||||||
|
updateActionBar();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: support additional sort orders
|
// TODO: support additional sort orders
|
||||||
private BaseAdapter mSortAdapter = new BaseAdapter() {
|
private BaseAdapter mSortAdapter = new BaseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return mDisplayState.showSize ? 3 : 2;
|
return mState.showSize ? 3 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -438,8 +456,8 @@ public class DocumentsActivity extends Activity {
|
|||||||
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
|
||||||
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
|
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
|
||||||
|
|
||||||
if (mStack.size() > 0) {
|
if (mState.stack.size() > 0) {
|
||||||
title.setText(mStack.getTitle(mRoots));
|
title.setText(mState.stack.getTitle(mRoots));
|
||||||
} else {
|
} else {
|
||||||
// No directory means recents
|
// No directory means recents
|
||||||
title.setText(R.string.root_recent);
|
title.setText(R.string.root_recent);
|
||||||
@@ -467,26 +485,26 @@ public class DocumentsActivity extends Activity {
|
|||||||
private OnNavigationListener mSortListener = new OnNavigationListener() {
|
private OnNavigationListener mSortListener = new OnNavigationListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||||
mDisplayState.sortOrder = itemPosition;
|
mState.sortOrder = itemPosition;
|
||||||
updateDisplayState();
|
updateDisplayState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public RootInfo getCurrentRoot() {
|
public RootInfo getCurrentRoot() {
|
||||||
if (mStack.size() > 0) {
|
if (mState.stack.size() > 0) {
|
||||||
return mStack.getRoot(mRoots);
|
return mState.stack.getRoot(mRoots);
|
||||||
} else {
|
} else {
|
||||||
return mRoots.getRecentsRoot();
|
return mRoots.getRecentsRoot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DocumentInfo getCurrentDirectory() {
|
public DocumentInfo getCurrentDirectory() {
|
||||||
return mStack.peek();
|
return mState.stack.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayState getDisplayState() {
|
public State getDisplayState() {
|
||||||
return mDisplayState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCurrentDirectoryChanged() {
|
private void onCurrentDirectoryChanged() {
|
||||||
@@ -495,15 +513,15 @@ public class DocumentsActivity extends Activity {
|
|||||||
|
|
||||||
if (cwd == null) {
|
if (cwd == null) {
|
||||||
// No directory means recents
|
// No directory means recents
|
||||||
if (mAction == ACTION_CREATE) {
|
if (mState.action == ACTION_CREATE) {
|
||||||
RecentsCreateFragment.show(fm);
|
RecentsCreateFragment.show(fm);
|
||||||
} else {
|
} else {
|
||||||
DirectoryFragment.showRecentsOpen(fm);
|
DirectoryFragment.showRecentsOpen(fm);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mCurrentSearch != null) {
|
if (mState.currentSearch != null) {
|
||||||
// Ongoing search
|
// Ongoing search
|
||||||
DirectoryFragment.showSearch(fm, cwd.uri, mCurrentSearch);
|
DirectoryFragment.showSearch(fm, cwd.uri, mState.currentSearch);
|
||||||
} else {
|
} else {
|
||||||
// Normal boring directory
|
// Normal boring directory
|
||||||
DirectoryFragment.showNormal(fm, cwd.uri);
|
DirectoryFragment.showNormal(fm, cwd.uri);
|
||||||
@@ -511,7 +529,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forget any replacement target
|
// Forget any replacement target
|
||||||
if (mAction == ACTION_CREATE) {
|
if (mState.action == ACTION_CREATE) {
|
||||||
final SaveFragment save = SaveFragment.get(fm);
|
final SaveFragment save = SaveFragment.get(fm);
|
||||||
if (save != null) {
|
if (save != null) {
|
||||||
save.setReplaceTarget(null);
|
save.setReplaceTarget(null);
|
||||||
@@ -529,13 +547,13 @@ public class DocumentsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onStackPicked(DocumentStack stack) {
|
public void onStackPicked(DocumentStack stack) {
|
||||||
mStack = stack;
|
mState.stack = stack;
|
||||||
onCurrentDirectoryChanged();
|
onCurrentDirectoryChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRootPicked(RootInfo root, boolean closeDrawer) {
|
public void onRootPicked(RootInfo root, boolean closeDrawer) {
|
||||||
// Clear entire backstack and start in new root
|
// Clear entire backstack and start in new root
|
||||||
mStack.clear();
|
mState.stack.clear();
|
||||||
|
|
||||||
if (!mRoots.isRecentsRoot(root)) {
|
if (!mRoots.isRecentsRoot(root)) {
|
||||||
try {
|
try {
|
||||||
@@ -566,19 +584,19 @@ public class DocumentsActivity extends Activity {
|
|||||||
if (doc.isDirectory()) {
|
if (doc.isDirectory()) {
|
||||||
// TODO: query display mode user preference for this dir
|
// TODO: query display mode user preference for this dir
|
||||||
if (doc.isGridPreferred()) {
|
if (doc.isGridPreferred()) {
|
||||||
mDisplayState.mode = MODE_GRID;
|
mState.mode = MODE_GRID;
|
||||||
} else {
|
} else {
|
||||||
mDisplayState.mode = MODE_LIST;
|
mState.mode = MODE_LIST;
|
||||||
}
|
}
|
||||||
mStack.push(doc);
|
mState.stack.push(doc);
|
||||||
onCurrentDirectoryChanged();
|
onCurrentDirectoryChanged();
|
||||||
} else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
|
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||||
// Explicit file picked, return
|
// Explicit file picked, return
|
||||||
onFinished(doc.uri);
|
onFinished(doc.uri);
|
||||||
} else if (mAction == ACTION_CREATE) {
|
} else if (mState.action == ACTION_CREATE) {
|
||||||
// Replace selected file
|
// Replace selected file
|
||||||
SaveFragment.get(fm).setReplaceTarget(doc);
|
SaveFragment.get(fm).setReplaceTarget(doc);
|
||||||
} else if (mAction == ACTION_MANAGE) {
|
} else if (mState.action == ACTION_MANAGE) {
|
||||||
// Open the document
|
// Open the document
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
final Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
@@ -592,7 +610,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onDocumentsPicked(List<DocumentInfo> docs) {
|
public void onDocumentsPicked(List<DocumentInfo> docs) {
|
||||||
if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
|
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||||
final int size = docs.size();
|
final int size = docs.size();
|
||||||
final Uri[] uris = new Uri[size];
|
final Uri[] uris = new Uri[size];
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@@ -629,14 +647,14 @@ public class DocumentsActivity extends Activity {
|
|||||||
final ContentResolver resolver = getContentResolver();
|
final ContentResolver resolver = getContentResolver();
|
||||||
final ContentValues values = new ContentValues();
|
final ContentValues values = new ContentValues();
|
||||||
|
|
||||||
final String rawStack = DocumentStack.serialize(mStack);
|
final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
|
||||||
if (mAction == ACTION_CREATE) {
|
if (mState.action == ACTION_CREATE) {
|
||||||
// Remember stack for last create
|
// Remember stack for last create
|
||||||
values.clear();
|
values.clear();
|
||||||
values.put(RecentsProvider.COL_PATH, rawStack);
|
values.put(RecentsProvider.COL_PATH, rawStack);
|
||||||
resolver.insert(RecentsProvider.buildRecentCreate(), values);
|
resolver.insert(RecentsProvider.buildRecentCreate(), values);
|
||||||
|
|
||||||
} else if (mAction == ACTION_OPEN || mAction == ACTION_GET_CONTENT) {
|
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
|
||||||
// Remember opened items
|
// Remember opened items
|
||||||
for (Uri uri : uris) {
|
for (Uri uri : uris) {
|
||||||
values.clear();
|
values.clear();
|
||||||
@@ -656,14 +674,14 @@ public class DocumentsActivity extends Activity {
|
|||||||
intent.setData(uris[0]);
|
intent.setData(uris[0]);
|
||||||
} else if (uris.length > 1) {
|
} else if (uris.length > 1) {
|
||||||
final ClipData clipData = new ClipData(
|
final ClipData clipData = new ClipData(
|
||||||
null, mDisplayState.acceptMimes, new ClipData.Item(uris[0]));
|
null, mState.acceptMimes, new ClipData.Item(uris[0]));
|
||||||
for (int i = 1; i < uris.length; i++) {
|
for (int i = 1; i < uris.length; i++) {
|
||||||
clipData.addItem(new ClipData.Item(uris[i]));
|
clipData.addItem(new ClipData.Item(uris[i]));
|
||||||
}
|
}
|
||||||
intent.setClipData(clipData);
|
intent.setClipData(clipData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAction == ACTION_GET_CONTENT) {
|
if (mState.action == ACTION_GET_CONTENT) {
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
} else {
|
} else {
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
@@ -675,7 +693,7 @@ public class DocumentsActivity extends Activity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DisplayState {
|
public static class State implements android.os.Parcelable {
|
||||||
public int action;
|
public int action;
|
||||||
public int mode = MODE_LIST;
|
public int mode = MODE_LIST;
|
||||||
public String[] acceptMimes;
|
public String[] acceptMimes;
|
||||||
@@ -684,6 +702,11 @@ public class DocumentsActivity extends Activity {
|
|||||||
public boolean showSize = false;
|
public boolean showSize = false;
|
||||||
public boolean localOnly = false;
|
public boolean localOnly = false;
|
||||||
|
|
||||||
|
/** Current user navigation stack; empty implies recents. */
|
||||||
|
public DocumentStack stack = new DocumentStack();
|
||||||
|
/** Currently active search, overriding any stack. */
|
||||||
|
public String currentSearch;
|
||||||
|
|
||||||
public static final int ACTION_OPEN = 1;
|
public static final int ACTION_OPEN = 1;
|
||||||
public static final int ACTION_CREATE = 2;
|
public static final int ACTION_CREATE = 2;
|
||||||
public static final int ACTION_GET_CONTENT = 3;
|
public static final int ACTION_GET_CONTENT = 3;
|
||||||
@@ -695,11 +718,51 @@ public class DocumentsActivity extends Activity {
|
|||||||
public static final int SORT_ORDER_DISPLAY_NAME = 0;
|
public static final int SORT_ORDER_DISPLAY_NAME = 0;
|
||||||
public static final int SORT_ORDER_LAST_MODIFIED = 1;
|
public static final int SORT_ORDER_LAST_MODIFIED = 1;
|
||||||
public static final int SORT_ORDER_SIZE = 2;
|
public static final int SORT_ORDER_SIZE = 2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeInt(action);
|
||||||
|
out.writeInt(mode);
|
||||||
|
out.writeStringArray(acceptMimes);
|
||||||
|
out.writeInt(sortOrder);
|
||||||
|
out.writeInt(allowMultiple ? 1 : 0);
|
||||||
|
out.writeInt(showSize ? 1 : 0);
|
||||||
|
out.writeInt(localOnly ? 1 : 0);
|
||||||
|
DurableUtils.writeToParcel(out, stack);
|
||||||
|
out.writeString(currentSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<State> CREATOR = new Creator<State>() {
|
||||||
|
@Override
|
||||||
|
public State createFromParcel(Parcel in) {
|
||||||
|
final State state = new State();
|
||||||
|
state.action = in.readInt();
|
||||||
|
state.mode = in.readInt();
|
||||||
|
state.acceptMimes = in.readStringArray();
|
||||||
|
state.sortOrder = in.readInt();
|
||||||
|
state.allowMultiple = in.readInt() != 0;
|
||||||
|
state.showSize = in.readInt() != 0;
|
||||||
|
state.localOnly = in.readInt() != 0;
|
||||||
|
DurableUtils.readFromParcel(in, state.stack);
|
||||||
|
state.currentSearch = in.readString();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State[] newArray(int size) {
|
||||||
|
return new State[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpStack() {
|
private void dumpStack() {
|
||||||
Log.d(TAG, "Current stack:");
|
Log.d(TAG, "Current stack:");
|
||||||
for (DocumentInfo doc : mStack) {
|
for (DocumentInfo doc : mState.stack) {
|
||||||
Log.d(TAG, "--> " + doc);
|
Log.d(TAG, "--> " + doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ import com.google.android.collect.Lists;
|
|||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -138,12 +140,13 @@ public class RecentsCreateFragment extends Fragment {
|
|||||||
uri, null, null, null, RecentsProvider.COL_TIMESTAMP + " DESC", signal);
|
uri, null, null, null, RecentsProvider.COL_TIMESTAMP + " DESC", signal);
|
||||||
try {
|
try {
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
final String rawStack = cursor.getString(
|
final byte[] raw = cursor.getBlob(
|
||||||
cursor.getColumnIndex(RecentsProvider.COL_PATH));
|
cursor.getColumnIndex(RecentsProvider.COL_PATH));
|
||||||
try {
|
try {
|
||||||
final DocumentStack stack = DocumentStack.deserialize(resolver, rawStack);
|
final DocumentStack stack = new DocumentStack();
|
||||||
|
stack.read(new DataInputStream(new ByteArrayInputStream(raw)));
|
||||||
result.add(stack);
|
result.add(stack);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Failed to resolve stack: " + e);
|
Log.w(TAG, "Failed to resolve stack: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ public class RootsCache {
|
|||||||
// TODO: cache roots in local provider to avoid spinning up backends
|
// TODO: cache roots in local provider to avoid spinning up backends
|
||||||
// TODO: root updates should trigger UI refresh
|
// TODO: root updates should trigger UI refresh
|
||||||
|
|
||||||
|
private static final boolean RECENTS_ENABLED = false;
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
public List<RootInfo> mRoots = Lists.newArrayList();
|
public List<RootInfo> mRoots = Lists.newArrayList();
|
||||||
@@ -68,7 +70,7 @@ public class RootsCache {
|
|||||||
public void update() {
|
public void update() {
|
||||||
mRoots.clear();
|
mRoots.clear();
|
||||||
|
|
||||||
{
|
if (RECENTS_ENABLED) {
|
||||||
// Create special root for recents
|
// Create special root for recents
|
||||||
final RootInfo root = new RootInfo();
|
final RootInfo root = new RootInfo();
|
||||||
root.rootType = Root.ROOT_TYPE_SHORTCUT;
|
root.rootType = Root.ROOT_TYPE_SHORTCUT;
|
||||||
|
|||||||
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package com.android.documentsui;
|
package com.android.documentsui;
|
||||||
|
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
|
||||||
|
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
|
||||||
|
|
||||||
import android.database.AbstractCursor;
|
import android.database.AbstractCursor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.provider.DocumentsContract.Document;
|
import android.provider.DocumentsContract.Document;
|
||||||
|
|
||||||
import com.android.documentsui.DocumentsActivity.DisplayState;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cursor wrapper that presents a sorted view of the underlying cursor. Handles
|
* Cursor wrapper that presents a sorted view of the underlying cursor. Handles
|
||||||
* common {@link Document} sorting modes, such as ordering directories first.
|
* common {@link Document} sorting modes, such as ordering directories first.
|
||||||
@@ -39,12 +41,12 @@ public class SortingCursorWrapper extends AbstractCursor {
|
|||||||
final int count = cursor.getCount();
|
final int count = cursor.getCount();
|
||||||
mPosition = new int[count];
|
mPosition = new int[count];
|
||||||
switch (sortOrder) {
|
switch (sortOrder) {
|
||||||
case DisplayState.SORT_ORDER_DISPLAY_NAME:
|
case SORT_ORDER_DISPLAY_NAME:
|
||||||
mValueString = new String[count];
|
mValueString = new String[count];
|
||||||
mValueLong = null;
|
mValueLong = null;
|
||||||
break;
|
break;
|
||||||
case DisplayState.SORT_ORDER_LAST_MODIFIED:
|
case SORT_ORDER_LAST_MODIFIED:
|
||||||
case DisplayState.SORT_ORDER_SIZE:
|
case SORT_ORDER_SIZE:
|
||||||
mValueString = null;
|
mValueString = null;
|
||||||
mValueLong = new long[count];
|
mValueLong = new long[count];
|
||||||
break;
|
break;
|
||||||
@@ -63,7 +65,7 @@ public class SortingCursorWrapper extends AbstractCursor {
|
|||||||
mPosition[i] = i;
|
mPosition[i] = i;
|
||||||
|
|
||||||
switch (sortOrder) {
|
switch (sortOrder) {
|
||||||
case DisplayState.SORT_ORDER_DISPLAY_NAME:
|
case SORT_ORDER_DISPLAY_NAME:
|
||||||
final String mimeType = cursor.getString(mimeTypeIndex);
|
final String mimeType = cursor.getString(mimeTypeIndex);
|
||||||
final String displayName = cursor.getString(displayNameIndex);
|
final String displayName = cursor.getString(displayNameIndex);
|
||||||
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||||
@@ -72,24 +74,24 @@ public class SortingCursorWrapper extends AbstractCursor {
|
|||||||
mValueString[i] = displayName;
|
mValueString[i] = displayName;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DisplayState.SORT_ORDER_LAST_MODIFIED:
|
case SORT_ORDER_LAST_MODIFIED:
|
||||||
mValueLong[i] = cursor.getLong(lastModifiedIndex);
|
mValueLong[i] = cursor.getLong(lastModifiedIndex);
|
||||||
break;
|
break;
|
||||||
case DisplayState.SORT_ORDER_SIZE:
|
case SORT_ORDER_SIZE:
|
||||||
mValueLong[i] = cursor.getLong(sizeIndex);
|
mValueLong[i] = cursor.getLong(sizeIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sortOrder) {
|
switch (sortOrder) {
|
||||||
case DisplayState.SORT_ORDER_DISPLAY_NAME:
|
case SORT_ORDER_DISPLAY_NAME:
|
||||||
synchronized (SortingCursorWrapper.class) {
|
synchronized (SortingCursorWrapper.class) {
|
||||||
|
|
||||||
binarySort(mPosition, mValueString);
|
binarySort(mPosition, mValueString);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DisplayState.SORT_ORDER_LAST_MODIFIED:
|
case SORT_ORDER_LAST_MODIFIED:
|
||||||
case DisplayState.SORT_ORDER_SIZE:
|
case SORT_ORDER_SIZE:
|
||||||
binarySort(mPosition, mValueLong);
|
binarySort(mPosition, mValueLong);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,19 @@ import com.android.documentsui.RecentsProvider;
|
|||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ProtocolException;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a {@link Document}.
|
* Representation of a {@link Document}.
|
||||||
*/
|
*/
|
||||||
public class DocumentInfo {
|
public class DocumentInfo implements Durable {
|
||||||
|
private static final int VERSION_INIT = 1;
|
||||||
|
|
||||||
public Uri uri;
|
public Uri uri;
|
||||||
public String mimeType;
|
public String mimeType;
|
||||||
public String displayName;
|
public String displayName;
|
||||||
@@ -46,6 +52,55 @@ public class DocumentInfo {
|
|||||||
public long size;
|
public long size;
|
||||||
public int icon;
|
public int icon;
|
||||||
|
|
||||||
|
public DocumentInfo() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
uri = null;
|
||||||
|
mimeType = null;
|
||||||
|
displayName = null;
|
||||||
|
lastModified = -1;
|
||||||
|
flags = 0;
|
||||||
|
summary = null;
|
||||||
|
size = -1;
|
||||||
|
icon = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(DataInputStream in) throws IOException {
|
||||||
|
final int version = in.readInt();
|
||||||
|
switch (version) {
|
||||||
|
case VERSION_INIT:
|
||||||
|
final String rawUri = DurableUtils.readNullableString(in);
|
||||||
|
uri = rawUri != null ? Uri.parse(rawUri) : null;
|
||||||
|
mimeType = DurableUtils.readNullableString(in);
|
||||||
|
displayName = DurableUtils.readNullableString(in);
|
||||||
|
lastModified = in.readLong();
|
||||||
|
flags = in.readInt();
|
||||||
|
summary = DurableUtils.readNullableString(in);
|
||||||
|
size = in.readLong();
|
||||||
|
icon = in.readInt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ProtocolException("Unknown version " + version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(DataOutputStream out) throws IOException {
|
||||||
|
out.writeInt(VERSION_INIT);
|
||||||
|
DurableUtils.writeNullableString(out, uri.toString());
|
||||||
|
DurableUtils.writeNullableString(out, mimeType);
|
||||||
|
DurableUtils.writeNullableString(out, displayName);
|
||||||
|
out.writeLong(lastModified);
|
||||||
|
out.writeInt(flags);
|
||||||
|
DurableUtils.writeNullableString(out, summary);
|
||||||
|
out.writeLong(size);
|
||||||
|
out.writeInt(icon);
|
||||||
|
}
|
||||||
|
|
||||||
public static DocumentInfo fromDirectoryCursor(Uri parent, Cursor cursor) {
|
public static DocumentInfo fromDirectoryCursor(Uri parent, Cursor cursor) {
|
||||||
final DocumentInfo doc = new DocumentInfo();
|
final DocumentInfo doc = new DocumentInfo();
|
||||||
final String authority = parent.getAuthority();
|
final String authority = parent.getAuthority();
|
||||||
|
|||||||
@@ -16,54 +16,20 @@
|
|||||||
|
|
||||||
package com.android.documentsui.model;
|
package com.android.documentsui.model;
|
||||||
|
|
||||||
import static com.android.documentsui.DocumentsActivity.TAG;
|
|
||||||
import static com.android.documentsui.model.DocumentInfo.asFileNotFoundException;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.android.documentsui.RootsCache;
|
import com.android.documentsui.RootsCache;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import java.io.DataInputStream;
|
||||||
import org.json.JSONException;
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.FileNotFoundException;
|
import java.net.ProtocolException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a stack of {@link DocumentInfo}, usually the result of a
|
* Representation of a stack of {@link DocumentInfo}, usually the result of a
|
||||||
* user-driven traversal.
|
* user-driven traversal.
|
||||||
*/
|
*/
|
||||||
public class DocumentStack extends LinkedList<DocumentInfo> {
|
public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
|
||||||
|
private static final int VERSION_INIT = 1;
|
||||||
public static String serialize(DocumentStack stack) {
|
|
||||||
final JSONArray json = new JSONArray();
|
|
||||||
for (int i = 0; i < stack.size(); i++) {
|
|
||||||
json.put(stack.get(i).uri);
|
|
||||||
}
|
|
||||||
return json.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DocumentStack deserialize(ContentResolver resolver, String raw)
|
|
||||||
throws FileNotFoundException {
|
|
||||||
Log.d(TAG, "deserialize: " + raw);
|
|
||||||
|
|
||||||
final DocumentStack stack = new DocumentStack();
|
|
||||||
try {
|
|
||||||
final JSONArray json = new JSONArray(raw);
|
|
||||||
for (int i = 0; i < json.length(); i++) {
|
|
||||||
final Uri uri = Uri.parse(json.getString(i));
|
|
||||||
final DocumentInfo doc = DocumentInfo.fromUri(resolver, uri);
|
|
||||||
stack.add(doc);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
throw asFileNotFoundException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle roots that have gone missing
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RootInfo getRoot(RootsCache roots) {
|
public RootInfo getRoot(RootsCache roots) {
|
||||||
return roots.findRoot(getLast().uri);
|
return roots.findRoot(getLast().uri);
|
||||||
@@ -78,4 +44,37 @@ public class DocumentStack extends LinkedList<DocumentInfo> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(DataInputStream in) throws IOException {
|
||||||
|
final int version = in.readInt();
|
||||||
|
switch (version) {
|
||||||
|
case VERSION_INIT:
|
||||||
|
final int size = in.readInt();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final DocumentInfo doc = new DocumentInfo();
|
||||||
|
doc.read(in);
|
||||||
|
add(doc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ProtocolException("Unknown version " + version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(DataOutputStream out) throws IOException {
|
||||||
|
out.writeInt(VERSION_INIT);
|
||||||
|
final int size = size();
|
||||||
|
out.writeInt(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final DocumentInfo doc = get(i);
|
||||||
|
doc.write(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.model;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface Durable {
|
||||||
|
public void reset();
|
||||||
|
public void read(DataInputStream in) throws IOException;
|
||||||
|
public void write(DataOutputStream out) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2013 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.model;
|
||||||
|
|
||||||
|
import static com.android.documentsui.DocumentsActivity.TAG;
|
||||||
|
|
||||||
|
import android.os.BadParcelableException;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DurableUtils {
|
||||||
|
public static <D extends Durable> byte[] writeToArray(D d) throws IOException {
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
d.write(new DataOutputStream(out));
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends Durable> D readFromArray(byte[] data, D d) throws IOException {
|
||||||
|
final ByteArrayInputStream in = new ByteArrayInputStream(data);
|
||||||
|
d.reset();
|
||||||
|
try {
|
||||||
|
d.read(new DataInputStream(in));
|
||||||
|
} catch (IOException e) {
|
||||||
|
d.reset();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends Durable> byte[] writeToArrayOrNull(D d) {
|
||||||
|
try {
|
||||||
|
return writeToArray(d);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to write", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends Durable> D readFromArrayOrNull(byte[] data, D d) {
|
||||||
|
try {
|
||||||
|
return readFromArray(data, d);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to read", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends Durable> void writeToParcel(Parcel parcel, D d) {
|
||||||
|
try {
|
||||||
|
parcel.writeByteArray(writeToArray(d));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BadParcelableException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends Durable> D readFromParcel(Parcel parcel, D d) {
|
||||||
|
try {
|
||||||
|
return readFromArray(parcel.createByteArray(), d);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BadParcelableException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeNullableString(DataOutputStream out, String value) throws IOException {
|
||||||
|
if (value != null) {
|
||||||
|
out.write(1);
|
||||||
|
out.writeUTF(value);
|
||||||
|
} else {
|
||||||
|
out.write(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readNullableString(DataInputStream in) throws IOException {
|
||||||
|
if (in.read() != 0) {
|
||||||
|
return in.readUTF();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user