1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.documentsui;
17 
18 import static com.android.documentsui.base.SharedMinimal.DEBUG;
19 
20 import android.util.Log;
21 
22 import androidx.annotation.GuardedBy;
23 import androidx.annotation.Nullable;
24 import androidx.recyclerview.selection.OperationMonitor;
25 
26 /**
27  * ContentLock provides a mechanism to block content from reloading while selection
28  * activities like gesture and band selection are active. Clients using live data
29  * (data loaded, for example by a {@link Loader}), should route calls to load
30  * content through this lock using {@link ContentLock#runWhenUnlocked(Runnable)}.
31  */
32 public final class ContentLock {
33 
34     private static final String TAG = "ContentLock";
35 
36     private final OperationMonitor mMonitor = new OperationMonitor();
37 
38     @GuardedBy("this")
39     private @Nullable Runnable mCallback;
40 
ContentLock()41     public ContentLock() {
42         mMonitor.addListener(() -> {
43             if (DEBUG) {
44                 Log.d(TAG, "monitor listener, is locked : " + isLocked());
45             }
46             if (!isLocked()) {
47                 synchronized (this) {
48                     final Runnable callback = mCallback;
49                     if (callback != null) {
50                         callback.run();
51                         mCallback = null;
52                     }
53                 }
54             }
55         });
56     }
57 
getMonitor()58     public OperationMonitor getMonitor() {
59         return mMonitor;
60     }
61 
62     /**
63      * Returns true if locked.
64      */
isLocked()65     private boolean isLocked() {
66         return mMonitor.isStarted();
67     }
68 
69     /**
70      * Attempts to run the given Runnable if not-locked, or else the Runnable is set to be ran next
71      * (replacing any previous set Runnables).
72      */
runWhenUnlocked(Runnable runnable)73     public synchronized void runWhenUnlocked(Runnable runnable) {
74         if (DEBUG) {
75             Log.d(TAG, "run when unlock, is locked : " + isLocked());
76         }
77         if (!isLocked()) {
78             runnable.run();
79         } else {
80             mCallback = runnable;
81         }
82     }
83 }
84