Loading src/com/android/documentsui/AbstractActionHandler.java +8 −2 Original line number Diff line number Diff line Loading @@ -576,11 +576,15 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA Context context = mActivity; if (mState.stack.isRecents()) { final LockingContentObserver observer = new LockingContentObserver( mContentLock, AbstractActionHandler.this::loadDocumentsForCurrentStack); MultiRootDocumentsLoader loader; if (mSearchMgr.isSearching()) { if (DEBUG) { Log.d(TAG, "Creating new GlobalSearchLoader."); } return new GlobalSearchLoader( loader = new GlobalSearchLoader( context, mProviders, mState, Loading @@ -591,13 +595,15 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA if (DEBUG) { Log.d(TAG, "Creating new loader recents."); } return new RecentsLoader( loader = new RecentsLoader( context, mProviders, mState, mExecutors, mInjector.fileTypeLookup); } loader.setObserver(observer); return loader; } else { Uri contentsUri = mSearchMgr.isSearching() ? DocumentsContract.buildSearchDocumentsUri( Loading src/com/android/documentsui/DirectoryLoader.java +0 −28 Original line number Diff line number Diff line Loading @@ -16,20 +16,16 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.OperationCanceledException; import android.os.RemoteException; import android.provider.DocumentsContract.Document; Loading Loading @@ -241,28 +237,4 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { getContext().getContentResolver().unregisterContentObserver(mObserver); } private static final class LockingContentObserver extends ContentObserver { private final ContentLock mLock; private final Runnable mContentChangedCallback; public LockingContentObserver(ContentLock lock, Runnable contentChangedCallback) { super(new Handler(Looper.getMainLooper())); mLock = lock; mContentChangedCallback = contentChangedCallback; } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { if (DEBUG) { Log.d(TAG, "Directory content updated."); } mLock.runWhenUnlocked(mContentChangedCallback); } } } src/com/android/documentsui/LockingContentObserver.java 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.TAG; import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.util.Log; /** * A custom {@link ContentObserver} which constructed by a {@link ContentLock} * and a {@link Runnable} callback. It will callback when it's onChange and ContentLock is unlock. */ public final class LockingContentObserver extends ContentObserver { private final ContentLock mLock; private final Runnable mContentChangedCallback; public LockingContentObserver(ContentLock lock, Runnable contentChangedCallback) { super(new Handler(Looper.getMainLooper())); mLock = lock; mContentChangedCallback = contentChangedCallback; } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { if (DEBUG) { Log.d(TAG, "Content updated."); } mLock.runWhenUnlocked(mContentChangedCallback); } } src/com/android/documentsui/MultiRootDocumentsLoader.java +17 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.TAG; import android.app.ActivityManager; import android.content.ContentProviderClient; Loading Loading @@ -65,6 +64,9 @@ import java.util.concurrent.TimeUnit; * and return the combined result. */ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<DirectoryResult> { private static final String TAG = "MultiRootDocsLoader"; // TODO: clean up cursor ownership so background thread doesn't traverse // previously returned cursors for filtering/sorting; this currently races // with the UI thread. Loading @@ -83,6 +85,7 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory private final ProvidersAccess mProviders; private final Lookup<String, Executor> mExecutors; private final Lookup<String, String> mFileTypeMap; private LockingContentObserver mObserver; @GuardedBy("mTasks") /** A authority -> QueryTask map */ Loading @@ -101,6 +104,8 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory * @param state current state * @param executors the executors of authorities * @param fileTypeMap the map of mime types and file types. * @param lock the selection lock * @param contentChangedCallback callback when content changed */ public MultiRootDocumentsLoader(Context context, ProvidersAccess providers, State state, Lookup<String, Executor> executors, Lookup<String, String> fileTypeMap) { Loading @@ -126,6 +131,10 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory } } public void setObserver(LockingContentObserver observer) { mObserver = observer; } private DirectoryResult loadInBackgroundLocked() { if (mFirstPassLatch == null) { // First time through we kick off all the recent tasks, and wait Loading Loading @@ -322,6 +331,10 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory FileUtils.closeQuietly(mResult); mResult = null; if (mObserver != null) { getContext().getContentResolver().unregisterContentObserver(mObserver); } } // TODO: create better transfer of ownership around cursor to ensure its Loading Loading @@ -406,6 +419,9 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory mState.sortModel.addQuerySortArgs(queryArgs); addQueryArgs(queryArgs); res[i] = client.query(uri, null, queryArgs, null); if (mObserver != null) { res[i].registerContentObserver(mObserver); } mCursors[i] = generateResultCursor(rootInfos.get(i), res[i]); } catch (Exception e) { Log.w(TAG, "Failed to load " + authority + ", " + rootInfos.get(i).rootId, Loading tests/common/com/android/documentsui/testing/TestCursor.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.testing; import android.database.MatrixCursor; public class TestCursor extends MatrixCursor { public TestCursor(String[] columnNames) { super(columnNames); } public void mockOnChange() { onChange(false); } } Loading
src/com/android/documentsui/AbstractActionHandler.java +8 −2 Original line number Diff line number Diff line Loading @@ -576,11 +576,15 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA Context context = mActivity; if (mState.stack.isRecents()) { final LockingContentObserver observer = new LockingContentObserver( mContentLock, AbstractActionHandler.this::loadDocumentsForCurrentStack); MultiRootDocumentsLoader loader; if (mSearchMgr.isSearching()) { if (DEBUG) { Log.d(TAG, "Creating new GlobalSearchLoader."); } return new GlobalSearchLoader( loader = new GlobalSearchLoader( context, mProviders, mState, Loading @@ -591,13 +595,15 @@ public abstract class AbstractActionHandler<T extends FragmentActivity & CommonA if (DEBUG) { Log.d(TAG, "Creating new loader recents."); } return new RecentsLoader( loader = new RecentsLoader( context, mProviders, mState, mExecutors, mInjector.fileTypeLookup); } loader.setObserver(observer); return loader; } else { Uri contentsUri = mSearchMgr.isSearching() ? DocumentsContract.buildSearchDocumentsUri( Loading
src/com/android/documentsui/DirectoryLoader.java +0 −28 Original line number Diff line number Diff line Loading @@ -16,20 +16,16 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.OperationCanceledException; import android.os.RemoteException; import android.provider.DocumentsContract.Document; Loading Loading @@ -241,28 +237,4 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { getContext().getContentResolver().unregisterContentObserver(mObserver); } private static final class LockingContentObserver extends ContentObserver { private final ContentLock mLock; private final Runnable mContentChangedCallback; public LockingContentObserver(ContentLock lock, Runnable contentChangedCallback) { super(new Handler(Looper.getMainLooper())); mLock = lock; mContentChangedCallback = contentChangedCallback; } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { if (DEBUG) { Log.d(TAG, "Directory content updated."); } mLock.runWhenUnlocked(mContentChangedCallback); } } }
src/com/android/documentsui/LockingContentObserver.java 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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 static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.TAG; import android.database.ContentObserver; import android.os.Handler; import android.os.Looper; import android.util.Log; /** * A custom {@link ContentObserver} which constructed by a {@link ContentLock} * and a {@link Runnable} callback. It will callback when it's onChange and ContentLock is unlock. */ public final class LockingContentObserver extends ContentObserver { private final ContentLock mLock; private final Runnable mContentChangedCallback; public LockingContentObserver(ContentLock lock, Runnable contentChangedCallback) { super(new Handler(Looper.getMainLooper())); mLock = lock; mContentChangedCallback = contentChangedCallback; } @Override public boolean deliverSelfNotifications() { return true; } @Override public void onChange(boolean selfChange) { if (DEBUG) { Log.d(TAG, "Content updated."); } mLock.runWhenUnlocked(mContentChangedCallback); } }
src/com/android/documentsui/MultiRootDocumentsLoader.java +17 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.documentsui; import static com.android.documentsui.base.SharedMinimal.DEBUG; import static com.android.documentsui.base.SharedMinimal.TAG; import android.app.ActivityManager; import android.content.ContentProviderClient; Loading Loading @@ -65,6 +64,9 @@ import java.util.concurrent.TimeUnit; * and return the combined result. */ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<DirectoryResult> { private static final String TAG = "MultiRootDocsLoader"; // TODO: clean up cursor ownership so background thread doesn't traverse // previously returned cursors for filtering/sorting; this currently races // with the UI thread. Loading @@ -83,6 +85,7 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory private final ProvidersAccess mProviders; private final Lookup<String, Executor> mExecutors; private final Lookup<String, String> mFileTypeMap; private LockingContentObserver mObserver; @GuardedBy("mTasks") /** A authority -> QueryTask map */ Loading @@ -101,6 +104,8 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory * @param state current state * @param executors the executors of authorities * @param fileTypeMap the map of mime types and file types. * @param lock the selection lock * @param contentChangedCallback callback when content changed */ public MultiRootDocumentsLoader(Context context, ProvidersAccess providers, State state, Lookup<String, Executor> executors, Lookup<String, String> fileTypeMap) { Loading @@ -126,6 +131,10 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory } } public void setObserver(LockingContentObserver observer) { mObserver = observer; } private DirectoryResult loadInBackgroundLocked() { if (mFirstPassLatch == null) { // First time through we kick off all the recent tasks, and wait Loading Loading @@ -322,6 +331,10 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory FileUtils.closeQuietly(mResult); mResult = null; if (mObserver != null) { getContext().getContentResolver().unregisterContentObserver(mObserver); } } // TODO: create better transfer of ownership around cursor to ensure its Loading Loading @@ -406,6 +419,9 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory mState.sortModel.addQuerySortArgs(queryArgs); addQueryArgs(queryArgs); res[i] = client.query(uri, null, queryArgs, null); if (mObserver != null) { res[i].registerContentObserver(mObserver); } mCursors[i] = generateResultCursor(rootInfos.get(i), res[i]); } catch (Exception e) { Log.w(TAG, "Failed to load " + authority + ", " + rootInfos.get(i).rootId, Loading
tests/common/com/android/documentsui/testing/TestCursor.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.testing; import android.database.MatrixCursor; public class TestCursor extends MatrixCursor { public TestCursor(String[] columnNames) { super(columnNames); } public void mockOnChange() { onChange(false); } }