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.selection; 17 18 import static android.support.v4.util.Preconditions.checkState; 19 import static com.android.documentsui.selection.Shared.DEBUG; 20 import static com.android.documentsui.selection.Shared.TAG; 21 22 import android.annotation.MainThread; 23 import android.annotation.Nullable; 24 import android.content.Loader; 25 import android.util.Log; 26 27 /** 28 * ContentLock provides a mechanism to block content from reloading while selection 29 * activities like gesture and band selection are active. Clients using live data 30 * (data loaded, for example by a {@link Loader}), should route calls to load 31 * content through this lock using {@link ContentLock#runWhenUnlocked(Runnable)}. 32 */ 33 public final class ContentLock { 34 35 private int mLocks = 0; 36 private @Nullable Runnable mCallback; 37 38 /** 39 * Increment the block count by 1 40 */ 41 @MainThread 42 public synchronized void block() { 43 mLocks++; 44 if (DEBUG) Log.v(TAG, "Incremented content lock count to " + mLocks + "."); 45 } 46 47 /** 48 * Decrement the block count by 1; If no other object is trying to block and there exists some 49 * callback, that callback will be run 50 */ 51 @MainThread 52 public synchronized void unblock() { 53 checkState(mLocks > 0); 54 55 mLocks--; 56 if (DEBUG) Log.v(TAG, "Decremented content lock count to " + mLocks + "."); 57 58 if (mLocks == 0 && mCallback != null) { 59 mCallback.run(); 60 mCallback = null; 61 } 62 } 63 64 /** 65 * Attempts to run the given Runnable if not-locked, or else the Runnable is set to be ran next 66 * (replacing any previous set Runnables). 67 */ 68 public synchronized void runWhenUnlocked(Runnable runnable) { 69 if (mLocks == 0) { 70 runnable.run(); 71 } else { 72 mCallback = runnable; 73 } 74 } 75 76 /** 77 * Returns true if locked. 78 */ 79 synchronized boolean isLocked() { 80 return mLocks > 0; 81 } 82 83 /** 84 * Allows other selection code to perform a precondition check asserting the state is locked. 85 */ 86 final void checkLocked() { 87 checkState(isLocked()); 88 } 89 90 /** 91 * Allows other selection code to perform a precondition check asserting the state is unlocked. 92 */ 93 final void checkUnlocked() { 94 checkState(!isLocked()); 95 } 96 } 97