blob: 260f7ade8ab713b68d11d45850c59d15c2107b16 [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
Artur Satayevafdb23a2019-12-10 17:47:53 +000019import android.compat.annotation.UnsupportedAppUsage;
Artur Satayev70507ed2019-07-29 13:18:27 +010020
Jeff Brown75ea64f2012-01-25 19:37:13 -080021/**
22 * Provides the ability to cancel an operation in progress.
23 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080024public final class CancellationSignal {
Artur Satayev70507ed2019-07-29 13:18:27 +010025 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown75ea64f2012-01-25 19:37:13 -080026 private boolean mIsCanceled;
Artur Satayev70507ed2019-07-29 13:18:27 +010027 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown75ea64f2012-01-25 19:37:13 -080028 private OnCancelListener mOnCancelListener;
Artur Satayev70507ed2019-07-29 13:18:27 +010029 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brown4c1241d2012-02-02 17:05:00 -080030 private ICancellationSignal mRemote;
Artur Satayev70507ed2019-07-29 13:18:27 +010031 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brownaeee2f52012-04-26 17:36:12 -070032 private boolean mCancelInProgress;
Jeff Brown75ea64f2012-01-25 19:37:13 -080033
34 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080035 * Creates a cancellation signal, initially not canceled.
Jeff Brown75ea64f2012-01-25 19:37:13 -080036 */
Jeff Brown4c1241d2012-02-02 17:05:00 -080037 public CancellationSignal() {
Jeff Brown75ea64f2012-01-25 19:37:13 -080038 }
39
40 /**
41 * Returns true if the operation has been canceled.
42 *
43 * @return True if the operation has been canceled.
44 */
45 public boolean isCanceled() {
46 synchronized (this) {
47 return mIsCanceled;
48 }
49 }
50
51 /**
52 * Throws {@link OperationCanceledException} if the operation has been canceled.
53 *
54 * @throws OperationCanceledException if the operation has been canceled.
55 */
56 public void throwIfCanceled() {
57 if (isCanceled()) {
58 throw new OperationCanceledException();
59 }
60 }
61
62 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080063 * Cancels the operation and signals the cancellation listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -080064 * If the operation has not yet started, then it will be canceled as soon as it does.
65 */
66 public void cancel() {
Jeff Brownaeee2f52012-04-26 17:36:12 -070067 final OnCancelListener listener;
68 final ICancellationSignal remote;
Jeff Brown75ea64f2012-01-25 19:37:13 -080069 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -070070 if (mIsCanceled) {
71 return;
72 }
73 mIsCanceled = true;
74 mCancelInProgress = true;
75 listener = mOnCancelListener;
76 remote = mRemote;
77 }
78
79 try {
80 if (listener != null) {
81 listener.onCancel();
82 }
83 if (remote != null) {
84 try {
85 remote.cancel();
86 } catch (RemoteException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -080087 }
Jeff Brownaeee2f52012-04-26 17:36:12 -070088 }
89 } finally {
90 synchronized (this) {
91 mCancelInProgress = false;
92 notifyAll();
Jeff Brown75ea64f2012-01-25 19:37:13 -080093 }
94 }
95 }
96
97 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -080098 * Sets the cancellation listener to be called when canceled.
99 *
100 * This method is intended to be used by the recipient of a cancellation signal
101 * such as a database or a content provider to handle cancellation requests
102 * while performing a long-running operation. This method is not intended to be
103 * used by applications themselves.
104 *
105 * If {@link CancellationSignal#cancel} has already been called, then the provided
Jeff Brown75ea64f2012-01-25 19:37:13 -0800106 * listener is invoked immediately.
107 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700108 * This method is guaranteed that the listener will not be called after it
109 * has been removed.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800110 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800111 * @param listener The cancellation listener, or null to remove the current listener.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800112 */
113 public void setOnCancelListener(OnCancelListener listener) {
114 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700115 waitForCancelFinishedLocked();
116
117 if (mOnCancelListener == listener) {
118 return;
119 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800120 mOnCancelListener = listener;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700121 if (!mIsCanceled || listener == null) {
122 return;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800123 }
124 }
Jeff Brownaeee2f52012-04-26 17:36:12 -0700125 listener.onCancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800126 }
127
128 /**
129 * Sets the remote transport.
130 *
Jeff Brownaeee2f52012-04-26 17:36:12 -0700131 * If {@link CancellationSignal#cancel} has already been called, then the provided
132 * remote transport is canceled immediately.
133 *
134 * This method is guaranteed that the remote transport will not be called after it
135 * has been removed.
136 *
Jeff Brown75ea64f2012-01-25 19:37:13 -0800137 * @param remote The remote transport, or null to remove.
138 *
139 * @hide
140 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800141 public void setRemote(ICancellationSignal remote) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800142 synchronized (this) {
Jeff Brownaeee2f52012-04-26 17:36:12 -0700143 waitForCancelFinishedLocked();
144
145 if (mRemote == remote) {
146 return;
147 }
Jeff Brown75ea64f2012-01-25 19:37:13 -0800148 mRemote = remote;
Jeff Brownaeee2f52012-04-26 17:36:12 -0700149 if (!mIsCanceled || remote == null) {
150 return;
151 }
152 }
153 try {
154 remote.cancel();
155 } catch (RemoteException ex) {
156 }
157 }
158
Artur Satayev70507ed2019-07-29 13:18:27 +0100159 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
Jeff Brownaeee2f52012-04-26 17:36:12 -0700160 private void waitForCancelFinishedLocked() {
161 while (mCancelInProgress) {
162 try {
163 wait();
164 } catch (InterruptedException ex) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800165 }
166 }
167 }
168
169 /**
170 * Creates a transport that can be returned back to the caller of
Jeff Brown4c1241d2012-02-02 17:05:00 -0800171 * a Binder function and subsequently used to dispatch a cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800172 *
Jeff Brown4c1241d2012-02-02 17:05:00 -0800173 * @return The new cancellation signal transport.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800174 *
175 * @hide
176 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800177 public static ICancellationSignal createTransport() {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800178 return new Transport();
179 }
180
181 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800182 * Given a locally created transport, returns its associated cancellation signal.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800183 *
184 * @param transport The locally created transport, or null if none.
Jeff Brown4c1241d2012-02-02 17:05:00 -0800185 * @return The associated cancellation signal, or null if none.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800186 *
187 * @hide
188 */
Jeff Brown4c1241d2012-02-02 17:05:00 -0800189 public static CancellationSignal fromTransport(ICancellationSignal transport) {
Jeff Brown75ea64f2012-01-25 19:37:13 -0800190 if (transport instanceof Transport) {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800191 return ((Transport)transport).mCancellationSignal;
Jeff Brown75ea64f2012-01-25 19:37:13 -0800192 }
193 return null;
194 }
195
196 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800197 * Listens for cancellation.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800198 */
199 public interface OnCancelListener {
200 /**
Jeff Brown4c1241d2012-02-02 17:05:00 -0800201 * Called when {@link CancellationSignal#cancel} is invoked.
Jeff Brown75ea64f2012-01-25 19:37:13 -0800202 */
203 void onCancel();
204 }
205
Jeff Brown4c1241d2012-02-02 17:05:00 -0800206 private static final class Transport extends ICancellationSignal.Stub {
207 final CancellationSignal mCancellationSignal = new CancellationSignal();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800208
209 @Override
210 public void cancel() throws RemoteException {
Jeff Brown4c1241d2012-02-02 17:05:00 -0800211 mCancellationSignal.cancel();
Jeff Brown75ea64f2012-01-25 19:37:13 -0800212 }
213 }
214}