Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 893390bd authored by Aga Wronska's avatar Aga Wronska
Browse files

Directory fragment refactoring.

First attempt to to refactor fragments handling, state and app lifecycle.

The goal was to simplify code by using android built lifecycle
mechanism, eliminate bugs caused by multiple creation of the fragment,
see the performance impact and give some fundament for refactoring of
fragments and activities in the app.

Search view manager:
    * Remove curentSearch from state
    * Restore search from saved state (ex. after rotation)
    * Rename file  to give the better overview of its purpose

Directory fragment:
    * Store selection state in a bundle
    * Remove double creation of fragment
    * Use loaders to reload content when possible
    * Keep info about state inside the object
    * Refactor available types of fragment to be normal and recents
    * Make search type a mode possibly available in all types
    * Remove search being invoked from refresh method
    * Do search by reloading fragments content instead of recreation as
      an example

Other:
    * Fix window title maybe

Bug: 26968405, 27101786
Change-Id: I58f36cd0a3e3a6ec98996cd8aac16e10e425e1fe
parent 855d408e
Loading
Loading
Loading
Loading
+22 −18
Original line number Diff line number Diff line
@@ -23,9 +23,11 @@ import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -46,7 +48,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.Spinner;

import com.android.documentsui.SearchManager.SearchManagerListener;
import com.android.documentsui.SearchViewManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.dirlist.Model;
@@ -64,14 +66,12 @@ import java.util.concurrent.Executor;
public abstract class BaseActivity extends Activity
        implements SearchManagerListener, NavigationView.Environment {

    static final String EXTRA_STATE = "state";

    // See comments where this const is referenced for details.
    private static final int DRAWER_NO_FIDDLE_DELAY = 1500;

    State mState;
    RootsCache mRoots;
    SearchManager mSearchManager;
    SearchViewManager mSearchManager;
    DrawerController mDrawer;
    NavigationView mNavigator;

@@ -121,7 +121,7 @@ public abstract class BaseActivity extends Activity
                    }
                });

        mSearchManager = new SearchManager(this);
        mSearchManager = new SearchViewManager(this, icicle);

        DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
        setActionBar(toolbar);
@@ -141,6 +141,7 @@ public abstract class BaseActivity extends Activity
        boolean showMenu = super.onCreateOptionsMenu(menu);

        getMenuInflater().inflate(R.menu.activity, menu);
        mNavigator.update();
        mSearchManager.install((DocumentsToolbar) findViewById(R.id.toolbar));

        return showMenu;
@@ -188,7 +189,7 @@ public abstract class BaseActivity extends Activity

    private State getState(@Nullable Bundle icicle) {
        if (icicle != null) {
            State state = icicle.<State>getParcelable(EXTRA_STATE);
            State state = icicle.<State>getParcelable(Shared.EXTRA_STATE);
            if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state);
            return state;
        }
@@ -224,6 +225,9 @@ public abstract class BaseActivity extends Activity
    }

    void onRootPicked(RootInfo root) {
        // Clicking on the current root removes search
        mSearchManager.cancelSearch();

        // Skip refreshing if root nor directory didn't change
        if (root.equals(getCurrentRoot()) && mState.stack.size() == 1) {
            return;
@@ -233,7 +237,6 @@ public abstract class BaseActivity extends Activity

        // Clear entire backstack and start in new root
        mState.onRootChanged(root);
        mSearchManager.update(root);

        // Recents is always in memory, so we just load it directly.
        // Otherwise we delegate loading data from disk to a task
@@ -370,18 +373,18 @@ public abstract class BaseActivity extends Activity
     * e.g. The current directory name displayed on the action bar won't get updated.
     */
    @Override
    public void onSearchChanged() {
        refreshDirectory(ANIM_NONE);
    public void onSearchChanged(@Nullable String query) {
        // We should not get here if root is not searchable
        checkState(canSearchRoot());
        reloadSearch(query);
    }

    /**
     * Called when search query changed.
     * Updates the state object.
     * @param query - New query
     */
    @Override
    public void onSearchQueryChanged(String query) {
        mState.currentSearch = query;
    private void reloadSearch(String query) {
        FragmentManager fm = getFragmentManager();
        RootInfo root = getCurrentRoot();
        DocumentInfo cwd = getCurrentDirectory();

        DirectoryFragment.reloadSearch(fm, root, cwd, query);
    }

    final List<String> getExcludedAuthorities() {
@@ -486,7 +489,8 @@ public abstract class BaseActivity extends Activity
    @Override
    protected void onSaveInstanceState(Bundle state) {
        super.onSaveInstanceState(state);
        state.putParcelable(EXTRA_STATE, mState);
        state.putParcelable(Shared.EXTRA_STATE, mState);
        mSearchManager.onSaveInstanceState(state);
    }

    @Override
+7 −4
Original line number Diff line number Diff line
@@ -53,19 +53,22 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
    private final RootInfo mRoot;
    private final Uri mUri;
    private final int mUserSortOrder;
    private final boolean mSearchMode;

    private DocumentInfo mDoc;
    private CancellationSignal mSignal;
    private DirectoryResult mResult;


    public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
            int userSortOrder) {
            int userSortOrder, boolean inSearchMode) {
        super(context, ProviderExecutor.forAuthority(root.authority));
        mType = type;
        mRoot = root;
        mUri = uri;
        mUserSortOrder = userSortOrder;
        mDoc = doc;
        mSearchMode = inSearchMode;
    }

    @Override
@@ -83,7 +86,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
        final DirectoryResult result = new DirectoryResult();

        // Use default document when searching
        if (mType == DirectoryFragment.TYPE_SEARCH) {
        if (mSearchMode) {
            final Uri docUri = DocumentsContract.buildDocumentUri(
                    mRoot.authority, mRoot.documentId);
            try {
@@ -106,7 +109,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
        }

        // Search always uses ranking from provider
        if (mType == DirectoryFragment.TYPE_SEARCH) {
        if (mSearchMode) {
            result.sortOrder = State.SORT_ORDER_UNKNOWN;
        }

@@ -127,7 +130,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {

            cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);

            if (mType == DirectoryFragment.TYPE_SEARCH) {
            if (mSearchMode) {
                // Filter directories out of search results, for now
                cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
            }
+0 −5
Original line number Diff line number Diff line
@@ -289,15 +289,10 @@ public class DocumentsActivity extends BaseActivity {
                        MimePredicate.VISUAL_MIMES, mState.acceptMimes);
                mState.derivedMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
            }
        } else {
            if (mSearchManager.isSearching()) {
                // Ongoing search
                DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
        } else {
                // Normal boring directory
                DirectoryFragment.showDirectory(fm, root, cwd, anim);
        }
        }

        // Forget any replacement target
        if (mState.action == ACTION_CREATE) {
+6 −7
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.documentsui;

import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.ACTION_MANAGE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.internal.util.Preconditions.checkState;

import android.app.Activity;
import android.app.Fragment;
@@ -119,18 +121,15 @@ public class DownloadsActivity extends BaseActivity {
        final RootInfo root = getCurrentRoot();
        final DocumentInfo cwd = getCurrentDirectory();

        if (DEBUG) checkState(!mSearchManager.isSearching());

        // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
        // root).
        Preconditions.checkNotNull(cwd);

        if (mState.currentSearch != null) {
            // Ongoing search
            DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
        } else {
        // Normal boring directory
        DirectoryFragment.showDirectory(fm, root, cwd, anim);
    }
    }

    @Override
    public void onDocumentPicked(DocumentInfo doc, Model model) {
+4 −8
Original line number Diff line number Diff line
@@ -82,7 +82,6 @@ public class FilesActivity extends BaseActivity {

        if (mState.restored) {
            if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
            refreshCurrentRootAndDirectory(ANIM_NONE);
        } else if (!mState.stack.isEmpty()) {
            // If a non-empty stack is present in our state it was read (presumably)
            // from EXTRA_STACK intent extra. In this case, we'll skip other means of
@@ -248,18 +247,15 @@ public class FilesActivity extends BaseActivity {
        final RootInfo root = getCurrentRoot();
        final DocumentInfo cwd = getCurrentDirectory();

        if (DEBUG) checkState(!mSearchManager.isSearching());

        if (cwd == null) {
            DirectoryFragment.showRecentsOpen(fm, anim);
        } else {
            if (mState.currentSearch != null) {
                // Ongoing search
                DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
        } else {
            // Normal boring directory
            DirectoryFragment.showDirectory(fm, root, cwd, anim);
        }
    }
    }

    @Override
    void onRootPicked(RootInfo root) {
Loading