Loading src/com/android/documentsui/inspector/DocumentInspectorFragment.java +33 −6 Original line number Diff line number Diff line Loading @@ -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(); Loading src/com/android/documentsui/inspector/DocumentLoader.java 0 → 100644 +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 src/com/android/documentsui/inspector/InspectorController.java 0 → 100644 +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(); } } tests/AndroidManifest.xml +13 −0 Original line number Diff line number Diff line Loading @@ -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" Loading tests/common/com/android/documentsui/InspectorProvider.java 0 → 100644 +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
src/com/android/documentsui/inspector/DocumentInspectorFragment.java +33 −6 Original line number Diff line number Diff line Loading @@ -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(); Loading
src/com/android/documentsui/inspector/DocumentLoader.java 0 → 100644 +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
src/com/android/documentsui/inspector/InspectorController.java 0 → 100644 +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(); } }
tests/AndroidManifest.xml +13 −0 Original line number Diff line number Diff line Loading @@ -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" Loading
tests/common/com/android/documentsui/InspectorProvider.java 0 → 100644 +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; } }