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

Commit fcac5264 authored by Winson Chung's avatar Winson Chung Committed by Automerger Merge Worker
Browse files

Merge "Abstract out common code for managing a single instance remote...

Merge "Abstract out common code for managing a single instance remote callback" into sc-v2-dev am: 3e90f3b5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16078803

Change-Id: I0b5dcc8ad34459b4e1de29e24d7bb444333dddda
parents d9dd71a4 3e90f3b5
Loading
Loading
Loading
Loading
+123 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.wm.shell.common;

import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.util.Slog;

import androidx.annotation.BinderThread;

import java.util.function.Consumer;

/**
 * Manages the lifecycle of a single instance of a remote listener, including the clean up if the
 * remote process dies.  All calls on this class should happen on the main shell thread.
 *
 * @param <C> The controller (must be RemoteCallable)
 * @param <L> The remote listener interface type
 */
public class SingleInstanceRemoteListener<C extends RemoteCallable, L extends IInterface> {
    private static final String TAG = SingleInstanceRemoteListener.class.getSimpleName();

    /**
     * Simple callable interface that throws a remote exception.
     */
    public interface RemoteCall<L> {
        void accept(L l) throws RemoteException;
    }

    private final C mCallableController;
    private final Consumer<C> mOnRegisterCallback;
    private final Consumer<C> mOnUnregisterCallback;

    L mListener;

    private final IBinder.DeathRecipient mListenerDeathRecipient =
            new IBinder.DeathRecipient() {
                @Override
                @BinderThread
                public void binderDied() {
                    final C callableController = mCallableController;
                    mCallableController.getRemoteCallExecutor().execute(() -> {
                        mListener = null;
                        mOnUnregisterCallback.accept(callableController);
                    });
                }
            };

    /**
     * @param onRegisterCallback Callback when register() is called (same thread)
     * @param onUnregisterCallback Callback when unregister() is called (same thread as unregister()
     *                             or the callableController.getRemoteCallbackExecutor() thread)
     */
    public SingleInstanceRemoteListener(C callableController,
            Consumer<C> onRegisterCallback,
            Consumer<C> onUnregisterCallback) {
        mCallableController = callableController;
        mOnRegisterCallback = onRegisterCallback;
        mOnUnregisterCallback = onUnregisterCallback;
    }

    /**
     * Registers this listener, storing a reference to it and calls the provided method in the
     * constructor.
     */
    public void register(L listener) {
        if (mListener != null) {
            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0 /* flags */);
        }
        if (listener != null) {
            try {
                listener.asBinder().linkToDeath(mListenerDeathRecipient, 0 /* flags */);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to link to death");
                return;
            }
        }
        mListener = listener;
        mOnRegisterCallback.accept(mCallableController);
    }

    /**
     * Unregisters this listener, removing all references to it and calls the provided method in the
     * constructor.
     */
    public void unregister() {
        if (mListener != null) {
            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0 /* flags */);
        }
        mListener = null;
        mOnUnregisterCallback.accept(mCallableController);
    }

    /**
     * Safely wraps a call to the remote listener.
     */
    public void call(RemoteCall<L> handler) {
        if (mListener == null) {
            Slog.e(TAG, "Failed remote call on null listener");
            return;
        }
        try {
            handler.accept(mListener);
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed remote call", e);
        }
    }
}
 No newline at end of file
+39 −41
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -69,6 +68,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.onehanded.OneHandedController;
@@ -117,13 +117,28 @@ public class PipController implements PipTransitionController.PipTransitionCallb
    private final Rect mTmpInsetBounds = new Rect();

    private boolean mIsInFixedRotation;
    private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
    private PipAnimationListener mPinnedStackAnimationRecentsCallback;

    protected PhonePipMenuController mMenuController;
    protected PipTaskOrganizer mPipTaskOrganizer;
    protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener =
            new PipControllerPinnedTaskListener();

    private interface PipAnimationListener {
        /**
         * Notifies the listener that the Pip animation is started.
         */
        void onPipAnimationStarted();

        /**
         * Notifies the listener about PiP round corner radius changes.
         * Listener can expect an immediate callback the first time they attach.
         *
         * @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
         */
        void onPipCornerRadiusChanged(int cornerRadius);
    }

    /**
     * Handler for display rotation changes.
     */
@@ -551,7 +566,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
                animationType == PipAnimationController.ANIM_TYPE_BOUNDS);
    }

    private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
    private void setPinnedStackAnimationListener(PipAnimationListener callback) {
        mPinnedStackAnimationRecentsCallback = callback;
        onPipCornerRadiusChanged();
    }
@@ -560,11 +575,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
        if (mPinnedStackAnimationRecentsCallback != null) {
            final int cornerRadius =
                    mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
            try {
            mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to call onPipCornerRadiusChanged", e);
            }
        }
    }

@@ -623,11 +634,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
        // Disable touches while the animation is running
        mTouchHandler.setTouchEnabled(false);
        if (mPinnedStackAnimationRecentsCallback != null) {
            try {
            mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e);
            }
        }
    }

@@ -866,22 +873,25 @@ public class PipController implements PipTransitionController.PipTransitionCallb
    @BinderThread
    private static class IPipImpl extends IPip.Stub {
        private PipController mController;
        private IPipAnimationListener mListener;
        private final IBinder.DeathRecipient mListenerDeathRecipient =
                new IBinder.DeathRecipient() {
        private final SingleInstanceRemoteListener<PipController,
                IPipAnimationListener> mListener;
        private final PipAnimationListener mPipAnimationListener = new PipAnimationListener() {
            @Override
                    @BinderThread
                    public void binderDied() {
                        final PipController controller = mController;
                        controller.getRemoteCallExecutor().execute(() -> {
                            mListener = null;
                            controller.setPinnedStackAnimationListener(null);
                        });
            public void onPipAnimationStarted() {
                mListener.call(l -> l.onPipAnimationStarted());
            }

            @Override
            public void onPipCornerRadiusChanged(int cornerRadius) {
                mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius));
            }
        };

        IPipImpl(PipController controller) {
            mController = controller;
            mListener = new SingleInstanceRemoteListener<>(mController,
                    c -> c.setPinnedStackAnimationListener(mPipAnimationListener),
                    c -> c.setPinnedStackAnimationListener(null));
        }

        /**
@@ -925,23 +935,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb
        public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
            executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
                    (controller) -> {
                        if (mListener != null) {
                            // Reset the old death recipient
                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
                                    0 /* flags */);
                        }
                        if (listener != null) {
                            // Register the death recipient for the new listener to clear the listener
                            try {
                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
                                        0 /* flags */);
                            } catch (RemoteException e) {
                                Slog.e(TAG, "Failed to link to death");
                                return;
                            }
                            mListener.register(listener);
                        } else {
                            mListener.unregister();
                        }
                        mListener = listener;
                        controller.setPinnedStackAnimationListener(listener);
                    });
        }
    }
+10 −53
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -61,6 +60,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -433,46 +433,26 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    @BinderThread
    private static class ISplitScreenImpl extends ISplitScreen.Stub {
        private SplitScreenController mController;
        private ISplitScreenListener mListener;
        private final SingleInstanceRemoteListener<SplitScreenController,
                ISplitScreenListener> mListener;
        private final SplitScreen.SplitScreenListener mSplitScreenListener =
                new SplitScreen.SplitScreenListener() {
                    @Override
                    public void onStagePositionChanged(int stage, int position) {
                        try {
                            if (mListener != null) {
                                mListener.onStagePositionChanged(stage, position);
                            }
                        } catch (RemoteException e) {
                            Slog.e(TAG, "onStagePositionChanged", e);
                        }
                        mListener.call(l -> l.onStagePositionChanged(stage, position));
                    }

                    @Override
                    public void onTaskStageChanged(int taskId, int stage, boolean visible) {
                        try {
                            if (mListener != null) {
                                mListener.onTaskStageChanged(taskId, stage, visible);
                            }
                        } catch (RemoteException e) {
                            Slog.e(TAG, "onTaskStageChanged", e);
                        }
                    }
                };
        private final IBinder.DeathRecipient mListenerDeathRecipient =
                new IBinder.DeathRecipient() {
                    @Override
                    @BinderThread
                    public void binderDied() {
                        final SplitScreenController controller = mController;
                        controller.getRemoteCallExecutor().execute(() -> {
                            mListener = null;
                            controller.unregisterSplitScreenListener(mSplitScreenListener);
                        });
                        mListener.call(l -> l.onTaskStageChanged(taskId, stage, visible));
                    }
                };

        public ISplitScreenImpl(SplitScreenController controller) {
            mController = controller;
            mListener = new SingleInstanceRemoteListener<>(controller,
                    c -> c.registerSplitScreenListener(mSplitScreenListener),
                    c -> c.unregisterSplitScreenListener(mSplitScreenListener));
        }

        /**
@@ -485,36 +465,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        @Override
        public void registerSplitScreenListener(ISplitScreenListener listener) {
            executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
                    (controller) -> {
                        if (mListener != null) {
                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
                                    0 /* flags */);
                        }
                        if (listener != null) {
                            try {
                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
                                        0 /* flags */);
                            } catch (RemoteException e) {
                                Slog.e(TAG, "Failed to link to death");
                                return;
                            }
                        }
                        mListener = listener;
                        controller.registerSplitScreenListener(mSplitScreenListener);
                    });
                    (controller) -> mListener.register(listener));
        }

        @Override
        public void unregisterSplitScreenListener(ISplitScreenListener listener) {
            executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
                    (controller) -> {
                        if (mListener != null) {
                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
                                    0 /* flags */);
                        }
                        mListener = null;
                        controller.unregisterSplitScreenListener(mSplitScreenListener);
                    });
                    (controller) -> mListener.unregister());
        }

        @Override
+12 −40
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import com.android.internal.util.function.TriConsumer;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.TransactionPool;

/**
@@ -237,24 +238,19 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
    @BinderThread
    private static class IStartingWindowImpl extends IStartingWindow.Stub {
        private StartingWindowController mController;
        private IStartingWindowListener mListener;
        private SingleInstanceRemoteListener<StartingWindowController,
                IStartingWindowListener> mListener;
        private final TriConsumer<Integer, Integer, Integer> mStartingWindowListener =
                this::notifyIStartingWindowListener;
        private final IBinder.DeathRecipient mListenerDeathRecipient =
                new IBinder.DeathRecipient() {
                    @Override
                    @BinderThread
                    public void binderDied() {
                        final StartingWindowController controller = mController;
                        controller.getRemoteCallExecutor().execute(() -> {
                            mListener = null;
                            controller.setStartingWindowListener(null);
                        });
                    }
                (taskId, supportedType, startingWindowBackgroundColor) -> {
                    mListener.call(l -> l.onTaskLaunching(taskId, supportedType,
                            startingWindowBackgroundColor));
                };

        public IStartingWindowImpl(StartingWindowController controller) {
            mController = controller;
            mListener = new SingleInstanceRemoteListener<>(controller,
                    c -> c.setStartingWindowListener(mStartingWindowListener),
                    c -> c.setStartingWindowListener(null));
        }

        /**
@@ -268,36 +264,12 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
        public void setStartingWindowListener(IStartingWindowListener listener) {
            executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
                    (controller) -> {
                        if (mListener != null) {
                            // Reset the old death recipient
                            mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
                                    0 /* flags */);
                        }
                        if (listener != null) {
                            try {
                                listener.asBinder().linkToDeath(mListenerDeathRecipient,
                                        0 /* flags */);
                            } catch (RemoteException e) {
                                Slog.e(TAG, "Failed to link to death");
                                return;
                            }
                            mListener.register(listener);
                        } else {
                            mListener.unregister();
                        }
                        mListener = listener;
                        controller.setStartingWindowListener(mStartingWindowListener);
                    });
        }

        private void notifyIStartingWindowListener(int taskId, int supportedType,
                int startingWindowBackgroundColor) {
            if (mListener == null) {
                return;
            }

            try {
                mListener.onTaskLaunching(taskId, supportedType, startingWindowBackgroundColor);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to notify task launching", e);
            }
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -38,11 +38,11 @@ public interface ShellTransitions {
    /**
     * Registers a remote transition.
     */
    void registerRemote(@NonNull TransitionFilter filter,
            @NonNull RemoteTransition remoteTransition);
    default void registerRemote(@NonNull TransitionFilter filter,
            @NonNull RemoteTransition remoteTransition) {}

    /**
     * Unregisters a remote transition.
     */
    void unregisterRemote(@NonNull RemoteTransition remoteTransition);
    default void unregisterRemote(@NonNull RemoteTransition remoteTransition) {}
}
Loading