DocumentsActivity.java revision b51331116eb2ebbc41aaf69142916f9af6dffdd5
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.documentsui; 18 19import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE; 20import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT; 21import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE; 22import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN; 23import static com.android.documentsui.DocumentsActivity.State.MODE_GRID; 24import static com.android.documentsui.DocumentsActivity.State.MODE_LIST; 25import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED; 26 27import android.app.ActionBar; 28import android.app.ActionBar.OnNavigationListener; 29import android.app.Activity; 30import android.app.Fragment; 31import android.app.FragmentManager; 32import android.content.ActivityNotFoundException; 33import android.content.ClipData; 34import android.content.ComponentName; 35import android.content.ContentProviderClient; 36import android.content.ContentResolver; 37import android.content.ContentValues; 38import android.content.Intent; 39import android.content.pm.ResolveInfo; 40import android.database.Cursor; 41import android.graphics.drawable.ColorDrawable; 42import android.net.Uri; 43import android.os.Bundle; 44import android.os.Parcel; 45import android.provider.DocumentsContract; 46import android.support.v4.app.ActionBarDrawerToggle; 47import android.support.v4.view.GravityCompat; 48import android.support.v4.widget.DrawerLayout; 49import android.support.v4.widget.DrawerLayout.DrawerListener; 50import android.util.Log; 51import android.view.LayoutInflater; 52import android.view.Menu; 53import android.view.MenuItem; 54import android.view.View; 55import android.view.ViewGroup; 56import android.widget.BaseAdapter; 57import android.widget.SearchView; 58import android.widget.SearchView.OnCloseListener; 59import android.widget.SearchView.OnQueryTextListener; 60import android.widget.TextView; 61import android.widget.Toast; 62 63import com.android.documentsui.model.DocumentInfo; 64import com.android.documentsui.model.DocumentStack; 65import com.android.documentsui.model.DurableUtils; 66import com.android.documentsui.model.RootInfo; 67 68import java.io.FileNotFoundException; 69import java.io.IOException; 70import java.util.Arrays; 71import java.util.List; 72 73public class DocumentsActivity extends Activity { 74 public static final String TAG = "Documents"; 75 76 private SearchView mSearchView; 77 78 private View mRootsContainer; 79 private DrawerLayout mDrawerLayout; 80 private ActionBarDrawerToggle mDrawerToggle; 81 82 private static final String EXTRA_STATE = "state"; 83 84 private RootsCache mRoots; 85 private State mState; 86 87 @Override 88 public void onCreate(Bundle icicle) { 89 super.onCreate(icicle); 90 91 mRoots = DocumentsApplication.getRootsCache(this); 92 93 setResult(Activity.RESULT_CANCELED); 94 setContentView(R.layout.activity); 95 96 mRootsContainer = findViewById(R.id.container_roots); 97 98 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 99 100 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 101 R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close); 102 103 mDrawerLayout.setDrawerListener(mDrawerListener); 104 mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); 105 106 if (icicle != null) { 107 mState = icicle.getParcelable(EXTRA_STATE); 108 } else { 109 buildDefaultState(); 110 } 111 112 if (mState.action == ACTION_MANAGE) { 113 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); 114 } 115 116 if (mState.action == ACTION_CREATE) { 117 final String mimeType = getIntent().getType(); 118 final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE); 119 SaveFragment.show(getFragmentManager(), mimeType, title); 120 } 121 122 if (mState.action == ACTION_GET_CONTENT) { 123 final Intent moreApps = new Intent(getIntent()); 124 moreApps.setComponent(null); 125 moreApps.setPackage(null); 126 RootsFragment.show(getFragmentManager(), moreApps); 127 } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE) { 128 RootsFragment.show(getFragmentManager(), null); 129 } 130 131 onCurrentDirectoryChanged(); 132 } 133 134 private void buildDefaultState() { 135 mState = new State(); 136 137 final Intent intent = getIntent(); 138 final String action = intent.getAction(); 139 if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) { 140 mState.action = ACTION_OPEN; 141 } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) { 142 mState.action = ACTION_CREATE; 143 } else if (Intent.ACTION_GET_CONTENT.equals(action)) { 144 mState.action = ACTION_GET_CONTENT; 145 } else if (DocumentsContract.ACTION_MANAGE_DOCUMENTS.equals(action)) { 146 mState.action = ACTION_MANAGE; 147 } 148 149 if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { 150 mState.allowMultiple = intent.getBooleanExtra( 151 Intent.EXTRA_ALLOW_MULTIPLE, false); 152 } 153 154 if (mState.action == ACTION_MANAGE) { 155 mState.acceptMimes = new String[] { "*/*" }; 156 mState.allowMultiple = true; 157 } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { 158 mState.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); 159 } else { 160 mState.acceptMimes = new String[] { intent.getType() }; 161 } 162 163 mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); 164 165 if (mState.action == ACTION_MANAGE) { 166 mState.sortOrder = SORT_ORDER_LAST_MODIFIED; 167 } 168 169 if (mState.action == ACTION_MANAGE) { 170 final Uri rootUri = intent.getData(); 171 final RootInfo root = mRoots.findRoot(rootUri); 172 if (root != null) { 173 onRootPicked(root, true); 174 } else { 175 Log.w(TAG, "Failed to find root: " + rootUri); 176 finish(); 177 } 178 179 } else { 180 // Restore last stack for calling package 181 // TODO: move into async loader 182 final String packageName = getCallingPackage(); 183 final Cursor cursor = getContentResolver() 184 .query(RecentsProvider.buildResume(packageName), null, null, null, null); 185 try { 186 if (cursor.moveToFirst()) { 187 final byte[] rawStack = cursor.getBlob( 188 cursor.getColumnIndex(RecentsProvider.COL_PATH)); 189 DurableUtils.readFromArray(rawStack, mState.stack); 190 } 191 } catch (IOException e) { 192 Log.w(TAG, "Failed to resume", e); 193 } finally { 194 cursor.close(); 195 } 196 197 mDrawerLayout.openDrawer(mRootsContainer); 198 } 199 } 200 201 @Override 202 public void onStart() { 203 super.onStart(); 204 205 if (mState.action == ACTION_MANAGE) { 206 mState.showSize = true; 207 } else { 208 mState.showSize = SettingsActivity.getDisplayFileSize(this); 209 } 210 } 211 212 private DrawerListener mDrawerListener = new DrawerListener() { 213 @Override 214 public void onDrawerSlide(View drawerView, float slideOffset) { 215 mDrawerToggle.onDrawerSlide(drawerView, slideOffset); 216 } 217 218 @Override 219 public void onDrawerOpened(View drawerView) { 220 mDrawerToggle.onDrawerOpened(drawerView); 221 updateActionBar(); 222 } 223 224 @Override 225 public void onDrawerClosed(View drawerView) { 226 mDrawerToggle.onDrawerClosed(drawerView); 227 updateActionBar(); 228 } 229 230 @Override 231 public void onDrawerStateChanged(int newState) { 232 mDrawerToggle.onDrawerStateChanged(newState); 233 } 234 }; 235 236 @Override 237 protected void onPostCreate(Bundle savedInstanceState) { 238 super.onPostCreate(savedInstanceState); 239 mDrawerToggle.syncState(); 240 } 241 242 public void updateActionBar() { 243 final ActionBar actionBar = getActionBar(); 244 245 actionBar.setDisplayShowHomeEnabled(true); 246 247 if (mDrawerLayout.isDrawerOpen(mRootsContainer)) { 248 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 249 actionBar.setIcon(new ColorDrawable()); 250 251 if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { 252 actionBar.setTitle(R.string.title_open); 253 } else if (mState.action == ACTION_CREATE) { 254 actionBar.setTitle(R.string.title_save); 255 } 256 257 actionBar.setDisplayHomeAsUpEnabled(true); 258 mDrawerToggle.setDrawerIndicatorEnabled(true); 259 260 } else { 261 final RootInfo root = getCurrentRoot(); 262 actionBar.setIcon(root != null ? root.loadIcon(this) : null); 263 264 if (mRoots.isRecentsRoot(root)) { 265 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 266 actionBar.setTitle(root.title); 267 } else { 268 actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 269 actionBar.setTitle(null); 270 actionBar.setListNavigationCallbacks(mSortAdapter, mSortListener); 271 actionBar.setSelectedNavigationItem(mState.sortOrder); 272 } 273 274 if (mState.stack.size() > 1) { 275 actionBar.setDisplayHomeAsUpEnabled(true); 276 mDrawerToggle.setDrawerIndicatorEnabled(false); 277 } else if (mState.action == ACTION_MANAGE) { 278 actionBar.setDisplayHomeAsUpEnabled(false); 279 mDrawerToggle.setDrawerIndicatorEnabled(false); 280 } else { 281 actionBar.setDisplayHomeAsUpEnabled(true); 282 mDrawerToggle.setDrawerIndicatorEnabled(true); 283 } 284 } 285 } 286 287 @Override 288 public boolean onCreateOptionsMenu(Menu menu) { 289 super.onCreateOptionsMenu(menu); 290 getMenuInflater().inflate(R.menu.activity, menu); 291 292 final MenuItem searchMenu = menu.findItem(R.id.menu_search); 293 mSearchView = (SearchView) searchMenu.getActionView(); 294 mSearchView.setOnQueryTextListener(new OnQueryTextListener() { 295 @Override 296 public boolean onQueryTextSubmit(String query) { 297 mState.currentSearch = query; 298 onCurrentDirectoryChanged(); 299 mSearchView.setIconified(true); 300 return true; 301 } 302 303 @Override 304 public boolean onQueryTextChange(String newText) { 305 return false; 306 } 307 }); 308 309 mSearchView.setOnCloseListener(new OnCloseListener() { 310 @Override 311 public boolean onClose() { 312 mState.currentSearch = null; 313 onCurrentDirectoryChanged(); 314 return false; 315 } 316 }); 317 318 return true; 319 } 320 321 @Override 322 public boolean onPrepareOptionsMenu(Menu menu) { 323 super.onPrepareOptionsMenu(menu); 324 325 final FragmentManager fm = getFragmentManager(); 326 final DocumentInfo cwd = getCurrentDirectory(); 327 328 final MenuItem createDir = menu.findItem(R.id.menu_create_dir); 329 final MenuItem search = menu.findItem(R.id.menu_search); 330 final MenuItem grid = menu.findItem(R.id.menu_grid); 331 final MenuItem list = menu.findItem(R.id.menu_list); 332 final MenuItem settings = menu.findItem(R.id.menu_settings); 333 334 grid.setVisible(mState.mode != MODE_GRID); 335 list.setVisible(mState.mode != MODE_LIST); 336 337 final boolean searchVisible; 338 if (mState.action == ACTION_CREATE) { 339 createDir.setVisible(cwd != null && cwd.isCreateSupported()); 340 searchVisible = false; 341 342 // No display options in recent directories 343 if (cwd == null) { 344 grid.setVisible(false); 345 list.setVisible(false); 346 } 347 348 SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported()); 349 } else { 350 createDir.setVisible(false); 351 searchVisible = cwd != null && cwd.isSearchSupported(); 352 } 353 354 // TODO: close any search in-progress when hiding 355 search.setVisible(searchVisible); 356 357 settings.setVisible(mState.action != ACTION_MANAGE); 358 359 return true; 360 } 361 362 @Override 363 public boolean onOptionsItemSelected(MenuItem item) { 364 if (mDrawerToggle.onOptionsItemSelected(item)) { 365 return true; 366 } 367 368 final int id = item.getItemId(); 369 if (id == android.R.id.home) { 370 onBackPressed(); 371 return true; 372 } else if (id == R.id.menu_create_dir) { 373 CreateDirectoryFragment.show(getFragmentManager()); 374 return true; 375 } else if (id == R.id.menu_search) { 376 return false; 377 } else if (id == R.id.menu_grid) { 378 // TODO: persist explicit user mode for cwd 379 mState.mode = MODE_GRID; 380 updateDisplayState(); 381 invalidateOptionsMenu(); 382 return true; 383 } else if (id == R.id.menu_list) { 384 // TODO: persist explicit user mode for cwd 385 mState.mode = MODE_LIST; 386 updateDisplayState(); 387 invalidateOptionsMenu(); 388 return true; 389 } else if (id == R.id.menu_settings) { 390 startActivity(new Intent(this, SettingsActivity.class)); 391 return true; 392 } else { 393 return super.onOptionsItemSelected(item); 394 } 395 } 396 397 @Override 398 public void onBackPressed() { 399 final int size = mState.stack.size(); 400 if (size > 1) { 401 mState.stack.pop(); 402 onCurrentDirectoryChanged(); 403 } else if (size == 1 && !mDrawerLayout.isDrawerOpen(mRootsContainer)) { 404 // TODO: open root drawer once we can capture back key 405 super.onBackPressed(); 406 } else { 407 super.onBackPressed(); 408 } 409 } 410 411 @Override 412 protected void onSaveInstanceState(Bundle state) { 413 super.onSaveInstanceState(state); 414 state.putParcelable(EXTRA_STATE, mState); 415 } 416 417 @Override 418 protected void onRestoreInstanceState(Bundle state) { 419 super.onRestoreInstanceState(state); 420 updateActionBar(); 421 } 422 423 // TODO: support additional sort orders 424 private BaseAdapter mSortAdapter = new BaseAdapter() { 425 @Override 426 public int getCount() { 427 return mState.showSize ? 3 : 2; 428 } 429 430 @Override 431 public Object getItem(int position) { 432 switch (position) { 433 case 0: 434 return getText(R.string.sort_name); 435 case 1: 436 return getText(R.string.sort_date); 437 case 2: 438 return getText(R.string.sort_size); 439 default: 440 return null; 441 } 442 } 443 444 @Override 445 public long getItemId(int position) { 446 return position; 447 } 448 449 @Override 450 public View getView(int position, View convertView, ViewGroup parent) { 451 if (convertView == null) { 452 convertView = LayoutInflater.from(parent.getContext()) 453 .inflate(R.layout.item_title, parent, false); 454 } 455 456 final TextView title = (TextView) convertView.findViewById(android.R.id.title); 457 final TextView summary = (TextView) convertView.findViewById(android.R.id.summary); 458 459 if (mState.stack.size() > 0) { 460 title.setText(mState.stack.getTitle(mRoots)); 461 } else { 462 // No directory means recents 463 title.setText(R.string.root_recent); 464 } 465 466 summary.setText((String) getItem(position)); 467 468 return convertView; 469 } 470 471 @Override 472 public View getDropDownView(int position, View convertView, ViewGroup parent) { 473 if (convertView == null) { 474 convertView = LayoutInflater.from(parent.getContext()) 475 .inflate(android.R.layout.simple_dropdown_item_1line, parent, false); 476 } 477 478 final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1); 479 text1.setText((String) getItem(position)); 480 481 return convertView; 482 } 483 }; 484 485 private OnNavigationListener mSortListener = new OnNavigationListener() { 486 @Override 487 public boolean onNavigationItemSelected(int itemPosition, long itemId) { 488 mState.sortOrder = itemPosition; 489 updateDisplayState(); 490 return true; 491 } 492 }; 493 494 public RootInfo getCurrentRoot() { 495 if (mState.stack.size() > 0) { 496 return mState.stack.getRoot(mRoots); 497 } else { 498 return mRoots.getRecentsRoot(); 499 } 500 } 501 502 public DocumentInfo getCurrentDirectory() { 503 return mState.stack.peek(); 504 } 505 506 public State getDisplayState() { 507 return mState; 508 } 509 510 private void onCurrentDirectoryChanged() { 511 final FragmentManager fm = getFragmentManager(); 512 final DocumentInfo cwd = getCurrentDirectory(); 513 514 if (cwd == null) { 515 // No directory means recents 516 if (mState.action == ACTION_CREATE) { 517 RecentsCreateFragment.show(fm); 518 } else { 519 DirectoryFragment.showRecentsOpen(fm); 520 } 521 } else { 522 if (mState.currentSearch != null) { 523 // Ongoing search 524 DirectoryFragment.showSearch(fm, cwd.uri, mState.currentSearch); 525 } else { 526 // Normal boring directory 527 DirectoryFragment.showNormal(fm, cwd.uri); 528 } 529 } 530 531 // Forget any replacement target 532 if (mState.action == ACTION_CREATE) { 533 final SaveFragment save = SaveFragment.get(fm); 534 if (save != null) { 535 save.setReplaceTarget(null); 536 } 537 } 538 539 updateActionBar(); 540 invalidateOptionsMenu(); 541 dumpStack(); 542 } 543 544 private void updateDisplayState() { 545 // TODO: handle multiple directory stacks on tablets 546 DirectoryFragment.get(getFragmentManager()).updateDisplayState(); 547 } 548 549 public void onStackPicked(DocumentStack stack) { 550 mState.stack = stack; 551 onCurrentDirectoryChanged(); 552 } 553 554 public void onRootPicked(RootInfo root, boolean closeDrawer) { 555 // Clear entire backstack and start in new root 556 mState.stack.clear(); 557 558 if (!mRoots.isRecentsRoot(root)) { 559 try { 560 final Uri uri = DocumentsContract.buildDocumentUri(root.authority, root.documentId); 561 onDocumentPicked(DocumentInfo.fromUri(getContentResolver(), uri)); 562 } catch (FileNotFoundException e) { 563 } 564 } else { 565 onCurrentDirectoryChanged(); 566 } 567 568 if (closeDrawer) { 569 mDrawerLayout.closeDrawers(); 570 } 571 } 572 573 public void onAppPicked(ResolveInfo info) { 574 final Intent intent = new Intent(getIntent()); 575 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 576 intent.setComponent(new ComponentName( 577 info.activityInfo.applicationInfo.packageName, info.activityInfo.name)); 578 startActivity(intent); 579 finish(); 580 } 581 582 public void onDocumentPicked(DocumentInfo doc) { 583 final FragmentManager fm = getFragmentManager(); 584 if (doc.isDirectory()) { 585 // TODO: query display mode user preference for this dir 586 if (doc.isGridPreferred()) { 587 mState.mode = MODE_GRID; 588 } else { 589 mState.mode = MODE_LIST; 590 } 591 mState.stack.push(doc); 592 onCurrentDirectoryChanged(); 593 } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { 594 // Explicit file picked, return 595 onFinished(doc.uri); 596 } else if (mState.action == ACTION_CREATE) { 597 // Replace selected file 598 SaveFragment.get(fm).setReplaceTarget(doc); 599 } else if (mState.action == ACTION_MANAGE) { 600 // Open the document 601 final Intent intent = new Intent(Intent.ACTION_VIEW); 602 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 603 intent.setData(doc.uri); 604 try { 605 startActivity(intent); 606 } catch (ActivityNotFoundException ex) { 607 Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); 608 } 609 } 610 } 611 612 public void onDocumentsPicked(List<DocumentInfo> docs) { 613 if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { 614 final int size = docs.size(); 615 final Uri[] uris = new Uri[size]; 616 for (int i = 0; i < size; i++) { 617 uris[i] = docs.get(i).uri; 618 } 619 onFinished(uris); 620 } 621 } 622 623 public void onSaveRequested(DocumentInfo replaceTarget) { 624 onFinished(replaceTarget.uri); 625 } 626 627 public void onSaveRequested(String mimeType, String displayName) { 628 final DocumentInfo cwd = getCurrentDirectory(); 629 final String authority = cwd.uri.getAuthority(); 630 631 final ContentProviderClient client = getContentResolver() 632 .acquireUnstableContentProviderClient(authority); 633 try { 634 final Uri childUri = DocumentsContract.createDocument( 635 getContentResolver(), cwd.uri, mimeType, displayName); 636 onFinished(childUri); 637 } catch (Exception e) { 638 Toast.makeText(this, R.string.save_error, Toast.LENGTH_SHORT).show(); 639 } finally { 640 ContentProviderClient.closeQuietly(client); 641 } 642 } 643 644 private void onFinished(Uri... uris) { 645 Log.d(TAG, "onFinished() " + Arrays.toString(uris)); 646 647 final ContentResolver resolver = getContentResolver(); 648 final ContentValues values = new ContentValues(); 649 650 final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); 651 if (mState.action == ACTION_CREATE) { 652 // Remember stack for last create 653 values.clear(); 654 values.put(RecentsProvider.COL_PATH, rawStack); 655 resolver.insert(RecentsProvider.buildRecentCreate(), values); 656 657 } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { 658 // Remember opened items 659 for (Uri uri : uris) { 660 values.clear(); 661 values.put(RecentsProvider.COL_URI, uri.toString()); 662 resolver.insert(RecentsProvider.buildRecentOpen(), values); 663 } 664 } 665 666 // Remember location for next app launch 667 final String packageName = getCallingPackage(); 668 values.clear(); 669 values.put(RecentsProvider.COL_PATH, rawStack); 670 resolver.insert(RecentsProvider.buildResume(packageName), values); 671 672 final Intent intent = new Intent(); 673 if (uris.length == 1) { 674 intent.setData(uris[0]); 675 } else if (uris.length > 1) { 676 final ClipData clipData = new ClipData( 677 null, mState.acceptMimes, new ClipData.Item(uris[0])); 678 for (int i = 1; i < uris.length; i++) { 679 clipData.addItem(new ClipData.Item(uris[i])); 680 } 681 intent.setClipData(clipData); 682 } 683 684 if (mState.action == ACTION_GET_CONTENT) { 685 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 686 } else { 687 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 688 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION 689 | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION); 690 } 691 692 setResult(Activity.RESULT_OK, intent); 693 finish(); 694 } 695 696 public static class State implements android.os.Parcelable { 697 public int action; 698 public int mode = MODE_LIST; 699 public String[] acceptMimes; 700 public int sortOrder = SORT_ORDER_DISPLAY_NAME; 701 public boolean allowMultiple = false; 702 public boolean showSize = false; 703 public boolean localOnly = false; 704 705 /** Current user navigation stack; empty implies recents. */ 706 public DocumentStack stack = new DocumentStack(); 707 /** Currently active search, overriding any stack. */ 708 public String currentSearch; 709 710 public static final int ACTION_OPEN = 1; 711 public static final int ACTION_CREATE = 2; 712 public static final int ACTION_GET_CONTENT = 3; 713 public static final int ACTION_MANAGE = 4; 714 715 public static final int MODE_LIST = 0; 716 public static final int MODE_GRID = 1; 717 718 public static final int SORT_ORDER_DISPLAY_NAME = 0; 719 public static final int SORT_ORDER_LAST_MODIFIED = 1; 720 public static final int SORT_ORDER_SIZE = 2; 721 722 @Override 723 public int describeContents() { 724 return 0; 725 } 726 727 @Override 728 public void writeToParcel(Parcel out, int flags) { 729 out.writeInt(action); 730 out.writeInt(mode); 731 out.writeStringArray(acceptMimes); 732 out.writeInt(sortOrder); 733 out.writeInt(allowMultiple ? 1 : 0); 734 out.writeInt(showSize ? 1 : 0); 735 out.writeInt(localOnly ? 1 : 0); 736 DurableUtils.writeToParcel(out, stack); 737 out.writeString(currentSearch); 738 } 739 740 public static final Creator<State> CREATOR = new Creator<State>() { 741 @Override 742 public State createFromParcel(Parcel in) { 743 final State state = new State(); 744 state.action = in.readInt(); 745 state.mode = in.readInt(); 746 state.acceptMimes = in.readStringArray(); 747 state.sortOrder = in.readInt(); 748 state.allowMultiple = in.readInt() != 0; 749 state.showSize = in.readInt() != 0; 750 state.localOnly = in.readInt() != 0; 751 DurableUtils.readFromParcel(in, state.stack); 752 state.currentSearch = in.readString(); 753 return state; 754 } 755 756 @Override 757 public State[] newArray(int size) { 758 return new State[size]; 759 } 760 }; 761 } 762 763 private void dumpStack() { 764 Log.d(TAG, "Current stack:"); 765 for (DocumentInfo doc : mState.stack) { 766 Log.d(TAG, "--> " + doc); 767 } 768 } 769 770 public static DocumentsActivity get(Fragment fragment) { 771 return (DocumentsActivity) fragment.getActivity(); 772 } 773} 774