| /* |
| * Copyright (C) 2019 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.annotation.Nullable; |
| import android.os.RemoteException; |
| import android.util.Slog; |
| import android.view.IDisplayChangeWindowCallback; |
| import android.view.IDisplayChangeWindowController; |
| import android.view.IWindowManager; |
| import android.window.DisplayAreaInfo; |
| import android.window.WindowContainerTransaction; |
| |
| import androidx.annotation.BinderThread; |
| |
| import com.android.wm.shell.common.annotations.ShellMainThread; |
| |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| /** |
| * This module deals with display rotations coming from WM. When WM starts a rotation: after it has |
| * frozen the screen, it will call into this class. This will then call all registered local |
| * controllers and give them a chance to queue up task changes to be applied synchronously with that |
| * rotation. |
| */ |
| public class DisplayChangeController { |
| private static final String TAG = DisplayChangeController.class.getSimpleName(); |
| |
| private final ShellExecutor mMainExecutor; |
| private final IWindowManager mWmService; |
| private final IDisplayChangeWindowController mControllerImpl; |
| |
| private final CopyOnWriteArrayList<OnDisplayChangingListener> mDisplayChangeListener = |
| new CopyOnWriteArrayList<>(); |
| |
| public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) { |
| mMainExecutor = mainExecutor; |
| mWmService = wmService; |
| mControllerImpl = new DisplayChangeWindowControllerImpl(); |
| try { |
| mWmService.setDisplayChangeWindowController(mControllerImpl); |
| } catch (RemoteException e) { |
| throw new RuntimeException("Unable to register rotation controller"); |
| } |
| } |
| |
| /** |
| * Adds a display rotation controller. |
| */ |
| public void addDisplayChangeListener(OnDisplayChangingListener listener) { |
| mDisplayChangeListener.add(listener); |
| } |
| |
| /** |
| * Removes a display rotation controller. |
| */ |
| public void removeDisplayChangeListener(OnDisplayChangingListener listener) { |
| mDisplayChangeListener.remove(listener); |
| } |
| |
| /** Query all listeners for changes that should happen on display change. */ |
| public void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId, |
| int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) { |
| for (OnDisplayChangingListener c : mDisplayChangeListener) { |
| c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct); |
| } |
| } |
| |
| private void onDisplayChange(int displayId, int fromRotation, int toRotation, |
| DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) { |
| WindowContainerTransaction t = new WindowContainerTransaction(); |
| dispatchOnDisplayChange(t, displayId, fromRotation, toRotation, newDisplayAreaInfo); |
| try { |
| callback.continueDisplayChange(t); |
| } catch (RemoteException e) { |
| Slog.e(TAG, "Failed to continue handling display change", e); |
| } |
| } |
| |
| @BinderThread |
| private class DisplayChangeWindowControllerImpl |
| extends IDisplayChangeWindowController.Stub { |
| @Override |
| public void onDisplayChange(int displayId, int fromRotation, int toRotation, |
| DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) { |
| mMainExecutor.execute(() -> DisplayChangeController.this |
| .onDisplayChange(displayId, fromRotation, toRotation, |
| newDisplayAreaInfo, callback)); |
| } |
| } |
| |
| /** |
| * Give a listener a chance to queue up configuration changes to execute as part of a |
| * display rotation. The contents of {@link #onDisplayChange} must run synchronously. |
| */ |
| @ShellMainThread |
| public interface OnDisplayChangingListener { |
| /** |
| * Called before the display size has changed. |
| * Contents of this method must run synchronously. |
| * @param displayId display id of the display that is under the change |
| * @param fromRotation rotation before the change |
| * @param toRotation rotation after the change |
| * @param newDisplayAreaInfo display area info after applying the update |
| * @param t A task transaction to populate. |
| */ |
| void onDisplayChange(int displayId, int fromRotation, int toRotation, |
| @Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction t); |
| } |
| } |