blob: 99fb9982e70619d386a0ffe48e0636a4ac6fd48c [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
Artur Satayev70507ed2019-07-29 13:18:27 +010021import dalvik.annotation.compat.UnsupportedAppUsage;
22
Jeff Brown75ea64f2012-01-25 19:37:13 -080023/**
24 * Provides the ability to cancel an operation in progress.
25 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080026public final class CancellationSignal {
Artur Satayev70507ed2019-07-29 13:18:27 +010027 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown75ea64f2012-01-25 19:37:13 -080028 private boolean mIsCanceled;
Artur Satayev70507ed2019-07-29 13:18:27 +010029 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown75ea64f2012-01-25 19:37:13 -080030 private OnCancelListener mOnCancelListener;
Artur Satayev70507ed2019-07-29 13:18:27 +010031 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown4c1241d2012-02-02 17:05:00 -080032 private ICancellationSignal mRemote;
Artur Satayev70507ed2019-07-29 13:18:27 +010033 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brownaeee2f52012-04-26 17:36:12 -070034 private boolean mCancelInProgress;
Jeff Brown75ea64f2012-01-25 19:37:13 -080035
36 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080037 * Creates a cancellation signal, initially not canceled.
Jeff Brown75ea64f2012-01-25 19:37:13 -080038 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080039 public CancellationSignal() {
Jeff Brown75ea64f2012-01-25 19:37:13 -080040 }
41
42 /**
43 * Returns true if the operation has been canceled.
44 *
45 * @return True if the operation has been canceled.
46 */
47 public boolean isCanceled() {
48 synchronized (this) {
49 return mIsCanceled;
50 }
51 }
52
53 /**
54 * Throws {@link OperationCanceledException} if the operation has been canceled.
55 *
56 * @throws OperationCanceledException if the operation has been canceled.
57 */
58 public void throwIfCanceled() {
59 if (isCanceled()) {
60 throw new OperationCanceledException();
61 }
62 }
63
64 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080065 * Cancels the operation and signals the cancellation listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -080066 * If the operation has not yet started, then it will be canceled as soon as it does.
67 */
68 public void cancel() {
Jeff Brownaeee2f52012-04-26 17:36:12 -070069 final OnCancelListener listener;
70 final ICancellationSignal remote;
Jeff Brown75ea64f2012-01-25 19:37:13 -080071 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -070072 if (mIsCanceled) {
73 return;
74 }
75 mIsCanceled = true;
76 mCancelInProgress = true;
77 listener = mOnCancelListener;
78 remote = mRemote;
79 }
80
81 try {
82 if (listener != null) {
83 listener.onCancel();
84 }
85 if (remote != null) {
86 try {
87 remote.cancel();
88 } catch (RemoteException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -080089 }
Jeff Brownaeee2f52012-04-26 17:36:12 -070090 }
91 } finally {
92 synchronized (this) {
93 mCancelInProgress = false;
94 notifyAll();
Jeff Brown75ea64f2012-01-25 19:37:13 -080095 }
96 }
97 }
98
99 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800100 * Sets the cancellation listener to be called when canceled.
101 *
102 * This method is intended to be used by the recipient of a cancellation signal
103 * such as a database or a content provider to handle cancellation requests
104 * while performing a long-running operation. This method is not intended to be
105 * used by applications themselves.
106 *
107 * If {@link CancellationSignal#cancel} has already been called, then the provided
Jeff Brown75ea64f2012-01-25 19:37:13 -0800108 * listener is invoked immediately.
109 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700110 * This method is guaranteed that the listener will not be called after it
111 * has been removed.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800112 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800113 * @param listener The cancellation listener, or null to remove the current listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800114 */
115 public void setOnCancelListener(OnCancelListener listener) {
116 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700117 waitForCancelFinishedLocked();
118
119 if (mOnCancelListener == listener) {
120 return;
121 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800122 mOnCancelListener = listener;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700123 if (!mIsCanceled || listener == null) {
124 return;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800125 }
126 }
Jeff Brownaeee2f52012-04-26 17:36:12 -0700127 listener.onCancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800128 }
129
130 /**
131 * Sets the remote transport.
132 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700133 * If {@link CancellationSignal#cancel} has already been called, then the provided
134 * remote transport is canceled immediately.
135 *
136 * This method is guaranteed that the remote transport will not be called after it
137 * has been removed.
138 *
Jeff Brown75ea64f2012-01-25 19:37:13 -0800139 * @param remote The remote transport, or null to remove.
140 *
141 * @hide
142 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800143 public void setRemote(ICancellationSignal remote) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800144 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700145 waitForCancelFinishedLocked();
146
147 if (mRemote == remote) {
148 return;
149 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800150 mRemote = remote;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700151 if (!mIsCanceled || remote == null) {
152 return;
153 }
154 }
155 try {
156 remote.cancel();
157 } catch (RemoteException ex) {
158 }
159 }
160
Artur Satayev70507ed2019-07-29 13:18:27 +0100161 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brownaeee2f52012-04-26 17:36:12 -0700162 private void waitForCancelFinishedLocked() {
163 while (mCancelInProgress) {
164 try {
165 wait();
166 } catch (InterruptedException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800167 }
168 }
169 }
170
171 /**
172 * Creates a transport that can be returned back to the caller of
Jeff Brown4c1241d2012-02-02 17:05:00 -0800173 * a Binder function and subsequently used to dispatch a cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800174 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800175 * @return The new cancellation signal transport.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800176 *
177 * @hide
178 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800179 public static ICancellationSignal createTransport() {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800180 return new Transport();
181 }
182
183 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800184 * Given a locally created transport, returns its associated cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800185 *
186 * @param transport The locally created transport, or null if none.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800187 * @return The associated cancellation signal, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800188 *
189 * @hide
190 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800191 public static CancellationSignal fromTransport(ICancellationSignal transport) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800192 if (transport instanceof Transport) {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800193 return ((Transport)transport).mCancellationSignal;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800194 }
195 return null;
196 }
197
198 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800199 * Listens for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800200 */
201 public interface OnCancelListener {
202 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800203 * Called when {@link CancellationSignal#cancel} is invoked.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800204 */
205 void onCancel();
206 }
207
Jeff Brown4c1241d2012-02-02 17:05:00 -0800208 private static final class Transport extends ICancellationSignal.Stub {
209 final CancellationSignal mCancellationSignal = new CancellationSignal();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800210
211 @Override
212 public void cancel() throws RemoteException {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800213 mCancellationSignal.cancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800214 }
215 }
216}