1220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown/*
2220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Copyright (C) 2012 The Android Open Source Project
3220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
4220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * you may not use this file except in compliance with the License.
6220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * You may obtain a copy of the License at
7220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
8220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown *
10220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Unless required by applicable law or agreed to in writing, software
11220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * See the License for the specific language governing permissions and
14220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * limitations under the License.
15220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */
16220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
17220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownpackage android.support.v4.os;
18220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
19220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownimport android.os.Build;
20220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
21220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown/**
22220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Static library support version of the framework's {@link android.os.CancellationSignal}.
23220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * Used to write apps that run on platforms prior to Android 4.1.  See the framework SDK
24220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown * documentation for a class overview.
25220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown */
26220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brownpublic final class CancellationSignal {
27220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private boolean mIsCanceled;
28220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private OnCancelListener mOnCancelListener;
29220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private Object mCancellationSignalObj;
30220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private boolean mCancelInProgress;
31220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
32220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
33220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Creates a cancellation signal, initially not canceled.
34220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
35220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public CancellationSignal() {
36220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
37220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
38220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
39220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Returns true if the operation has been canceled.
40220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
41220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return True if the operation has been canceled.
42220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
43220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public boolean isCanceled() {
44220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        synchronized (this) {
45220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            return mIsCanceled;
46220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
47220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
48220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
49220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
50220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Throws {@link OperationCanceledException} if the operation has been canceled.
51220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
52220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @throws OperationCanceledException if the operation has been canceled.
53220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
54220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public void throwIfCanceled() {
55220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        if (isCanceled()) {
56220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            throw new OperationCanceledException();
57220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
58220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
59220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
60220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
61220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Cancels the operation and signals the cancellation listener.
62220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * If the operation has not yet started, then it will be canceled as soon as it does.
63220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
64220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public void cancel() {
65220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        final OnCancelListener listener;
66220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        final Object obj;
67220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        synchronized (this) {
68220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (mIsCanceled) {
69220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                return;
70220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
71220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            mIsCanceled = true;
72220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            mCancelInProgress = true;
73220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            listener = mOnCancelListener;
74220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            obj = mCancellationSignalObj;
75220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
76220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
77220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        try {
78220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (listener != null) {
79220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                listener.onCancel();
80220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
81220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (obj != null) {
82220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                CancellationSignalCompatJellybean.cancel(obj);
83220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
84220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        } finally {
85220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            synchronized (this) {
86220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                mCancelInProgress = false;
87220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                notifyAll();
88220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
89220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
90220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
91220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
92220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
93220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Sets the cancellation listener to be called when canceled.
94220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
95220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * This method is intended to be used by the recipient of a cancellation signal
96220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * such as a database or a content provider to handle cancellation requests
97220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * while performing a long-running operation.  This method is not intended to be
98220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * used by applications themselves.
99220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
100220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * If {@link CancellationSignal#cancel} has already been called, then the provided
101220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * listener is invoked immediately.
102220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
103220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * This method is guaranteed that the listener will not be called after it
104220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * has been removed.
105220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
106220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @param listener The cancellation listener, or null to remove the current listener.
107220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
108220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public void setOnCancelListener(OnCancelListener listener) {
109220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        synchronized (this) {
110220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            waitForCancelFinishedLocked();
111220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
112220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (mOnCancelListener == listener) {
113220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                return;
114220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
115220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            mOnCancelListener = listener;
116220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (!mIsCanceled || listener == null) {
117220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                return;
118220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
119220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
120220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        listener.onCancel();
121220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
122220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
123220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    /**
124220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Gets the framework {@link android.os.CancellationSignal} associated with this object.
125220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * <p>
126220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Framework support for cancellation signals was added in
127220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} so this method will always
128220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * return null on older versions of the platform.
129220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * </p>
130220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     *
131220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * @return A framework cancellation signal object, or null on platform versions
132220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * prior to Jellybean.
133220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
134220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public Object getCancellationSignalObject() {
135220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        if (Build.VERSION.SDK_INT < 16) {
136220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            return null;
137220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
138220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        synchronized (this) {
139220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            if (mCancellationSignalObj == null) {
140220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                mCancellationSignalObj = CancellationSignalCompatJellybean.create();
141220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                if (mIsCanceled) {
142220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                    CancellationSignalCompatJellybean.cancel(mCancellationSignalObj);
143220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                }
144220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
145220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            return mCancellationSignalObj;
146220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
147220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
148220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
149220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    private void waitForCancelFinishedLocked() {
150220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        while (mCancelInProgress) {
151220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            try {
152220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown                wait();
153220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            } catch (InterruptedException ex) {
154220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown            }
155220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        }
156220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
157220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown
158220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     /**
159220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     * Listens for cancellation.
160220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown     */
161220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    public interface OnCancelListener {
162220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        /**
163220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown         * Called when {@link CancellationSignal#cancel} is invoked.
164220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown         */
165220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown        void onCancel();
166220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown    }
167220dc21ab5a2a5b3f8b6532105121750770a69f4Jeff Brown}
168