Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ead0a9f7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove onRemoved callbacks"

parents da3a9a08 1d7e0baa
Loading
Loading
Loading
Loading
+132 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.listeners;

import android.annotation.Nullable;

import java.util.concurrent.Executor;
import java.util.function.Supplier;

/**
 * Interface (trait) for executing listener style operations on an executor.
 */
public interface ListenerExecutor {

    /**
     * An listener operation to perform.
     *
     * @param <TListener> listener type
     */
    interface ListenerOperation<TListener> {
        /**
         * Performs the operation on the given listener.
         */
        void operate(TListener listener) throws Exception;

        /**
         * Called before this operation is to be run. Some operations may be canceled before they
         * are run, in which case this method may not be called. {@link #onPostExecute(boolean)}
         * will only be run if this method was run.
         */
        default void onPreExecute() {}

        /**
         * Called if the operation fails while running. Will not be invoked in the event of a
         * RuntimeException, which will propagate normally. Implementations of
         * {@link ListenerExecutor} have the option to override
         * {@link ListenerExecutor#onOperationFailure(ListenerOperation, Exception)} instead to
         * intercept failures at the class level.
         */
        default void onFailure(Exception e) {
            // implementations should handle any exceptions that may be thrown
            throw new AssertionError(e);
        }

        /**
         * Called after the operation is run. This method will always be called if
         * {@link #onPreExecute()} is called. Success implies that the operation was run to
         * completion with no failures.
         */
        default void onPostExecute(boolean success) {}

        /**
         * Called after this operation is complete (which does not imply that it was necessarily
         * run). Will always be called once per operation, no matter if the operation was run or
         * not. Success implies that the operation was run to completion with no failures.
         */
        default void onComplete(boolean success) {}
    }

    /**
     * May be override to handle operation failures at a class level. Will not be invoked in the
     * event of a RuntimeException, which will propagate normally.
     */
    default <TListener> void onOperationFailure(ListenerOperation<TListener> operation,
            Exception exception) {
        operation.onFailure(exception);
    }

    /**
     * Executes the given listener operation on the given executor, using the provided listener
     * supplier. If the supplier returns a null value, or a value during the operation that does not
     * match the value prior to the operation, then the operation is considered canceled.
     */
    default <TListener> void executeSafely(Executor executor, Supplier<TListener> listenerSupplier,
            @Nullable ListenerOperation<TListener> operation) {
        if (operation == null) {
            return;
        }

        boolean executing = false;
        boolean preexecute = false;
        try {
            TListener listener = listenerSupplier.get();
            if (listener == null) {
                return;
            }

            operation.onPreExecute();
            preexecute = true;
            executor.execute(() -> {
                boolean success = false;
                try {
                    if (listener == listenerSupplier.get()) {
                        operation.operate(listener);
                        success = true;
                    }
                } catch (Exception e) {
                    if (e instanceof RuntimeException) {
                        throw (RuntimeException) e;
                    } else {
                        onOperationFailure(operation, e);
                    }
                } finally {
                    operation.onPostExecute(success);
                    operation.onComplete(success);
                }
            });
            executing = true;
        } finally {
            if (!executing) {
                if (preexecute) {
                    operation.onPostExecute(false);
                }
                operation.onComplete(false);
            }
        }
    }
}
+0 −4
Original line number Original line Diff line number Diff line
@@ -45,10 +45,6 @@ public class ListenerTransport<TListener> {
        mListener = listener;
        mListener = listener;
    }
    }


    final boolean isRegistered() {
        return mListener != null;
    }

    /**
    /**
     * Prevents any listener invocations that happen-after this call.
     * Prevents any listener invocations that happen-after this call.
     */
     */
+0 −145
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.listeners;

import android.annotation.NonNull;
import android.os.RemoteException;
import android.util.ArrayMap;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.util.Objects;

/**
 * A listener manager which tracks listeners along with their keys. This class enforces proper use
 * of transport objects and ensure unregistration race conditions are handled properly. If listeners
 * should be multiplexed before being sent to the server, see {@link ListenerTransportMultiplexer}
 * instead.
 *
 * @param <TTransport> transport type
 */
public abstract class ListenerTransportManager<TTransport extends ListenerTransport<?>> {

    @GuardedBy("mTransports")
    private final ArrayMap<Object, TTransport> mTransports = new ArrayMap<>();

    /**
     * Should be implemented to register the transport with the server.
     *
     * @see #reregisterWithServer(ListenerTransport, ListenerTransport)
     */
    protected abstract void registerWithServer(TTransport transport) throws RemoteException;

    /**
     * Invoked when the server already has a transport registered for a key, and it is being
     * replaced with a new transport. The default implementation unregisters the old transport, then
     * registers the new transport, but this may be overridden by subclasses in order to reregister
     * more efficiently.
     */
    protected void reregisterWithServer(TTransport oldTransport, TTransport newTransport)
            throws RemoteException {
        unregisterWithServer(oldTransport);
        registerWithServer(newTransport);
    }

    /**
     * Should be implemented to unregister the transport from the server.
     */
    protected abstract void unregisterWithServer(TTransport transport) throws RemoteException;

    /**
     * Adds a new transport with the given key and makes a call to add the transport server side. If
     * a transport already exists with that key, it will be replaced by the new transport and
     * {@link #reregisterWithServer(ListenerTransport, ListenerTransport)} will be invoked to
     * replace the old transport with the new transport server side. If no transport exists with
     * that key, it will be added server side via {@link #registerWithServer(ListenerTransport)}.
     */
    protected void registerListener(@NonNull Object key, @NonNull TTransport transport) {
        Objects.requireNonNull(key);
        Objects.requireNonNull(transport);

        synchronized (mTransports) {
            TTransport oldTransport = mTransports.put(key, transport);
            if (oldTransport != null) {
                oldTransport.unregister();
            }

            Preconditions.checkState(transport.isRegistered());

            boolean registered = false;
            try {
                if (oldTransport == null) {
                    registerWithServer(transport);
                } else {
                    reregisterWithServer(oldTransport, transport);
                }
                registered = true;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            } finally {
                if (!registered) {
                    transport.unregister();
                    mTransports.remove(key);
                }
            }
        }
    }

    /**
     * Removes the transport with the given key, and makes a call to remove the transport server
     * side via {@link #unregisterWithServer(ListenerTransport)}.
     */
    protected void unregisterListener(@NonNull Object key) {
        Objects.requireNonNull(key);

        synchronized (mTransports) {
            TTransport transport = mTransports.remove(key);
            if (transport == null) {
                return;
            }

            transport.unregister();
            try {
                unregisterWithServer(transport);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

    /**
     * Removes the given transport with the given key if such a mapping exists. This only removes
     * the client registration, it does not make any calls to remove the transport server side. The
     * intended use is for when the transport is already removed server side and only client side
     * cleanup is necessary.
     */
    protected void removeTransport(@NonNull Object key, @NonNull ListenerTransport<?> transport) {
        Objects.requireNonNull(key);
        Objects.requireNonNull(transport);

        synchronized (mTransports) {
            TTransport typedTransport = mTransports.get(key);
            if (typedTransport != transport) {
                return;
            }

            mTransports.remove(key);
            typedTransport.unregister();
        }
    }
}
+6 −10
Original line number Original line Diff line number Diff line
@@ -21,13 +21,12 @@ import android.annotation.Nullable;
import android.os.Build;
import android.os.Build;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collection;
import java.util.Objects;
import java.util.Objects;
@@ -38,8 +37,7 @@ import java.util.function.Consumer;
 * A listener multiplexer designed for use by client-side code. This class ensures that listeners
 * A listener multiplexer designed for use by client-side code. This class ensures that listeners
 * are never invoked while a lock is held. This class is only useful for multiplexing listeners -
 * are never invoked while a lock is held. This class is only useful for multiplexing listeners -
 * if all client listeners can be combined into a single server request, and all server results will
 * if all client listeners can be combined into a single server request, and all server results will
 * be delivered to all clients. If this is not the case, see {@link ListenerTransportManager}
 * be delivered to all clients.
 * instead.
 *
 *
 * By default, the multiplexer will replace requests on the server simply by registering the new
 * By default, the multiplexer will replace requests on the server simply by registering the new
 * request and trusting the server to know this is replacing the old request. If the server needs to
 * request and trusting the server to know this is replacing the old request. If the server needs to
@@ -229,9 +227,7 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> {
    /**
    /**
     * Dumps debug information.
     * Dumps debug information.
     */
     */
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");

        ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations;
        ArrayMap<Object, RequestListenerTransport<TRequest, TListener>> registrations;
        synchronized (mLock) {
        synchronized (mLock) {
            registrations = mRegistrations;
            registrations = mRegistrations;
@@ -239,12 +235,12 @@ public abstract class ListenerTransportMultiplexer<TRequest, TListener> {
            ipw.print("service: ");
            ipw.print("service: ");
            if (mServiceRegistered) {
            if (mServiceRegistered) {
                if (mCurrentRequest == null) {
                if (mCurrentRequest == null) {
                    pw.print("request registered");
                    ipw.print("request registered");
                } else {
                } else {
                    pw.print("request registered - " + mCurrentRequest);
                    ipw.print("request registered - " + mCurrentRequest);
                }
                }
            } else {
            } else {
                pw.print("unregistered");
                ipw.print("unregistered");
            }
            }
            ipw.println();
            ipw.println();
        }
        }
+28 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.location;

import android.location.Location;

/**
 * Listener for single locations.
 * {@hide}
 */
oneway interface ILocationCallback
{
    void onLocation(in @nullable Location location);
}
Loading