blob: e8053d5d275d55eccbfd3577245a0fc10dae56e6 [file] [log] [blame]
Jeff Brown75ea64f2012-01-25 19:37:13 -08001/*
2 * Copyright (C) 2012 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
Jeff Browna7771df2012-05-07 20:06:46 -070017package android.os;
Jeff Brown75ea64f2012-01-25 19:37:13 -080018
Jeff Browna7771df2012-05-07 20:06:46 -070019import android.os.ICancellationSignal;
Jeff Brown75ea64f2012-01-25 19:37:13 -080020
21/**
22 * Provides the ability to cancel an operation in progress.
23 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080024public final class CancellationSignal {
Jeff Brown75ea64f2012-01-25 19:37:13 -080025 private boolean mIsCanceled;
26 private OnCancelListener mOnCancelListener;
Jeff Brown4c1241d2012-02-02 17:05:00 -080027 private ICancellationSignal mRemote;
Jeff Brownaeee2f52012-04-26 17:36:12 -070028 private boolean mCancelInProgress;
Jeff Brown75ea64f2012-01-25 19:37:13 -080029
30 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080031 * Creates a cancellation signal, initially not canceled.
Jeff Brown75ea64f2012-01-25 19:37:13 -080032 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080033 public CancellationSignal() {
Jeff Brown75ea64f2012-01-25 19:37:13 -080034 }
35
36 /**
37 * Returns true if the operation has been canceled.
38 *
39 * @return True if the operation has been canceled.
40 */
41 public boolean isCanceled() {
42 synchronized (this) {
43 return mIsCanceled;
44 }
45 }
46
47 /**
48 * Throws {@link OperationCanceledException} if the operation has been canceled.
49 *
50 * @throws OperationCanceledException if the operation has been canceled.
51 */
52 public void throwIfCanceled() {
53 if (isCanceled()) {
54 throw new OperationCanceledException();
55 }
56 }
57
58 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080059 * Cancels the operation and signals the cancellation listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -080060 * If the operation has not yet started, then it will be canceled as soon as it does.
61 */
62 public void cancel() {
Jeff Brownaeee2f52012-04-26 17:36:12 -070063 final OnCancelListener listener;
64 final ICancellationSignal remote;
Jeff Brown75ea64f2012-01-25 19:37:13 -080065 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -070066 if (mIsCanceled) {
67 return;
68 }
69 mIsCanceled = true;
70 mCancelInProgress = true;
71 listener = mOnCancelListener;
72 remote = mRemote;
73 }
74
75 try {
76 if (listener != null) {
77 listener.onCancel();
78 }
79 if (remote != null) {
80 try {
81 remote.cancel();
82 } catch (RemoteException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -080083 }
Jeff Brownaeee2f52012-04-26 17:36:12 -070084 }
85 } finally {
86 synchronized (this) {
87 mCancelInProgress = false;
88 notifyAll();
Jeff Brown75ea64f2012-01-25 19:37:13 -080089 }
90 }
91 }
92
93 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080094 * Sets the cancellation listener to be called when canceled.
95 *
96 * This method is intended to be used by the recipient of a cancellation signal
97 * such as a database or a content provider to handle cancellation requests
98 * while performing a long-running operation. This method is not intended to be
99 * used by applications themselves.
100 *
101 * If {@link CancellationSignal#cancel} has already been called, then the provided
Jeff Brown75ea64f2012-01-25 19:37:13 -0800102 * listener is invoked immediately.
103 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700104 * This method is guaranteed that the listener will not be called after it
105 * has been removed.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800106 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800107 * @param listener The cancellation listener, or null to remove the current listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800108 */
109 public void setOnCancelListener(OnCancelListener listener) {
110 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700111 waitForCancelFinishedLocked();
112
113 if (mOnCancelListener == listener) {
114 return;
115 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800116 mOnCancelListener = listener;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700117 if (!mIsCanceled || listener == null) {
118 return;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800119 }
120 }
Jeff Brownaeee2f52012-04-26 17:36:12 -0700121 listener.onCancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800122 }
123
124 /**
125 * Sets the remote transport.
126 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700127 * If {@link CancellationSignal#cancel} has already been called, then the provided
128 * remote transport is canceled immediately.
129 *
130 * This method is guaranteed that the remote transport will not be called after it
131 * has been removed.
132 *
Jeff Brown75ea64f2012-01-25 19:37:13 -0800133 * @param remote The remote transport, or null to remove.
134 *
135 * @hide
136 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800137 public void setRemote(ICancellationSignal remote) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800138 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700139 waitForCancelFinishedLocked();
140
141 if (mRemote == remote) {
142 return;
143 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800144 mRemote = remote;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700145 if (!mIsCanceled || remote == null) {
146 return;
147 }
148 }
149 try {
150 remote.cancel();
151 } catch (RemoteException ex) {
152 }
153 }
154
155 private void waitForCancelFinishedLocked() {
156 while (mCancelInProgress) {
157 try {
158 wait();
159 } catch (InterruptedException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800160 }
161 }
162 }
163
164 /**
165 * Creates a transport that can be returned back to the caller of
Jeff Brown4c1241d2012-02-02 17:05:00 -0800166 * a Binder function and subsequently used to dispatch a cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800167 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800168 * @return The new cancellation signal transport.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800169 *
170 * @hide
171 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800172 public static ICancellationSignal createTransport() {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800173 return new Transport();
174 }
175
176 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800177 * Given a locally created transport, returns its associated cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800178 *
179 * @param transport The locally created transport, or null if none.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800180 * @return The associated cancellation signal, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800181 *
182 * @hide
183 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800184 public static CancellationSignal fromTransport(ICancellationSignal transport) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800185 if (transport instanceof Transport) {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800186 return ((Transport)transport).mCancellationSignal;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800187 }
188 return null;
189 }
190
191 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800192 * Listens for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800193 */
194 public interface OnCancelListener {
195 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800196 * Called when {@link CancellationSignal#cancel} is invoked.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800197 */
198 void onCancel();
199 }
200
Jeff Brown4c1241d2012-02-02 17:05:00 -0800201 private static final class Transport extends ICancellationSignal.Stub {
202 final CancellationSignal mCancellationSignal = new CancellationSignal();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800203
204 @Override
205 public void cancel() throws RemoteException {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800206 mCancellationSignal.cancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800207 }
208 }
209}