blob: dcba9b7758dd077146c4b1c6c8aaf929a8c38c83 [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;
20import android.os.ICancellationSignal.Stub;
Jeff Brown75ea64f2012-01-25 19:37:13 -080021
22/**
23 * Provides the ability to cancel an operation in progress.
24 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080025public final class CancellationSignal {
Jeff Brown75ea64f2012-01-25 19:37:13 -080026 private boolean mIsCanceled;
27 private OnCancelListener mOnCancelListener;
Jeff Brown4c1241d2012-02-02 17:05:00 -080028 private ICancellationSignal mRemote;
Jeff Brownaeee2f52012-04-26 17:36:12 -070029 private boolean mCancelInProgress;
Jeff Brown75ea64f2012-01-25 19:37:13 -080030
31 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080032 * Creates a cancellation signal, initially not canceled.
Jeff Brown75ea64f2012-01-25 19:37:13 -080033 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080034 public CancellationSignal() {
Jeff Brown75ea64f2012-01-25 19:37:13 -080035 }
36
37 /**
38 * Returns true if the operation has been canceled.
39 *
40 * @return True if the operation has been canceled.
41 */
42 public boolean isCanceled() {
43 synchronized (this) {
44 return mIsCanceled;
45 }
46 }
47
48 /**
49 * Throws {@link OperationCanceledException} if the operation has been canceled.
50 *
51 * @throws OperationCanceledException if the operation has been canceled.
52 */
53 public void throwIfCanceled() {
54 if (isCanceled()) {
55 throw new OperationCanceledException();
56 }
57 }
58
59 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080060 * Cancels the operation and signals the cancellation listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -080061 * If the operation has not yet started, then it will be canceled as soon as it does.
62 */
63 public void cancel() {
Jeff Brownaeee2f52012-04-26 17:36:12 -070064 final OnCancelListener listener;
65 final ICancellationSignal remote;
Jeff Brown75ea64f2012-01-25 19:37:13 -080066 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -070067 if (mIsCanceled) {
68 return;
69 }
70 mIsCanceled = true;
71 mCancelInProgress = true;
72 listener = mOnCancelListener;
73 remote = mRemote;
74 }
75
76 try {
77 if (listener != null) {
78 listener.onCancel();
79 }
80 if (remote != null) {
81 try {
82 remote.cancel();
83 } catch (RemoteException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -080084 }
Jeff Brownaeee2f52012-04-26 17:36:12 -070085 }
86 } finally {
87 synchronized (this) {
88 mCancelInProgress = false;
89 notifyAll();
Jeff Brown75ea64f2012-01-25 19:37:13 -080090 }
91 }
92 }
93
94 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080095 * Sets the cancellation listener to be called when canceled.
96 *
97 * This method is intended to be used by the recipient of a cancellation signal
98 * such as a database or a content provider to handle cancellation requests
99 * while performing a long-running operation. This method is not intended to be
100 * used by applications themselves.
101 *
102 * If {@link CancellationSignal#cancel} has already been called, then the provided
Jeff Brown75ea64f2012-01-25 19:37:13 -0800103 * listener is invoked immediately.
104 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700105 * This method is guaranteed that the listener will not be called after it
106 * has been removed.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800107 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800108 * @param listener The cancellation listener, or null to remove the current listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800109 */
110 public void setOnCancelListener(OnCancelListener listener) {
111 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700112 waitForCancelFinishedLocked();
113
114 if (mOnCancelListener == listener) {
115 return;
116 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800117 mOnCancelListener = listener;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700118 if (!mIsCanceled || listener == null) {
119 return;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800120 }
121 }
Jeff Brownaeee2f52012-04-26 17:36:12 -0700122 listener.onCancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800123 }
124
125 /**
126 * Sets the remote transport.
127 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700128 * If {@link CancellationSignal#cancel} has already been called, then the provided
129 * remote transport is canceled immediately.
130 *
131 * This method is guaranteed that the remote transport will not be called after it
132 * has been removed.
133 *
Jeff Brown75ea64f2012-01-25 19:37:13 -0800134 * @param remote The remote transport, or null to remove.
135 *
136 * @hide
137 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800138 public void setRemote(ICancellationSignal remote) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800139 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700140 waitForCancelFinishedLocked();
141
142 if (mRemote == remote) {
143 return;
144 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800145 mRemote = remote;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700146 if (!mIsCanceled || remote == null) {
147 return;
148 }
149 }
150 try {
151 remote.cancel();
152 } catch (RemoteException ex) {
153 }
154 }
155
156 private void waitForCancelFinishedLocked() {
157 while (mCancelInProgress) {
158 try {
159 wait();
160 } catch (InterruptedException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800161 }
162 }
163 }
164
165 /**
166 * Creates a transport that can be returned back to the caller of
Jeff Brown4c1241d2012-02-02 17:05:00 -0800167 * a Binder function and subsequently used to dispatch a cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800168 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800169 * @return The new cancellation signal transport.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800170 *
171 * @hide
172 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800173 public static ICancellationSignal createTransport() {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800174 return new Transport();
175 }
176
177 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800178 * Given a locally created transport, returns its associated cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800179 *
180 * @param transport The locally created transport, or null if none.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800181 * @return The associated cancellation signal, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800182 *
183 * @hide
184 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800185 public static CancellationSignal fromTransport(ICancellationSignal transport) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800186 if (transport instanceof Transport) {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800187 return ((Transport)transport).mCancellationSignal;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800188 }
189 return null;
190 }
191
192 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800193 * Listens for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800194 */
195 public interface OnCancelListener {
196 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800197 * Called when {@link CancellationSignal#cancel} is invoked.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800198 */
199 void onCancel();
200 }
201
Jeff Brown4c1241d2012-02-02 17:05:00 -0800202 private static final class Transport extends ICancellationSignal.Stub {
203 final CancellationSignal mCancellationSignal = new CancellationSignal();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800204
205 @Override
206 public void cancel() throws RemoteException {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800207 mCancellationSignal.cancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800208 }
209 }
210}