Loading core/java/android/app/ActivityThread.java +23 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,7 @@ import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; /** * This manages the execution of the main thread in an Loading Loading @@ -370,6 +371,11 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("mAppThread") private int mLastProcessState = PROCESS_STATE_UNKNOWN; ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>(); @NonNull private final ConfigurationChangedListenerController mConfigurationChangedListenerController = new ConfigurationChangedListenerController(); private int mLastSessionId; // Holds the value of the last reported device ID value from the server for the top activity. int mLastReportedDeviceId; Loading Loading @@ -3540,6 +3546,21 @@ public final class ActivityThread extends ClientTransactionHandler return mConfigurationController.getConfiguration(); } /** * @hide */ public void addConfigurationChangedListener(Executor executor, Consumer<IBinder> consumer) { mConfigurationChangedListenerController.addListener(executor, consumer); } /** * @hide */ public void removeConfigurationChangedListener(Consumer<IBinder> consumer) { mConfigurationChangedListenerController.removeListener(consumer); } @Override public void updatePendingConfiguration(Configuration config) { final Configuration updatedConfig = Loading Loading @@ -6098,6 +6119,8 @@ public final class ActivityThread extends ClientTransactionHandler " did not call through to super.onConfigurationChanged()"); } } mConfigurationChangedListenerController .dispatchOnConfigurationChanged(activity.getActivityToken()); return configToReport; } Loading core/java/android/app/ConfigurationChangedListenerController.java 0 → 100644 +116 −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 android.app; import android.annotation.NonNull; import android.os.IBinder; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Manages listeners for unfiltered configuration changes. * @hide */ class ConfigurationChangedListenerController { private final Object mLock = new Object(); @GuardedBy("mLock") private final List<ListenerContainer> mListenerContainers = new ArrayList<>(); /** * Adds a listener to receive updates when they are dispatched. This only dispatches updates and * does not relay the last emitted value. If called with the same listener then this method does * not have any effect. * @param executor an executor that is used to dispatch the updates. * @param consumer a listener interested in receiving updates. */ void addListener(@NonNull Executor executor, @NonNull Consumer<IBinder> consumer) { synchronized (mLock) { if (indexOf(consumer) > -1) { return; } mListenerContainers.add(new ListenerContainer(executor, consumer)); } } /** * Removes the listener that was previously registered. If the listener was not registered this * method does not have any effect. */ void removeListener(@NonNull Consumer<IBinder> consumer) { synchronized (mLock) { final int index = indexOf(consumer); if (index > -1) { mListenerContainers.remove(index); } } } /** * Dispatches the update to all registered listeners * @param activityToken a token for the {@link Activity} that received a configuration update. */ void dispatchOnConfigurationChanged(@NonNull IBinder activityToken) { final List<ListenerContainer> consumers; synchronized (mLock) { consumers = new ArrayList<>(mListenerContainers); } for (int i = 0; i < consumers.size(); i++) { consumers.get(i).accept(activityToken); } } @GuardedBy("mLock") private int indexOf(Consumer<IBinder> consumer) { for (int i = 0; i < mListenerContainers.size(); i++) { if (mListenerContainers.get(i).isMatch(consumer)) { return i; } } return -1; } private static final class ListenerContainer { @NonNull private final Executor mExecutor; @NonNull private final Consumer<IBinder> mConsumer; ListenerContainer(@NonNull Executor executor, @NonNull Consumer<IBinder> consumer) { mExecutor = executor; mConsumer = consumer; } public boolean isMatch(@NonNull Consumer<IBinder> consumer) { return mConsumer.equals(consumer); } public void accept(@NonNull IBinder activityToken) { mExecutor.execute(() -> mConsumer.accept(activityToken)); } } } libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +1 −8 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package androidx.window.extensions; import android.app.ActivityThread; import android.app.Application; import android.content.Context; import android.window.TaskFragmentOrganizer; import androidx.annotation.NonNull; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; Loading Loading @@ -81,13 +80,7 @@ public class WindowExtensionsImpl implements WindowExtensions { Context context = getApplication(); DeviceStateManagerFoldingFeatureProducer producer = getFoldingFeatureProducer(); // TODO(b/263263909) Use the organizer to tell if an Activity is embededed. // Need to improve our Dependency Injection and centralize the logic. TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(command -> { throw new RuntimeException("Not allowed!"); }); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, organizer, producer); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, producer); } } } Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +39 −43 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; import android.app.Activity; import android.app.ActivityClient; import android.app.ActivityThread; import android.app.Application; import android.app.WindowConfiguration; import android.content.ComponentCallbacks; Loading @@ -34,8 +34,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; import android.view.WindowManager; import android.window.TaskFragmentOrganizer; import android.util.Log; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; Loading @@ -51,7 +50,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** Loading @@ -63,7 +61,7 @@ import java.util.Set; * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead. */ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private static final String TAG = "SampleExtension"; private static final String TAG = WindowLayoutComponentImpl.class.getSimpleName(); private final Object mLock = new Object(); Loading @@ -85,16 +83,15 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private final Map<java.util.function.Consumer<WindowLayoutInfo>, Consumer<WindowLayoutInfo>> mJavaToExtConsumers = new ArrayMap<>(); private final TaskFragmentOrganizer mTaskFragmentOrganizer; private final RawConfigurationChangedListener mRawConfigurationChangedListener = new RawConfigurationChangedListener(); public WindowLayoutComponentImpl(@NonNull Context context, @NonNull TaskFragmentOrganizer taskFragmentOrganizer, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) { ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); mFoldingFeatureProducer = foldingFeatureProducer; mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); mTaskFragmentOrganizer = taskFragmentOrganizer; } /** Registers to listen to {@link CommonFoldingFeature} changes */ Loading @@ -117,6 +114,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { final Consumer<WindowLayoutInfo> extConsumer = consumer::accept; synchronized (mLock) { mJavaToExtConsumers.put(consumer, extConsumer); updateListenerRegistrations(); } addWindowLayoutInfoListener(activity, extConsumer); } Loading Loading @@ -170,6 +168,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { final Consumer<WindowLayoutInfo> extConsumer; synchronized (mLock) { extConsumer = mJavaToExtConsumers.remove(consumer); updateListenerRegistrations(); } if (extConsumer != null) { removeWindowLayoutInfoListener(extConsumer); Loading Loading @@ -199,6 +198,17 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } @GuardedBy("mLock") private void updateListenerRegistrations() { ActivityThread currentThread = ActivityThread.currentActivityThread(); if (mJavaToExtConsumers.isEmpty()) { currentThread.removeConfigurationChangedListener(mRawConfigurationChangedListener); } else { currentThread.addConfigurationChangedListener(Runnable::run, mRawConfigurationChangedListener); } } @GuardedBy("mLock") @NonNull private Set<Context> getContextsListeningForLayoutChanges() { Loading Loading @@ -344,25 +354,28 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { continue; } if (featureRect.left != 0 && featureRect.top != 0) { throw new IllegalArgumentException("Bounding rectangle must start at the top or " Log.wtf(TAG, "Bounding rectangle must start at the top or " + "left of the window. BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } if (featureRect.left == 0 && featureRect.width() != windowConfiguration.getBounds().width()) { throw new IllegalArgumentException("Horizontal FoldingFeature must have full width." Log.wtf(TAG, "Horizontal FoldingFeature must have full width." + " BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } if (featureRect.top == 0 && featureRect.height() != windowConfiguration.getBounds().height()) { throw new IllegalArgumentException("Vertical FoldingFeature must have full height." Log.wtf(TAG, "Vertical FoldingFeature must have full height." + " BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } features.add(new FoldingFeature(featureRect, baseFeature.getType(), state)); } Loading @@ -382,38 +395,11 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { // Display features are not supported on secondary displays. return false; } final int windowingMode; IBinder activityToken = context.getActivityToken(); if (activityToken != null) { final Configuration taskConfig = ActivityClient.getInstance().getTaskConfiguration( activityToken); if (taskConfig == null) { // If we cannot determine the task configuration for any reason, it is likely that // we won't be able to determine its position correctly as well. DisplayFeatures' // bounds in this case can't be computed correctly, so we should skip. return false; } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); final WindowManager windowManager = Objects.requireNonNull( context.getSystemService(WindowManager.class)); final Rect maxBounds = windowManager.getMaximumWindowMetrics().getBounds(); boolean isTaskExpanded = maxBounds.equals(taskBounds); /* * We need to proxy being in full screen because when a user enters PiP and exits PiP * the task windowingMode will report multi-window/pinned until the transition is * finished in WM Shell. * maxBounds == taskWindowBounds is a proxy check to verify the window is full screen */ return isTaskExpanded; } else { // TODO(b/242674941): use task windowing mode for window context that associates with // activity. windowingMode = context.getResources().getConfiguration().windowConfiguration .getWindowingMode(); } // It is recommended not to report any display features in multi-window mode, since it // won't be possible to synchronize the display feature positions with window movement. return !WindowConfiguration.inMultiWindowMode(windowingMode); // We do not report folding features for Activities in PiP because the bounds are // not updated fast enough and the window is too small for the UI to adapt. return context.getResources().getConfiguration().windowConfiguration .getWindowingMode() != WindowConfiguration.WINDOWING_MODE_PINNED; } @GuardedBy("mLock") Loading Loading @@ -442,6 +428,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } private final class RawConfigurationChangedListener implements java.util.function.Consumer<IBinder> { @Override public void accept(IBinder activityToken) { synchronized (mLock) { onDisplayFeaturesChangedIfListening(activityToken); } } } private final class ConfigurationChangeListener implements ComponentCallbacks { final IBinder mToken; Loading Loading
core/java/android/app/ActivityThread.java +23 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,7 @@ import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; /** * This manages the execution of the main thread in an Loading Loading @@ -370,6 +371,11 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("mAppThread") private int mLastProcessState = PROCESS_STATE_UNKNOWN; ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>(); @NonNull private final ConfigurationChangedListenerController mConfigurationChangedListenerController = new ConfigurationChangedListenerController(); private int mLastSessionId; // Holds the value of the last reported device ID value from the server for the top activity. int mLastReportedDeviceId; Loading Loading @@ -3540,6 +3546,21 @@ public final class ActivityThread extends ClientTransactionHandler return mConfigurationController.getConfiguration(); } /** * @hide */ public void addConfigurationChangedListener(Executor executor, Consumer<IBinder> consumer) { mConfigurationChangedListenerController.addListener(executor, consumer); } /** * @hide */ public void removeConfigurationChangedListener(Consumer<IBinder> consumer) { mConfigurationChangedListenerController.removeListener(consumer); } @Override public void updatePendingConfiguration(Configuration config) { final Configuration updatedConfig = Loading Loading @@ -6098,6 +6119,8 @@ public final class ActivityThread extends ClientTransactionHandler " did not call through to super.onConfigurationChanged()"); } } mConfigurationChangedListenerController .dispatchOnConfigurationChanged(activity.getActivityToken()); return configToReport; } Loading
core/java/android/app/ConfigurationChangedListenerController.java 0 → 100644 +116 −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 android.app; import android.annotation.NonNull; import android.os.IBinder; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.function.Consumer; /** * Manages listeners for unfiltered configuration changes. * @hide */ class ConfigurationChangedListenerController { private final Object mLock = new Object(); @GuardedBy("mLock") private final List<ListenerContainer> mListenerContainers = new ArrayList<>(); /** * Adds a listener to receive updates when they are dispatched. This only dispatches updates and * does not relay the last emitted value. If called with the same listener then this method does * not have any effect. * @param executor an executor that is used to dispatch the updates. * @param consumer a listener interested in receiving updates. */ void addListener(@NonNull Executor executor, @NonNull Consumer<IBinder> consumer) { synchronized (mLock) { if (indexOf(consumer) > -1) { return; } mListenerContainers.add(new ListenerContainer(executor, consumer)); } } /** * Removes the listener that was previously registered. If the listener was not registered this * method does not have any effect. */ void removeListener(@NonNull Consumer<IBinder> consumer) { synchronized (mLock) { final int index = indexOf(consumer); if (index > -1) { mListenerContainers.remove(index); } } } /** * Dispatches the update to all registered listeners * @param activityToken a token for the {@link Activity} that received a configuration update. */ void dispatchOnConfigurationChanged(@NonNull IBinder activityToken) { final List<ListenerContainer> consumers; synchronized (mLock) { consumers = new ArrayList<>(mListenerContainers); } for (int i = 0; i < consumers.size(); i++) { consumers.get(i).accept(activityToken); } } @GuardedBy("mLock") private int indexOf(Consumer<IBinder> consumer) { for (int i = 0; i < mListenerContainers.size(); i++) { if (mListenerContainers.get(i).isMatch(consumer)) { return i; } } return -1; } private static final class ListenerContainer { @NonNull private final Executor mExecutor; @NonNull private final Consumer<IBinder> mConsumer; ListenerContainer(@NonNull Executor executor, @NonNull Consumer<IBinder> consumer) { mExecutor = executor; mConsumer = consumer; } public boolean isMatch(@NonNull Consumer<IBinder> consumer) { return mConsumer.equals(consumer); } public void accept(@NonNull IBinder activityToken) { mExecutor.execute(() -> mConsumer.accept(activityToken)); } } }
libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +1 −8 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package androidx.window.extensions; import android.app.ActivityThread; import android.app.Application; import android.content.Context; import android.window.TaskFragmentOrganizer; import androidx.annotation.NonNull; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; Loading Loading @@ -81,13 +80,7 @@ public class WindowExtensionsImpl implements WindowExtensions { Context context = getApplication(); DeviceStateManagerFoldingFeatureProducer producer = getFoldingFeatureProducer(); // TODO(b/263263909) Use the organizer to tell if an Activity is embededed. // Need to improve our Dependency Injection and centralize the logic. TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(command -> { throw new RuntimeException("Not allowed!"); }); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, organizer, producer); mWindowLayoutComponent = new WindowLayoutComponentImpl(context, producer); } } } Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +39 −43 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; import android.app.Activity; import android.app.ActivityClient; import android.app.ActivityThread; import android.app.Application; import android.app.WindowConfiguration; import android.content.ComponentCallbacks; Loading @@ -34,8 +34,7 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; import android.util.ArrayMap; import android.view.WindowManager; import android.window.TaskFragmentOrganizer; import android.util.Log; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; Loading @@ -51,7 +50,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** Loading @@ -63,7 +61,7 @@ import java.util.Set; * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead. */ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private static final String TAG = "SampleExtension"; private static final String TAG = WindowLayoutComponentImpl.class.getSimpleName(); private final Object mLock = new Object(); Loading @@ -85,16 +83,15 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private final Map<java.util.function.Consumer<WindowLayoutInfo>, Consumer<WindowLayoutInfo>> mJavaToExtConsumers = new ArrayMap<>(); private final TaskFragmentOrganizer mTaskFragmentOrganizer; private final RawConfigurationChangedListener mRawConfigurationChangedListener = new RawConfigurationChangedListener(); public WindowLayoutComponentImpl(@NonNull Context context, @NonNull TaskFragmentOrganizer taskFragmentOrganizer, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) { ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); mFoldingFeatureProducer = foldingFeatureProducer; mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); mTaskFragmentOrganizer = taskFragmentOrganizer; } /** Registers to listen to {@link CommonFoldingFeature} changes */ Loading @@ -117,6 +114,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { final Consumer<WindowLayoutInfo> extConsumer = consumer::accept; synchronized (mLock) { mJavaToExtConsumers.put(consumer, extConsumer); updateListenerRegistrations(); } addWindowLayoutInfoListener(activity, extConsumer); } Loading Loading @@ -170,6 +168,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { final Consumer<WindowLayoutInfo> extConsumer; synchronized (mLock) { extConsumer = mJavaToExtConsumers.remove(consumer); updateListenerRegistrations(); } if (extConsumer != null) { removeWindowLayoutInfoListener(extConsumer); Loading Loading @@ -199,6 +198,17 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } @GuardedBy("mLock") private void updateListenerRegistrations() { ActivityThread currentThread = ActivityThread.currentActivityThread(); if (mJavaToExtConsumers.isEmpty()) { currentThread.removeConfigurationChangedListener(mRawConfigurationChangedListener); } else { currentThread.addConfigurationChangedListener(Runnable::run, mRawConfigurationChangedListener); } } @GuardedBy("mLock") @NonNull private Set<Context> getContextsListeningForLayoutChanges() { Loading Loading @@ -344,25 +354,28 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { continue; } if (featureRect.left != 0 && featureRect.top != 0) { throw new IllegalArgumentException("Bounding rectangle must start at the top or " Log.wtf(TAG, "Bounding rectangle must start at the top or " + "left of the window. BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } if (featureRect.left == 0 && featureRect.width() != windowConfiguration.getBounds().width()) { throw new IllegalArgumentException("Horizontal FoldingFeature must have full width." Log.wtf(TAG, "Horizontal FoldingFeature must have full width." + " BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } if (featureRect.top == 0 && featureRect.height() != windowConfiguration.getBounds().height()) { throw new IllegalArgumentException("Vertical FoldingFeature must have full height." Log.wtf(TAG, "Vertical FoldingFeature must have full height." + " BaseFeatureRect: " + baseFeature.getRect() + ", FeatureRect: " + featureRect + ", WindowConfiguration: " + windowConfiguration); continue; } features.add(new FoldingFeature(featureRect, baseFeature.getType(), state)); } Loading @@ -382,38 +395,11 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { // Display features are not supported on secondary displays. return false; } final int windowingMode; IBinder activityToken = context.getActivityToken(); if (activityToken != null) { final Configuration taskConfig = ActivityClient.getInstance().getTaskConfiguration( activityToken); if (taskConfig == null) { // If we cannot determine the task configuration for any reason, it is likely that // we won't be able to determine its position correctly as well. DisplayFeatures' // bounds in this case can't be computed correctly, so we should skip. return false; } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); final WindowManager windowManager = Objects.requireNonNull( context.getSystemService(WindowManager.class)); final Rect maxBounds = windowManager.getMaximumWindowMetrics().getBounds(); boolean isTaskExpanded = maxBounds.equals(taskBounds); /* * We need to proxy being in full screen because when a user enters PiP and exits PiP * the task windowingMode will report multi-window/pinned until the transition is * finished in WM Shell. * maxBounds == taskWindowBounds is a proxy check to verify the window is full screen */ return isTaskExpanded; } else { // TODO(b/242674941): use task windowing mode for window context that associates with // activity. windowingMode = context.getResources().getConfiguration().windowConfiguration .getWindowingMode(); } // It is recommended not to report any display features in multi-window mode, since it // won't be possible to synchronize the display feature positions with window movement. return !WindowConfiguration.inMultiWindowMode(windowingMode); // We do not report folding features for Activities in PiP because the bounds are // not updated fast enough and the window is too small for the UI to adapt. return context.getResources().getConfiguration().windowConfiguration .getWindowingMode() != WindowConfiguration.WINDOWING_MODE_PINNED; } @GuardedBy("mLock") Loading Loading @@ -442,6 +428,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } private final class RawConfigurationChangedListener implements java.util.function.Consumer<IBinder> { @Override public void accept(IBinder activityToken) { synchronized (mLock) { onDisplayFeaturesChangedIfListening(activityToken); } } } private final class ConfigurationChangeListener implements ComponentCallbacks { final IBinder mToken; Loading