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;
2075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
2175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown/**
2275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown * Provides the ability to cancel an operation in progress.
2375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown */
244c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brownpublic final class CancellationSignal {
2575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private boolean mIsCanceled;
2675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    private OnCancelListener mOnCancelListener;
274c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    private ICancellationSignal mRemote;
28aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    private boolean mCancelInProgress;
2975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
3075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
314c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Creates a cancellation signal, initially not canceled.
3275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
334c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public CancellationSignal() {
3475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
3575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
3675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
3775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Returns true if the operation has been canceled.
3875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
3975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @return True if the operation has been canceled.
4075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
4175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public boolean isCanceled() {
4275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
4375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            return mIsCanceled;
4475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
4575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
4675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
4775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
4875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Throws {@link OperationCanceledException} if the operation has been canceled.
4975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
5075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @throws OperationCanceledException if the operation has been canceled.
5175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
5275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void throwIfCanceled() {
5375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (isCanceled()) {
5475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            throw new OperationCanceledException();
5575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
5675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
5775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
5875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
594c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Cancels the operation and signals the cancellation listener.
6075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * If the operation has not yet started, then it will be canceled as soon as it does.
6175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
6275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void cancel() {
63aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        final OnCancelListener listener;
64aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        final ICancellationSignal remote;
6575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
66aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mIsCanceled) {
67aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
68aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
69aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            mIsCanceled = true;
70aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            mCancelInProgress = true;
71aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            listener = mOnCancelListener;
72aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            remote = mRemote;
73aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
74aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
75aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        try {
76aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (listener != null) {
77aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                listener.onCancel();
78aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
79aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (remote != null) {
80aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                try {
81aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                    remote.cancel();
82aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                } catch (RemoteException ex) {
8375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                }
8475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
85aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        } finally {
86aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            synchronized (this) {
87aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                mCancelInProgress = false;
88aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                notifyAll();
89aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
9075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
9175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
9275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
9375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
944c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Sets the cancellation listener to be called when canceled.
954c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     *
964c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * This method is intended to be used by the recipient of a cancellation signal
974c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * such as a database or a content provider to handle cancellation requests
984c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * while performing a long-running operation.  This method is not intended to be
994c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * used by applications themselves.
1004c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     *
1014c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * If {@link CancellationSignal#cancel} has already been called, then the provided
10275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * listener is invoked immediately.
10375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
104aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * This method is guaranteed that the listener will not be called after it
105aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * has been removed.
10675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
1074c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @param listener The cancellation listener, or null to remove the current listener.
10875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
10975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public void setOnCancelListener(OnCancelListener listener) {
11075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
111aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            waitForCancelFinishedLocked();
112aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
113aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mOnCancelListener == listener) {
114aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
115aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
11675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mOnCancelListener = listener;
117aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (!mIsCanceled || listener == null) {
118aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
11975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
12075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
121aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        listener.onCancel();
12275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
12375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
12475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
12575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Sets the remote transport.
12675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
127aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * If {@link CancellationSignal#cancel} has already been called, then the provided
128aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * remote transport is canceled immediately.
129aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     *
130aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * This method is guaranteed that the remote transport will not be called after it
131aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     * has been removed.
132aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown     *
13375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @param remote The remote transport, or null to remove.
13475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
13575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
13675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1374c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public void setRemote(ICancellationSignal remote) {
13875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        synchronized (this) {
139aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            waitForCancelFinishedLocked();
140aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
141aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (mRemote == remote) {
142aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
143aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
14475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            mRemote = remote;
145aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            if (!mIsCanceled || remote == null) {
146aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                return;
147aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            }
148aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
149aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        try {
150aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            remote.cancel();
151aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        } catch (RemoteException ex) {
152aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        }
153aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    }
154aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown
155aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown    private void waitForCancelFinishedLocked() {
156aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown        while (mCancelInProgress) {
157aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            try {
158aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown                wait();
159aeee2f5d7564614da7b5e1aedb8816fc6559b2e9Jeff Brown            } catch (InterruptedException ex) {
16075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown            }
16175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
16275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
16375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
16475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
16575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * Creates a transport that can be returned back to the caller of
1664c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * a Binder function and subsequently used to dispatch a cancellation signal.
16775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
1684c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @return The new cancellation signal transport.
16975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
17075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
17175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1724c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public static ICancellationSignal createTransport() {
17375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return new Transport();
17475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
17575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
17675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
1774c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Given a locally created transport, returns its associated cancellation signal.
17875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
17975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @param transport The locally created transport, or null if none.
1804c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * @return The associated cancellation signal, or null if none.
18175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     *
18275ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     * @hide
18375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
1844c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    public static CancellationSignal fromTransport(ICancellationSignal transport) {
18575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        if (transport instanceof Transport) {
1864c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            return ((Transport)transport).mCancellationSignal;
18775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
18875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        return null;
18975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
19075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
19175ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    /**
1924c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown     * Listens for cancellation.
19375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown     */
19475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    public interface OnCancelListener {
19575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        /**
1964c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown         * Called when {@link CancellationSignal#cancel} is invoked.
19775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown         */
19875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        void onCancel();
19975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
20075ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
2014c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown    private static final class Transport extends ICancellationSignal.Stub {
2024c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown        final CancellationSignal mCancellationSignal = new CancellationSignal();
20375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown
20475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        @Override
20575ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        public void cancel() throws RemoteException {
2064c1241df8f8b7fd5ec3dff6c7e0f66271248e76eJeff Brown            mCancellationSignal.cancel();
20775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown        }
20875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown    }
20975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown}
210