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

Commit f6d1a887 authored by Austin Kolander's avatar Austin Kolander
Browse files

Build a controller that loads document info

Bug: 62622004
Test: DocumentMetaLoaderTest
Change-Id: Ibfe38a472aadd8b1c52ceb80224f585a5a952c81
parent 26ce3ea0
Loading
Loading
Loading
Loading
+33 −6
Original line number Diff line number Diff line
@@ -15,31 +15,58 @@
 */
package com.android.documentsui.inspector;

import static com.android.internal.util.Preconditions.checkArgument;

import android.app.Fragment;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.android.documentsui.R;
import com.android.documentsui.inspector.InspectorController.Loader;
import com.android.internal.util.Preconditions;

/**
 * Displays the Properties view in Files.
 */
public class DocumentInspectorFragment extends Fragment {

    private static final String DOC_URI_ARG = "docUri";
    private Uri docUri;
    private InspectorController mController;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Loader loader = new DocumentLoader(this.getActivity(), this.getLoaderManager());
        mController = new InspectorController(loader);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

          Bundle args = getArguments();
          docUri = (Uri) args.get(DOC_URI_ARG);

        return inflater.inflate(R.layout.document_inspector_fragment, container, false);
    }

    @Override
    public void onStart() {
        super.onStart();
        Uri uri = (Uri) getArguments().get(DOC_URI_ARG);
        mController.loadInfo(uri);
    }

    @Override
    public void onStop() {
        super.onStop();
        mController.reset();
    }

    /**
     * Creates a fragment and sets a Uri as an argument.
     */
    public static DocumentInspectorFragment newInstance(Uri uri) {
        checkArgument(uri.getScheme().equals("content"));
        Bundle args = new Bundle();
        args.putParcelable(DOC_URI_ARG, uri);
        DocumentInspectorFragment fragment = new DocumentInspectorFragment();
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.inspector;

import static com.android.internal.util.Preconditions.checkArgument;

import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.inspector.InspectorController.Loader;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * Asynchronously loads a documents metadata into a DocumentInfo object.
 */
public class DocumentLoader implements Loader {

    private final Context mContext;
    private final LoaderManager mLoader;
    private List<Integer> loaderIds;

    public DocumentLoader(Context context, LoaderManager loader) {
        checkArgument(context != null);
        checkArgument(loader != null);
        mContext = context;
        mLoader = loader;
        loaderIds = new ArrayList<>();
    }

    private int getNextLoaderId() {
        int id = 0;
        while(mLoader.getLoader(id) != null) {
            id++;
            checkArgument(id <= Integer.MAX_VALUE);
        }
        return id;
    }

    /**
     * @param uri is a Content Uri.
     */
    @Override
    public void load(Uri uri, Consumer<DocumentInfo> callback) {
        //Check that we have correct Uri type and that the loader is not already created.
        checkArgument(uri.getScheme().equals("content"));

        //get a new loader id.
        int loadId = getNextLoaderId();
        checkArgument(mLoader.getLoader(loadId) == null);
        loaderIds.add(loadId);
        mLoader.restartLoader(loadId, null, new Callbacks(mContext, uri, mLoader, callback));
    }

    @Override
    public void reset() {
        for (Integer id : loaderIds) {
            mLoader.destroyLoader(id);
        }
        loaderIds.clear();
    }

    /**
     * Implements the callback interface for the Loader.
     */
    static final class Callbacks implements LoaderCallbacks<Cursor> {

        private final Context mContext;
        private final Uri mDocUri;
        private final Consumer<DocumentInfo> mDocConsumer;
        private final LoaderManager mManager;

        Callbacks(Context context, Uri uri, LoaderManager manager,
                Consumer<DocumentInfo> docConsumer) {

            checkArgument(context != null);
            checkArgument(uri != null);
            checkArgument(manager != null);
            checkArgument(docConsumer != null);
            mContext = context;
            mDocUri = uri;
            mDocConsumer = docConsumer;
            mManager = manager;
        }

        @Override
        public android.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
            return new CursorLoader(mContext, mDocUri, null, null, null, null);
        }

        @Override
        public void onLoadFinished(android.content.Loader<Cursor> loader, Cursor cursor) {

            //returns DocumentInfo null if the cursor is null or isEmpty.
            if (cursor == null || !cursor.moveToFirst()) {
                mDocConsumer.accept(null);
            }
            else {
                DocumentInfo docInfo = DocumentInfo.fromCursor(cursor, mDocUri.getAuthority());
                mDocConsumer.accept(docInfo);
            }

            mManager.destroyLoader(loader.getId());
        }

        @Override
        public void onLoaderReset(android.content.Loader<Cursor> loader) {

        }
    }
}
 No newline at end of file
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.inspector;

import static com.android.internal.util.Preconditions.checkArgument;

import android.net.Uri;
import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.base.DocumentInfo;
import com.android.internal.util.Preconditions;
import java.util.function.Consumer;

/**
 * A controller that coordinates retrieving document information and sending it to the view.
 */
public final class InspectorController {

    private final Loader mLoader;

    public InspectorController(Loader loader) {
        checkArgument(loader != null);
        mLoader = loader;
    }

    public void reset() {
        mLoader.reset();
    }

    public void loadInfo(Uri uri) {
        mLoader.load(uri, this::updateView);
    }

    /**
     * Updates the view.
     *
     */
    @Nullable
    private void updateView(@Nullable DocumentInfo docInfo) {
        //TODO: update the view.
        Log.d("DocInfo", docInfo.toString());
    }

    /**
     * Interface for loading document metadata.
     */
    public interface Loader {

        /**
         * Starts the Asynchronous process of loading file data.
         *
         * @param uri - A content uri to query metadata from.
         * @param callback - Function to be called when the loader has finished loading metadata. A
         * DocumentInfo will be sent to this method. DocumentInfo may be null.
         */
        void load(Uri uri, Consumer<DocumentInfo> callback);

        /**
         * Deletes all loader id's when android lifecycle ends.
         */
        void reset();
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -63,6 +63,19 @@
            </intent-filter>
      </provider>

      <!-- Provider for testing inspector -->
      <provider
          android:name="com.android.documentsui.InspectorProvider"
          android:authorities="com.android.documentsui.inspectorprovider"
          android:exported="true"
          android:grantUriPermissions="true"
          android:permission="android.permission.MANAGE_DOCUMENTS"
          android:enabled="true">
        <intent-filter>
          <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
        </intent-filter>
      </provider>

       <!-- Provider with support for paging. -->
       <provider
            android:name="com.android.documentsui.PagingProvider"
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.documentsui;

import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.DocumentsContract.Root;
import java.io.FileNotFoundException;

/**
 * Content Provider for testing the Document Inspector.
 */
public class InspectorProvider extends TestRootProvider {

    private static final String AUTHORITY = "com.android.documentsui.inspectorprovider";

    private static final String ROOT_ID = "inspector-root";
    private static final String ROOT_DOC_ID = "root0";
    private static final int ROOT_FLAGS = 0;

    public InspectorProvider() {
        super("Inspector Root", ROOT_ID, ROOT_FLAGS, ROOT_DOC_ID);
    }

    @Override
    public Cursor queryDocument(String documentId, String[] projection)
            throws FileNotFoundException {

        MatrixCursor c = createDocCursor(projection);
        addFolder(c, documentId);
        return c;
    }

    @Override
    public Cursor queryChildDocuments(String s, String[] projection, String s1)
        throws FileNotFoundException {

        MatrixCursor c = createDocCursor(projection);
        addFile(c, "test.txt");
        addFile(c, "test1.txt");
        return c;
    }
}
Loading