1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.location.listeners;
18 
19 import android.annotation.Nullable;
20 
21 import java.util.Objects;
22 import java.util.concurrent.Executor;
23 import java.util.concurrent.atomic.AtomicBoolean;
24 
25 /**
26  * A listener registration that stores its own key, and thus can remove itself. By default it will
27  * remove itself if any checked exception occurs on listener execution.
28  *
29  * @param <TKey>               key type
30  * @param <TListener>          listener type
31  */
32 public abstract class RemovableListenerRegistration<TKey, TListener> extends
33         ListenerRegistration<TListener> {
34 
35     @Nullable private volatile TKey mKey;
36     private final AtomicBoolean mRemoved = new AtomicBoolean(false);
37 
RemovableListenerRegistration(Executor executor, TListener listener)38     protected RemovableListenerRegistration(Executor executor, TListener listener) {
39         super(executor, listener);
40     }
41 
42     /**
43      * Must be implemented to return the {@link ListenerMultiplexer} this registration is registered
44      * with. Often this is easiest to accomplish by defining registration subclasses as non-static
45      * inner classes of the multiplexer they are to be used with.
46      */
getOwner()47     protected abstract ListenerMultiplexer<TKey, ? super TListener, ?, ?> getOwner();
48 
49     /**
50      * Returns the key associated with this registration. May not be invoked before
51      * {@link #onRegister(Object)} or after {@link #onUnregister()}.
52      */
getKey()53     protected final TKey getKey() {
54         return Objects.requireNonNull(mKey);
55     }
56 
57     /**
58      * Convenience method equivalent to invoking {@link #remove(boolean)} with the
59      * {@code immediately} parameter set to true.
60      */
remove()61     public final void remove() {
62         remove(true);
63     }
64 
65     /**
66      * Removes this registration. If the {@code immediately} parameter is true, all pending listener
67      * invocations will fail. If the {@code immediately} parameter is false, listener invocations
68      * that were scheduled before remove was invoked (including invocations scheduled within {@link
69      * #onRemove(boolean)}) will continue, but any listener invocations scheduled after remove was
70      * invoked will fail.
71      *
72      * <p>Only the first call to this method will ever go through (and so {@link #onRemove(boolean)}
73      * will only ever be invoked once).
74      *
75      * <p>Does nothing if invoked before {@link #onRegister()} or after {@link #onUnregister()}.
76      */
remove(boolean immediately)77     public final void remove(boolean immediately) {
78         TKey key = mKey;
79         if (key != null && !mRemoved.getAndSet(true)) {
80             onRemove(immediately);
81             if (immediately) {
82                 getOwner().removeRegistration(key, this);
83             } else {
84                 executeOperation(listener -> getOwner().removeRegistration(key, this));
85             }
86         }
87     }
88 
89     /**
90      * Invoked just before this registration is removed due to {@link #remove(boolean)}, on the same
91      * thread as the responsible {@link #remove(boolean)} call.
92      *
93      * <p>This method will only ever be invoked once, no matter how many calls to {@link
94      * #remove(boolean)} are made, as any registration can only be removed once.
95      */
onRemove(boolean immediately)96     protected void onRemove(boolean immediately) {}
97 
98     @Override
onRegister(Object key)99     protected final void onRegister(Object key) {
100         super.onRegister(key);
101         mKey = (TKey) Objects.requireNonNull(key);
102         onRegister();
103     }
104 
105     /**
106      * May be overridden by subclasses. Invoked when registration occurs. Invoked while holding the
107      * owning multiplexer's internal lock.
108      *
109      * <p>If overridden you must ensure the superclass method is invoked (usually as the first thing
110      * in the overridden method).
111      */
onRegister()112     protected void onRegister() {}
113 
114     @Override
onUnregister()115     protected void onUnregister() {
116         mKey = null;
117         super.onUnregister();
118     }
119 }
120