content: /*
   * 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 dev.dworks.apps.anexplorer;
  
  import android.app.Activity;
  import android.app.Fragment;
  import android.app.FragmentManager;
  import android.content.ActivityNotFoundException;
  import android.content.ClipData;
  import android.content.ComponentName;
  import android.content.ContentProviderClient;
  import android.content.ContentResolver;
  import android.content.ContentValues;
  import android.content.Context;
  import android.content.Intent;
  import android.content.pm.ResolveInfo;
  import android.content.res.Resources;
  import android.database.Cursor;
  import android.graphics.Point;
  import android.net.Uri;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import androidx.appcompat.app.ActionBarDrawerToggle;
  import androidx.recyclerview.widget.RecyclerView;
  import androidx.appcompat.widget.Toolbar;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.MenuItem.OnActionExpandListener;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.WindowManager;
  import android.widget.AbsListView;
  import android.widget.AdapterView;
  import android.widget.AdapterView.OnItemSelectedListener;
  import android.widget.BaseAdapter;
  import android.widget.ImageView;
  import android.widget.SearchView;
  import android.widget.SearchView.OnQueryTextListener;
  import android.widget.Spinner;
  import android.widget.TextView;
  import android.widget.Toast;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;
  import java.util.concurrent.Executor;
  
  import dev.dworks.apps.anexplorer.common.RootsCommonFragment;
  import dev.dworks.apps.anexplorer.fragment.CreateDirectoryFragment;
  import dev.dworks.apps.anexplorer.fragment.DirectoryFragment;
  import dev.dworks.apps.anexplorer.fragment.RootsFragment;
  import dev.dworks.apps.anexplorer.fragment.SaveFragment;
  import dev.dworks.apps.anexplorer.libcore.io.IoUtils;
  import dev.dworks.apps.anexplorer.misc.ContentProviderClientCompat;
  import dev.dworks.apps.anexplorer.misc.MimePredicate;
  import dev.dworks.apps.anexplorer.misc.ProviderExecutor;
  import dev.dworks.apps.anexplorer.misc.RootsCache;
  import dev.dworks.apps.anexplorer.misc.Utils;
  import dev.dworks.apps.anexplorer.model.DocumentInfo;
  import dev.dworks.apps.anexplorer.model.DocumentStack;
  import dev.dworks.apps.anexplorer.model.DocumentsContract;
  import dev.dworks.apps.anexplorer.model.DurableUtils;
  import dev.dworks.apps.anexplorer.model.RootInfo;
  import dev.dworks.apps.anexplorer.provider.RecentsProvider;
  import dev.dworks.apps.anexplorer.provider.RecentsProvider.ResumeColumns;
  import dev.dworks.apps.anexplorer.setting.SettingsActivity;
  
  import static dev.dworks.apps.anexplorer.fragment.DirectoryFragment.ANIM_DOWN;
  import static dev.dworks.apps.anexplorer.fragment.DirectoryFragment.ANIM_NONE;
  import static dev.dworks.apps.anexplorer.fragment.DirectoryFragment.ANIM_SIDE;
  import static dev.dworks.apps.anexplorer.fragment.DirectoryFragment.ANIM_UP;
  
  public class StandaloneActivity extends BaseActivity {
      public static final String TAG = "StandaloneActivity";
      private static final String EXTRA_STATE = "state";
      private static final int CODE_FORWARD = 42;
      private SearchView mSearchView;
      private Toolbar mToolbar;
      private Spinner mToolbarStack;
      private Toolbar mRootsToolbar;
      private ActionBarDrawerToggle mDrawerToggle;
      private boolean mIgnoreNextNavigation;
      private boolean mIgnoreNextClose;
      private boolean mIgnoreNextCollapse;
      private boolean mSearchExpanded;
      private RootsCache mRoots;
      private State mState;
      @Override
      public void onCreate(Bundle icicle) {
          if(Utils.hasLollipop()){
              getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
          }
          else if(Utils.hasKitKat()){
              setTheme(R.style.DocumentsTheme_Translucent);
          }
          setUpStatusBar();
          // Debug.waitForDebugger();
          super.onCreate(icicle);
          mRoots = DocumentsApplication.getRootsCache(this);
          setResult(Activity.RESULT_CANCELED);
          setContentView(R.layout.activity);
          final Context context = this;
          final Resources res = getResources();
          // Strongly define our horizontal dimension; we leave vertical as
          final WindowManager.LayoutParams a = getWindow().getAttributes();
          final Point size = new Point();
          getWindowManager().getDefaultDisplay().getSize(size);
          // a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
          getWindow().setAttributes(a);
          if (icicle != null) {
              mState = icicle.getParcelable(EXTRA_STATE);
          } else {
              buildDefaultState();
          }
          mToolbar = (Toolbar) findViewById(R.id.toolbar);
          mToolbar.setTitleTextAppearance(context,
                  android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
          mToolbarStack = (Spinner) findViewById(R.id.stack);
          mToolbarStack.setOnItemSelectedListener(mStackListener);
          mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
          if (mRootsToolbar != null) {
              mRootsToolbar.setTitleTextAppearance(context,
                      android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
          }
          setSupportActionBar(mToolbar);
          RootsCommonFragment.show(getFragmentManager(), null);
          if (!mState.restored) {
              new RestoreStackTask().execute();
          } else {
              onCurrentDirectoryChanged(ANIM_NONE);
          }
      }
  
      @Override
      public String getTag() {
          return null;
      }
  
      private void buildDefaultState() {
          mState = new State();
          final Intent intent = getIntent();
          mState.action = State.ACTION_MANAGE_ALL;
          mState.acceptMimes = new String[] { "*/*" };
          mState.allowMultiple = true;
          mState.acceptMimes = new String[] { intent.getType() };
          mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
          mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
          mState.showAdvanced = mState.forceAdvanced
                  | SettingsActivity.getDisplayAdvancedDevices(this);
          mState.showSize = true;
      }
      private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
          private Uri mRootUri;
          public RestoreRootTask(Uri rootUri) {
              mRootUri = rootUri;
          }
          @Override
          protected RootInfo doInBackground(Void... params) {
              final String rootId = DocumentsContract.getRootId(mRootUri);
              return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
          }
          @Override
          protected void onPostExecute(RootInfo root) {
              if (isDestroyed()) return;
              mState.restored = true;
              if (root != null) {
                  onRootPicked(root, true);
              } else {
                  Log.w(TAG, "Failed to find root: " + mRootUri);
                  finish();
              }
          }
      }
      private class RestoreStackTask extends AsyncTask<Void, Void, Void> {
          private volatile boolean mRestoredStack;
          private volatile boolean mExternal;
          @Override
          protected Void doInBackground(Void... params) {
              // Restore last stack for calling package
              final String packageName = getCallingPackageMaybeExtra();
              final Cursor cursor = getContentResolver()
                      .query(RecentsProvider.buildResume(packageName), null, null, null, null);
              try {
                  if (cursor.moveToFirst()) {
                      mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
                      final byte[] rawStack = cursor.getBlob(
                              cursor.getColumnIndex(ResumeColumns.STACK));
                      DurableUtils.readFromArray(rawStack, mState.stack);
                      mRestoredStack = true;
                  }
              } catch (IOException e) {
                  Log.w(TAG, "Failed to resume: " + e);
              } finally {
                  IoUtils.closeQuietly(cursor);
              }
              if (mRestoredStack) {
                  // Update the restored stack to ensure we have freshest data
                  final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
                  try {
                      mState.stack.updateRoot(matchingRoots);
                      mState.stack.updateDocuments(getContentResolver());
                  } catch (FileNotFoundException e) {
                      Log.w(TAG, "Failed to restore stack: " + e);
                      mState.stack.reset();
                      mRestoredStack = false;
                  }
              }
              return null;
          }
          @Override
          protected void onPostExecute(Void result) {
              if (isDestroyed()) return;
              mState.restored = true;
              onCurrentDirectoryChanged(ANIM_NONE);
          }
      }
      @Override
      protected void onPostCreate(Bundle savedInstanceState) {
          super.onPostCreate(savedInstanceState);
          if (mDrawerToggle != null) {
              mDrawerToggle.syncState();
          }
          updateActionBar();
      }
      @Override
      public void setRootsDrawerOpen(boolean open) {
          Log.w(TAG, "Trying to change state of roots drawer to > " + (open ? "open" : "closed"));
        // throw new UnsupportedOperationException();
      }
      public void updateActionBar() {
          final RootInfo root = getCurrentRoot();
          mToolbar.setNavigationIcon(
                  root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
          mToolbar.setNavigationContentDescription(R.string.drawer_open);
          mToolbar.setNavigationOnClickListener(null);
          if (mSearchExpanded) {
              mToolbar.setTitle(null);
              mToolbarStack.setVisibility(View.GONE);
              mToolbarStack.setAdapter(null);
          } else {
              if (mState.stack.size() <= 1) {
                  mToolbar.setTitle(root.title);
                  mToolbarStack.setVisibility(View.GONE);
                  mToolbarStack.setAdapter(null);
              } else {
                  mToolbar.setTitle(null);
                  mToolbarStack.setVisibility(View.VISIBLE);
                  mToolbarStack.setAdapter(mStackAdapter);
                  mIgnoreNextNavigation = true;
                  mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
              }
          }
      }
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          super.onCreateOptionsMenu(menu);
          getMenuInflater().inflate(R.menu.activity, menu);
          for (int i = 0; i < menu.size(); i++) {
              final MenuItem item = menu.getItem(i);
              switch (item.getItemId()) {
                  default:
                      item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
              }
          }
          final MenuItem searchMenu = menu.findItem(R.id.menu_search);
          mSearchView = (SearchView) searchMenu.getActionView();
          mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
              @Override
              public boolean onQueryTextSubmit(String query) {
                  mSearchExpanded = true;
                  mState.currentSearch = query;
                  mSearchView.clearFocus();
                  onCurrentDirectoryChanged(ANIM_NONE);
                  return true;
              }
              @Override
              public boolean onQueryTextChange(String newText) {
                  return false;
              }
          });
          searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
              @Override
              public boolean onMenuItemActionExpand(MenuItem item) {
                  mSearchExpanded = true;
                  updateActionBar();
                  return true;
              }
              @Override
              public boolean onMenuItemActionCollapse(MenuItem item) {
                  mSearchExpanded = false;
                  if (mIgnoreNextCollapse) {
                      mIgnoreNextCollapse = false;
                      return true;
                  }
                  mState.currentSearch = null;
                  onCurrentDirectoryChanged(ANIM_NONE);
                  return true;
              }
          });
          mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
              @Override
              public boolean onClose() {
                  mSearchExpanded = false;
                  if (mIgnoreNextClose) {
                      mIgnoreNextClose = false;
                      return false;
                  }
                  mState.currentSearch = null;
                  onCurrentDirectoryChanged(ANIM_NONE);
                  return false;
              }
          });
          return true;
      }
      @Override
      public boolean onPrepareOptionsMenu(Menu menu) {
          super.onPrepareOptionsMenu(menu);
          final FragmentManager fm = getFragmentManager();
          final RootInfo root = getCurrentRoot();
          final DocumentInfo cwd = getCurrentDirectory();
          final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
          final MenuItem search = menu.findItem(R.id.menu_search);
          final MenuItem sort = menu.findItem(R.id.menu_sort);
          final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
          final MenuItem grid = menu.findItem(R.id.menu_grid);
          final MenuItem list = menu.findItem(R.id.menu_list);
          sort.setVisible(cwd != null);
          grid.setVisible(mState.derivedMode != State.MODE_GRID);
          list.setVisible(mState.derivedMode != State.MODE_LIST);
          if (mState.currentSearch != null) {
              // Search uses backend ranking; no sorting
              sort.setVisible(false);
              search.expandActionView();
              mSearchView.setIconified(false);
              mSearchView.clearFocus();
              mSearchView.setQuery(mState.currentSearch, false);
          } else {
              mIgnoreNextClose = true;
              mSearchView.setIconified(true);
              mSearchView.clearFocus();
              mIgnoreNextCollapse = true;
              search.collapseActionView();
          }
          // Only sort by size when visible
          sortSize.setVisible(mState.showSize);
          search.setVisible(true);
          createDir.setVisible(true);
          return true;
      }
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
              return true;
          }
          final int id = item.getItemId();
          if (id == android.R.id.home) {
              onBackPressed();
              return true;
          } else if (id == R.id.menu_create_dir) {
              CreateDirectoryFragment.show(getSupportFragmentManager());
              return true;
          } else if (id == R.id.menu_search) {
              return false;
          } else if (id == R.id.menu_sort_name) {
              setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
              return true;
          } else if (id == R.id.menu_sort_date) {
              setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
              return true;
          } else if (id == R.id.menu_sort_size) {
              setUserSortOrder(State.SORT_ORDER_SIZE);
              return true;
          } else if (id == R.id.menu_grid) {
              setUserMode(State.MODE_GRID);
              return true;
          } else if (id == R.id.menu_list) {
              setUserMode(State.MODE_LIST);
              return true;
          } else {
              return super.onOptionsItemSelected(item);
          }
      }
  
      @Override
      public void onStateChanged() {
          supportInvalidateOptionsMenu();
      }
      /**
       * Set state sort order based on explicit user action.
       */
      private void setUserSortOrder(int sortOrder) {
          mState.userSortOrder = sortOrder;
          Fragment fragment = DirectoryFragment.get(getFragmentManager());
          if(fragment instanceof DirectoryFragment) {
              final DirectoryFragment directory = (DirectoryFragment) fragment;
              directory.onUserSortOrderChanged();
          }
      }
      /**
       * Set state mode based on explicit user action.
       */
      private void setUserMode(int mode) {
          mState.userMode = mode;
          Fragment fragment = DirectoryFragment.get(getFragmentManager());
          if(fragment instanceof DirectoryFragment) {
              final DirectoryFragment directory = (DirectoryFragment) fragment;
              directory.onUserModeChanged();
          }
      }
      @Override
      public void setPending(boolean pending) {
          final SaveFragment save = SaveFragment.get(getFragmentManager());
          if (save != null) {
              save.setPending(pending);
          }
      }
      @Override
      public void onBackPressed() {
          if (!mState.stackTouched) {
              super.onBackPressed();
              return;
          }
          final int size = mState.stack.size();
          if (size > 1) {
              mState.stack.pop();
              onCurrentDirectoryChanged(ANIM_UP);
          } else {
              super.onBackPressed();
          }
      }
      @Override
      protected void onSaveInstanceState(Bundle state) {
          super.onSaveInstanceState(state);
          state.putParcelable(EXTRA_STATE, mState);
      }
      @Override
      protected void onRestoreInstanceState(Bundle state) {
          super.onRestoreInstanceState(state);
      }
      private BaseAdapter mStackAdapter = new BaseAdapter() {
          @Override
          public int getCount() {
              return mState.stack.size();
          }
          @Override
          public DocumentInfo getItem(int position) {
              return mState.stack.get(mState.stack.size() - position - 1);
          }
          @Override
          public long getItemId(int position) {
              return position;
          }
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
              if (convertView == null) {
                  convertView = LayoutInflater.from(parent.getContext())
                          .inflate(R.layout.item_subdir_title, parent, false);
              }
              final TextView title = (TextView) convertView.findViewById(android.R.id.title);
              final DocumentInfo doc = getItem(position);
              if (position == 0) {
                  final RootInfo root = getCurrentRoot();
                  title.setText(root.title);
              } else {
                  title.setText(doc.displayName);
              }
              return convertView;
          }
          @Override
          public View getDropDownView(int position, View convertView, ViewGroup parent) {
              if (convertView == null) {
                  convertView = LayoutInflater.from(parent.getContext())
                          .inflate(R.layout.item_subdir, parent, false);
              }
              final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
              final TextView title = (TextView) convertView.findViewById(android.R.id.title);
              final DocumentInfo doc = getItem(position);
              if (position == 0) {
                  final RootInfo root = getCurrentRoot();
                  title.setText(root.title);
                  subdir.setVisibility(View.GONE);
              } else {
                  title.setText(doc.displayName);
                  subdir.setVisibility(View.VISIBLE);
              }
              return convertView;
          }
      };
      private OnItemSelectedListener mStackListener = new OnItemSelectedListener() {
          @Override
          public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
              if (mIgnoreNextNavigation) {
                  mIgnoreNextNavigation = false;
                  return;
              }
              while (mState.stack.size() > position + 1) {
                  mState.stackTouched = true;
                  mState.stack.pop();
              }
              onCurrentDirectoryChanged(ANIM_UP);
          }
          @Override
          public void onNothingSelected(AdapterView<?> parent) {
              // Ignored
          }
      };
      @Override
      public RootInfo getCurrentRoot() {
          if (mState.stack.root != null) {
              return mState.stack.root;
          } else {
              return mRoots.getHomeRoot();
          }
      }
  
      public RootInfo getDownloadRoot() {
          return mRoots.getDownloadRoot();
      }
  
      @Override
      public boolean getActionMode() {
          return false;
      }
  
      @Override
      public void setActionMode(boolean actionMode) {
  
      }
  
      @Override
      public void setUpStatusBar() {
  
      }
  
      @Override
      public void setUpDefaultStatusBar() {
  
      }
  
      @Override
      public boolean isShowAsDialog() {
          return false;
      }
  
      @Override
      public void upadateActionItems(RecyclerView mCurrentView) {
  
      }
  
      @Override
      public void setInfoDrawerOpen(boolean open) {
  
      }
  
      @Override
      public void again() {
  
      }
  
      public DocumentInfo getCurrentDirectory() {
          return mState.stack.peek();
      }
  
      private String getCallingPackageMaybeExtra() {
          final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME);
          return (extra != null) ? extra : getCallingPackage();
      }
      public Executor getCurrentExecutor() {
          final DocumentInfo cwd = getCurrentDirectory();
          if (cwd != null && cwd.authority != null) {
              return ProviderExecutor.forAuthority(cwd.authority);
          } else {
              return AsyncTask.THREAD_POOL_EXECUTOR;
          }
      }
      @Override
      public State getDisplayState() {
          return mState;
      }
  
      private void onCurrentDirectoryChanged(int anim) {
          final FragmentManager fm = getFragmentManager();
          final RootInfo root = getCurrentRoot();
          final DocumentInfo cwd = getCurrentDirectory();
          if (cwd == null) {
              DirectoryFragment.showRecentsOpen(fm, anim, root);
              // Start recents in grid when requesting visual things
              final boolean visualMimes = MimePredicate.mimeMatches(
                      MimePredicate.VISUAL_MIMES, mState.acceptMimes);
              mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
              mState.derivedMode = mState.userMode;
          } else {
              if (mState.currentSearch != null) {
                  // Ongoing search
                  DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch, anim);
              } else {
                  // Normal boring directory
                  DirectoryFragment.showNormal(fm, root, cwd, anim);
              }
          }
          final RootsCommonFragment roots = RootsCommonFragment.get(fm);
          if (roots != null) {
              roots.onCurrentRootChanged();
          }
          updateActionBar();
          supportInvalidateOptionsMenu();
          dumpStack();
      }
      @Override
      public void onStackPicked(DocumentStack stack) {
          try {
              // Update the restored stack to ensure we have freshest data
              stack.updateDocuments(getContentResolver());
              mState.stack = stack;
              mState.stackTouched = true;
              onCurrentDirectoryChanged(ANIM_SIDE);
          } catch (FileNotFoundException e) {
              Log.w(TAG, "Failed to restore stack: " + e);
          }
      }
      @Override
      public void onRootPicked(RootInfo root, boolean closeDrawer) {
          // Clear entire backstack and start in new root
          mState.stack.root = root;
          mState.stack.clear();
          mState.stackTouched = true;
          if (!mRoots.isRecentsRoot(root)) {
              new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
          } else {
              onCurrentDirectoryChanged(ANIM_SIDE);
          }
      }
      private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
          private RootInfo mRoot;
          public PickRootTask(RootInfo root) {
              mRoot = root;
          }
          @Override
          protected DocumentInfo doInBackground(Void... params) {
              try {
                  final Uri uri = DocumentsContract.buildDocumentUri(
                          mRoot.authority, mRoot.documentId);
                  return DocumentInfo.fromUri(getContentResolver(), uri);
              } catch (FileNotFoundException e) {
                  Log.w(TAG, "Failed to find root", e);
                  return null;
              }
          }
          @Override
          protected void onPostExecute(DocumentInfo result) {
              if (result != null) {
                  mState.stack.push(result);
                  mState.stackTouched = true;
                  onCurrentDirectoryChanged(ANIM_SIDE);
              }
          }
      }
      @Override
      public void onAppPicked(ResolveInfo info) {
          final Intent intent = new Intent(getIntent());
          intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
          intent.setComponent(new ComponentName(
                  info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
          startActivityForResult(intent, CODE_FORWARD);
      }
      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
          Log.d(TAG, "onActivityResult() code=" + resultCode);
          // Only relay back results when not canceled; otherwise stick around to
          // let the user pick another app/backend.
          if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) {
              // Remember that we last picked via external app
              final String packageName = getCallingPackageMaybeExtra();
              final ContentValues values = new ContentValues();
              values.put(ResumeColumns.EXTERNAL, 1);
              getContentResolver().insert(RecentsProvider.buildResume(packageName), values);
              // Pass back result to original caller
              setResult(resultCode, data);
              finish();
          } else {
              super.onActivityResult(requestCode, resultCode, data);
          }
      }
      @Override
      public void onDocumentPicked(DocumentInfo doc) {
          final FragmentManager fm = getFragmentManager();
          if (doc.isDirectory()) {
              mState.stack.push(doc);
              mState.stackTouched = true;
              onCurrentDirectoryChanged(ANIM_DOWN);
          } else {
              // Fall back to viewing
              final Intent view = new Intent(Intent.ACTION_VIEW);
              view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
              view.setData(doc.derivedUri);
              try {
                  startActivity(view);
              } catch (ActivityNotFoundException ex2) {
                  Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
              }
          }
      }
      public void onDocumentsPicked(List<DocumentInfo> docs) {
          // TODO
      }
      @Override
      public void onSaveRequested(DocumentInfo replaceTarget) {
          new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
      }
      @Override
      public void onSaveRequested(String mimeType, String displayName) {
          new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
      }
  
      @Override
      public boolean isCreateSupported() {
          return false;
      }
  
      @Override
      public void onPickRequested(DocumentInfo pickTarget) {
          final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
                  pickTarget.documentId);
          new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor());
      }
      private void saveStackBlocking() {
          final ContentResolver resolver = getContentResolver();
          final ContentValues values = new ContentValues();
          final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
          // Remember location for next app launch
          final String packageName = getCallingPackageMaybeExtra();
          values.clear();
          values.put(ResumeColumns.STACK, rawStack);
          values.put(ResumeColumns.EXTERNAL, 0);
          resolver.insert(RecentsProvider.buildResume(packageName), values);
      }
      private void onFinished(Uri... uris) {
          Log.d(TAG, "onFinished() " + Arrays.toString(uris));
          final Intent intent = new Intent();
          if (uris.length == 1) {
              intent.setData(uris[0]);
          } else if (uris.length > 1) {
              final ClipData clipData = new ClipData(
                      null, mState.acceptMimes, new ClipData.Item(uris[0]));
              for (int i = 1; i < uris.length; i++) {
                  clipData.addItem(new ClipData.Item(uris[i]));
              }
              if(Utils.hasJellyBean()){
                  intent.setClipData(clipData);
              }
              else{
                  intent.setData(uris[0]);
              }
          }
          intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                  | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                  | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
          setResult(Activity.RESULT_OK, intent);
          finish();
      }
      private class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
          private final String mMimeType;
          private final String mDisplayName;
          public CreateFinishTask(String mimeType, String displayName) {
              mMimeType = mimeType;
              mDisplayName = displayName;
          }
          @Override
          protected void onPreExecute() {
              setPending(true);
          }
          @Override
          protected Uri doInBackground(Void... params) {
              final ContentResolver resolver = getContentResolver();
              final DocumentInfo cwd = getCurrentDirectory();
              ContentProviderClient client = null;
              Uri childUri = null;
              try {
                  client = DocumentsApplication.acquireUnstableProviderOrThrow(
                          resolver, cwd.derivedUri.getAuthority());
  
                  childUri = DocumentsContract.createDocument(
                          resolver, cwd.derivedUri, mMimeType, mDisplayName);
              } catch (Exception e) {
                  Log.w(TAG, "Failed to create document", e);
              } finally {
                  ContentProviderClientCompat.releaseQuietly(client);
              }
              if (childUri != null) {
                  saveStackBlocking();
              }
              return childUri;
          }
          @Override
          protected void onPostExecute(Uri result) {
              if (result != null) {
                  onFinished(result);
              } else {
                  Toast.makeText(StandaloneActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
                          .show();
              }
              setPending(false);
          }
      }
      private class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
          private final Uri[] mUris;
          public ExistingFinishTask(Uri... uris) {
              mUris = uris;
          }
          @Override
          protected Void doInBackground(Void... params) {
              saveStackBlocking();
              return null;
          }
          @Override
          protected void onPostExecute(Void result) {
              onFinished(mUris);
          }
      }
      private class PickFinishTask extends AsyncTask<Void, Void, Void> {
          private final Uri mUri;
          public PickFinishTask(Uri uri) {
              mUri = uri;
          }
          @Override
          protected Void doInBackground(Void... params) {
              saveStackBlocking();
              return null;
          }
          @Override
          protected void onPostExecute(Void result) {
              onFinished(mUri);
          }
      }
      private void dumpStack() {
          Log.d(TAG, "Current stack: ");
          Log.d(TAG, " * " + mState.stack.root);
          for (DocumentInfo doc : mState.stack) {
              Log.d(TAG, " +-- " + doc);
          }
      }
      public static BaseActivity get(Fragment fragment) {
          return (BaseActivity) fragment.getActivity();
      }
  }