Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +28 −1 Original line number Diff line number Diff line Loading @@ -17,19 +17,28 @@ package com.android.wm.shell.dagger.pip; import android.annotation.NonNull; import android.content.Context; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipTransition; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import dagger.Module; import dagger.Provides; import java.util.Optional; /** * Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be * the successor of its sibling {@link Pip1Module}. Loading @@ -42,8 +51,26 @@ public abstract class Pip2Module { @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) { PipBoundsAlgorithm pipBoundsAlgorithm, Optional<PipController> pipController) { return new PipTransition(shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm); } @WMSingleton @Provides static Optional<PipController> providePipController(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { if (!PipUtils.isPip2ExperimentEnabled()) { return Optional.empty(); } else { return Optional.ofNullable(PipController.create( context, shellInit, shellController, displayController, displayInsetsController, pipDisplayLayoutState)); } } } libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java 0 → 100644 +133 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.pip2.phone; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import android.content.Context; import android.content.res.Configuration; import android.view.InsetsState; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements ConfigurationChangeListener, DisplayController.OnDisplaysChangedListener { private static final String TAG = PipController.class.getSimpleName(); private Context mContext; private ShellController mShellController; private DisplayController mDisplayController; private DisplayInsetsController mDisplayInsetsController; private PipDisplayLayoutState mPipDisplayLayoutState; private PipController(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; mShellController = shellController; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; mPipDisplayLayoutState = pipDisplayLayoutState; if (PipUtils.isPip2ExperimentEnabled()) { shellInit.addInitCallback(this::onInit, this); } } private void onInit() { // Ensure that we have the display info in case we get calls to update the bounds before the // listener calls back mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId()); DisplayLayout layout = new DisplayLayout(mContext, mContext.getDisplay()); mPipDisplayLayoutState.setDisplayLayout(layout); mShellController.addConfigurationChangeListener(this); mDisplayController.addDisplayWindowListener(this); mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), new DisplayInsetsController.OnInsetsChangedListener() { @Override public void insetsChanged(InsetsState insetsState) { onDisplayChanged(mDisplayController .getDisplayLayout(mPipDisplayLayoutState.getDisplayId())); } }); } /** * Instantiates {@link PipController}, returns {@code null} if the feature not supported. */ public static PipController create(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Device doesn't support Pip feature", TAG); return null; } return new PipController(context, shellInit, shellController, displayController, displayInsetsController, pipDisplayLayoutState); } @Override public void onConfigurationChanged(Configuration newConfiguration) { mPipDisplayLayoutState.onConfigurationChanged(); } @Override public void onThemeChanged() { onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay())); } @Override public void onDisplayAdded(int displayId) { if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); } @Override public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); } private void onDisplayChanged(DisplayLayout layout) { mPipDisplayLayoutState.setDisplayLayout(layout); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +28 −1 Original line number Diff line number Diff line Loading @@ -17,19 +17,28 @@ package com.android.wm.shell.dagger.pip; import android.annotation.NonNull; import android.content.Context; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipTransition; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import dagger.Module; import dagger.Provides; import java.util.Optional; /** * Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be * the successor of its sibling {@link Pip1Module}. Loading @@ -42,8 +51,26 @@ public abstract class Pip2Module { @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) { PipBoundsAlgorithm pipBoundsAlgorithm, Optional<PipController> pipController) { return new PipTransition(shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm); } @WMSingleton @Provides static Optional<PipController> providePipController(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { if (!PipUtils.isPip2ExperimentEnabled()) { return Optional.empty(); } else { return Optional.ofNullable(PipController.create( context, shellInit, shellController, displayController, displayInsetsController, pipDisplayLayoutState)); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java 0 → 100644 +133 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.pip2.phone; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import android.content.Context; import android.content.res.Configuration; import android.view.InsetsState; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ConfigurationChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements ConfigurationChangeListener, DisplayController.OnDisplaysChangedListener { private static final String TAG = PipController.class.getSimpleName(); private Context mContext; private ShellController mShellController; private DisplayController mDisplayController; private DisplayInsetsController mDisplayInsetsController; private PipDisplayLayoutState mPipDisplayLayoutState; private PipController(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { mContext = context; mShellController = shellController; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; mPipDisplayLayoutState = pipDisplayLayoutState; if (PipUtils.isPip2ExperimentEnabled()) { shellInit.addInitCallback(this::onInit, this); } } private void onInit() { // Ensure that we have the display info in case we get calls to update the bounds before the // listener calls back mPipDisplayLayoutState.setDisplayId(mContext.getDisplayId()); DisplayLayout layout = new DisplayLayout(mContext, mContext.getDisplay()); mPipDisplayLayoutState.setDisplayLayout(layout); mShellController.addConfigurationChangeListener(this); mDisplayController.addDisplayWindowListener(this); mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), new DisplayInsetsController.OnInsetsChangedListener() { @Override public void insetsChanged(InsetsState insetsState) { onDisplayChanged(mDisplayController .getDisplayLayout(mPipDisplayLayoutState.getDisplayId())); } }); } /** * Instantiates {@link PipController}, returns {@code null} if the feature not supported. */ public static PipController create(Context context, ShellInit shellInit, ShellController shellController, DisplayController displayController, DisplayInsetsController displayInsetsController, PipDisplayLayoutState pipDisplayLayoutState) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Device doesn't support Pip feature", TAG); return null; } return new PipController(context, shellInit, shellController, displayController, displayInsetsController, pipDisplayLayoutState); } @Override public void onConfigurationChanged(Configuration newConfiguration) { mPipDisplayLayoutState.onConfigurationChanged(); } @Override public void onThemeChanged() { onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay())); } @Override public void onDisplayAdded(int displayId) { if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); } @Override public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { if (displayId != mPipDisplayLayoutState.getDisplayId()) { return; } onDisplayChanged(mDisplayController.getDisplayLayout(displayId)); } private void onDisplayChanged(DisplayLayout layout) { mPipDisplayLayoutState.setDisplayLayout(layout); } }