CancellationSignal.java revision a7771df3696954f0e279407e8894a916a7cb26cc
175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown/*
275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Copyright (C) 2012 The Android Open Source Project
375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown *
475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * you may not use this file except in compliance with the License.
675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * You may obtain a copy of the License at
775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown *
875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown *
1075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Unless required by applicable law or agreed to in writing, software
1175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * See the License for the specific language governing permissions and
1475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * limitations under the License.
1575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */
1675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
17a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownpackage android.os;
1875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
19a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.ICancellationSignal;
20a7771df3696954f0e279407e8894a916a7cb26ccJeff Brownimport android.os.ICancellationSignal.Stub;
2175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
2275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown/**
2375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Provides the ability to cancel an operation in progress.
2475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */
254c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brownpublic final class CancellationSignal {
2675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private boolean mIsCanceled;
2775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private OnCancelListener mOnCancelListener;
284c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    private ICancellationSignal mRemote;
29aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    private boolean mCancelInProgress;
3075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
3175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
324c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Creates a cancellation signal, initially not canceled.
3375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
344c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public CancellationSignal() {
3575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
3675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
3775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
3875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Returns true if the operation has been canceled.
3975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
4075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @return True if the operation has been canceled.
4175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
4275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public boolean isCanceled() {
4375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
4475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return mIsCanceled;
4575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
4675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
4775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
4875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
4975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Throws {@link OperationCanceledException} if the operation has been canceled.
5075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
5175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation has been canceled.
5275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
5375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void throwIfCanceled() {
5475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (isCanceled()) {
5575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            throw new OperationCanceledException();
5675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
5775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
5875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
5975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
604c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Cancels the operation and signals the cancellation listener.
6175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * If the operation has not yet started, then it will be canceled as soon as it does.
6275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
6375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void cancel() {
64aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        final OnCancelListener listener;
65aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        final ICancellationSignal remote;
6675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
67aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mIsCanceled) {
68aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
69aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
70aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            mIsCanceled = true;
71aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            mCancelInProgress = true;
72aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            listener = mOnCancelListener;
73aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            remote = mRemote;
74aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
75aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
76aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        try {
77aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (listener != null) {
78aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                listener.onCancel();
79aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
80aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (remote != null) {
81aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                try {
82aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                    remote.cancel();
83aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                } catch (RemoteException ex) {
8475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                }
8575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
86aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        } finally {
87aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            synchronized (this) {
88aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                mCancelInProgress = false;
89aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                notifyAll();
90aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
9175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
9275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
9375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
9475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
954c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Sets the cancellation listener to be called when canceled.
964c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     *
974c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * This method is intended to be used by the recipient of a cancellation signal
984c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * such as a database or a content provider to handle cancellation requests
994c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * while performing a long-running operation.  This method is not intended to be
1004c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * used by applications themselves.
1014c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     *
1024c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * If {@link CancellationSignal#cancel} has already been called, then the provided
10375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * listener is invoked immediately.
10475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
105aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * This method is guaranteed that the listener will not be called after it
106aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * has been removed.
10775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
1084c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param listener The cancellation listener, or null to remove the current listener.
10975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
11075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void setOnCancelListener(OnCancelListener listener) {
11175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
112aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            waitForCancelFinishedLocked();
113aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
114aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mOnCancelListener == listener) {
115aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
116aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
11775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mOnCancelListener = listener;
118aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (!mIsCanceled || listener == null) {
119aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
12075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
12175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
122aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        listener.onCancel();
12375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
12475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
12575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
12675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Sets the remote transport.
12775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
128aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * If {@link CancellationSignal#cancel} has already been called, then the provided
129aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * remote transport is canceled immediately.
130aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     *
131aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * This method is guaranteed that the remote transport will not be called after it
132aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * has been removed.
133aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     *
13475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @param remote The remote transport, or null to remove.
13575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
13675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
13775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1384c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public void setRemote(ICancellationSignal remote) {
13975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
140aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            waitForCancelFinishedLocked();
141aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
142aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mRemote == remote) {
143aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
144aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
14575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mRemote = remote;
146aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (!mIsCanceled || remote == null) {
147aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
148aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
149aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
150aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        try {
151aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            remote.cancel();
152aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        } catch (RemoteException ex) {
153aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
154aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    }
155aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
156aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    private void waitForCancelFinishedLocked() {
157aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        while (mCancelInProgress) {
158aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            try {
159aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                wait();
160aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            } catch (InterruptedException ex) {
16175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
16275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
16375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
16475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
16575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
16675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Creates a transport that can be returned back to the caller of
1674c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * a Binder function and subsequently used to dispatch a cancellation signal.
16875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
1694c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @return The new cancellation signal transport.
17075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
17175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
17275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1734c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public static ICancellationSignal createTransport() {
17475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return new Transport();
17575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
17675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
17775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
1784c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Given a locally created transport, returns its associated cancellation signal.
17975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
18075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @param transport The locally created transport, or null if none.
1814c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @return The associated cancellation signal, or null if none.
18275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
18375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
18475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1854c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public static CancellationSignal fromTransport(ICancellationSignal transport) {
18675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (transport instanceof Transport) {
1874c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            return ((Transport)transport).mCancellationSignal;
18875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
18975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return null;
19075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
19175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
19275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
1934c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Listens for cancellation.
19475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
19575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public interface OnCancelListener {
19675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        /**
1974c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown         * Called when {@link CancellationSignal#cancel} is invoked.
19875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown         */
19975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        void onCancel();
20075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
20175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
2024c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    private static final class Transport extends ICancellationSignal.Stub {
2034c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        final CancellationSignal mCancellationSignal = new CancellationSignal();
20475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
20575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        @Override
20675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        public void cancel() throws RemoteException {
2074c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            mCancellationSignal.cancel();
20875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
20975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
21075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown}
211