Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +50 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package androidx.window.extensions.embedding; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; Loading Loading @@ -46,6 +47,7 @@ import android.app.Activity; import android.app.ActivityClient; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; import android.app.Instrumentation; import android.content.ComponentName; import android.content.Context; Loading @@ -70,12 +72,16 @@ import android.window.WindowContainerTransaction; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.common.CommonFoldingFeature; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import androidx.window.extensions.WindowExtensionsProvider; import androidx.window.extensions.layout.WindowLayoutComponentImpl; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -106,26 +112,65 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @GuardedBy("mLock") final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>(); // Callback to Jetpack to notify about changes to split states. @NonNull /** Callback to Jetpack to notify about changes to split states. */ @Nullable private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; final Object mLock = new Object(); private final ActivityStartMonitor mActivityStartMonitor; @NonNull final WindowLayoutComponentImpl mWindowLayoutComponent; public SplitController() { this((WindowLayoutComponentImpl) Objects.requireNonNull(WindowExtensionsProvider .getWindowExtensions().getWindowLayoutComponent())); } @VisibleForTesting SplitController(@NonNull WindowLayoutComponentImpl windowLayoutComponent) { final MainThreadExecutor executor = new MainThreadExecutor(); mHandler = executor.mHandler; mPresenter = new SplitPresenter(executor, this); ActivityThread activityThread = ActivityThread.currentActivityThread(); final ActivityThread activityThread = ActivityThread.currentActivityThread(); final Application application = activityThread.getApplication(); // Register a callback to be notified about activities being created. activityThread.getApplication().registerActivityLifecycleCallbacks( new LifecycleCallbacks()); application.registerActivityLifecycleCallbacks(new LifecycleCallbacks()); // Intercept activity starts to route activities to new containers if necessary. Instrumentation instrumentation = activityThread.getInstrumentation(); mActivityStartMonitor = new ActivityStartMonitor(); instrumentation.addMonitor(mActivityStartMonitor); mWindowLayoutComponent = windowLayoutComponent; mWindowLayoutComponent.addFoldingStateChangedCallback(new FoldingFeatureListener()); } private class FoldingFeatureListener implements Consumer<List<CommonFoldingFeature>> { @Override public void accept(List<CommonFoldingFeature> foldingFeatures) { synchronized (mLock) { final WindowContainerTransaction wct = new WindowContainerTransaction(); for (int i = 0; i < mTaskContainers.size(); i++) { final TaskContainer taskContainer = mTaskContainers.valueAt(i); if (!taskContainer.isVisible()) { continue; } if (taskContainer.getDisplayId() != DEFAULT_DISPLAY) { continue; } // TODO(b/238948678): Support reporting display features in all windowing modes. if (taskContainer.isInMultiWindow()) { continue; } if (taskContainer.isEmpty()) { continue; } updateContainersInTask(wct, taskContainer); updateAnimationOverride(taskContainer); } mPresenter.applyTransaction(wct); } } } /** Updates the embedding rules applied to future activity launches. */ Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +22 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import androidx.window.common.RawFoldingFeatureProducer; import androidx.window.util.DataProducer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; Loading Loading @@ -80,6 +81,11 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); } /** Registers to listen to {@link CommonFoldingFeature} changes */ public void addFoldingStateChangedCallback(Consumer<List<CommonFoldingFeature>> consumer) { mFoldingFeatureProducer.addDataChangedCallback(consumer); } /** * Adds a listener interested in receiving updates to {@link WindowLayoutInfo} * Loading Loading @@ -225,12 +231,23 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { */ private List<DisplayFeature> getDisplayFeatures( @NonNull @UiContext Context context, List<CommonFoldingFeature> storedFeatures) { List<DisplayFeature> features = new ArrayList<>(); if (!shouldReportDisplayFeatures(context)) { return Collections.emptyList(); } return getDisplayFeatures(context.getDisplayId(), context.getResources().getConfiguration().windowConfiguration, storedFeatures); } /** @see #getDisplayFeatures(Context, List) */ private List<DisplayFeature> getDisplayFeatures(int displayId, @NonNull WindowConfiguration windowConfiguration, List<CommonFoldingFeature> storedFeatures) { List<DisplayFeature> features = new ArrayList<>(); if (displayId != DEFAULT_DISPLAY) { return features; } int displayId = context.getDisplay().getDisplayId(); for (CommonFoldingFeature baseFeature : storedFeatures) { Integer state = convertToExtensionState(baseFeature.getState()); if (state == null) { Loading @@ -238,7 +255,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, featureRect); transformToWindowSpaceRect(context, featureRect); transformToWindowSpaceRect(windowConfiguration, featureRect); if (!isZero(featureRect)) { // TODO(b/228641877): Remove guarding when fixed. Loading @@ -263,6 +280,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { windowingMode = ActivityClient.getInstance().getTaskWindowingMode( context.getActivityToken()); } else { // TODO(b/242674941): use task windowing mode for window context that associates with // activity. windowingMode = context.getResources().getConfiguration().windowConfiguration .getWindowingMode(); } Loading libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java +13 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; Loading Loading @@ -89,13 +90,21 @@ public final class ExtensionHelper { /** Transforms rectangle from absolute coordinate space to the window coordinate space. */ public static void transformToWindowSpaceRect(@NonNull @UiContext Context context, Rect inOutRect) { Rect windowRect = getWindowBounds(context); if (!Rect.intersects(inOutRect, windowRect)) { transformToWindowSpaceRect(getWindowBounds(context), inOutRect); } /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */ public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration, Rect inOutRect) { transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect); } private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) { if (!inOutRect.intersect(bounds)) { inOutRect.setEmpty(); return; } inOutRect.intersect(windowRect); inOutRect.offset(-windowRect.left, -windowRect.top); inOutRect.offset(-bounds.left, -bounds.top); } /** Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +50 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package androidx.window.extensions.embedding; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO; import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE; Loading Loading @@ -46,6 +47,7 @@ import android.app.Activity; import android.app.ActivityClient; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; import android.app.Instrumentation; import android.content.ComponentName; import android.content.Context; Loading @@ -70,12 +72,16 @@ import android.window.WindowContainerTransaction; import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.window.common.CommonFoldingFeature; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import androidx.window.extensions.WindowExtensionsProvider; import androidx.window.extensions.layout.WindowLayoutComponentImpl; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; Loading Loading @@ -106,26 +112,65 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @GuardedBy("mLock") final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>(); // Callback to Jetpack to notify about changes to split states. @NonNull /** Callback to Jetpack to notify about changes to split states. */ @Nullable private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; final Object mLock = new Object(); private final ActivityStartMonitor mActivityStartMonitor; @NonNull final WindowLayoutComponentImpl mWindowLayoutComponent; public SplitController() { this((WindowLayoutComponentImpl) Objects.requireNonNull(WindowExtensionsProvider .getWindowExtensions().getWindowLayoutComponent())); } @VisibleForTesting SplitController(@NonNull WindowLayoutComponentImpl windowLayoutComponent) { final MainThreadExecutor executor = new MainThreadExecutor(); mHandler = executor.mHandler; mPresenter = new SplitPresenter(executor, this); ActivityThread activityThread = ActivityThread.currentActivityThread(); final ActivityThread activityThread = ActivityThread.currentActivityThread(); final Application application = activityThread.getApplication(); // Register a callback to be notified about activities being created. activityThread.getApplication().registerActivityLifecycleCallbacks( new LifecycleCallbacks()); application.registerActivityLifecycleCallbacks(new LifecycleCallbacks()); // Intercept activity starts to route activities to new containers if necessary. Instrumentation instrumentation = activityThread.getInstrumentation(); mActivityStartMonitor = new ActivityStartMonitor(); instrumentation.addMonitor(mActivityStartMonitor); mWindowLayoutComponent = windowLayoutComponent; mWindowLayoutComponent.addFoldingStateChangedCallback(new FoldingFeatureListener()); } private class FoldingFeatureListener implements Consumer<List<CommonFoldingFeature>> { @Override public void accept(List<CommonFoldingFeature> foldingFeatures) { synchronized (mLock) { final WindowContainerTransaction wct = new WindowContainerTransaction(); for (int i = 0; i < mTaskContainers.size(); i++) { final TaskContainer taskContainer = mTaskContainers.valueAt(i); if (!taskContainer.isVisible()) { continue; } if (taskContainer.getDisplayId() != DEFAULT_DISPLAY) { continue; } // TODO(b/238948678): Support reporting display features in all windowing modes. if (taskContainer.isInMultiWindow()) { continue; } if (taskContainer.isEmpty()) { continue; } updateContainersInTask(wct, taskContainer); updateAnimationOverride(taskContainer); } mPresenter.applyTransaction(wct); } } } /** Updates the embedding rules applied to future activity launches. */ Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +22 −3 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import androidx.window.common.RawFoldingFeatureProducer; import androidx.window.util.DataProducer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; Loading Loading @@ -80,6 +81,11 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); } /** Registers to listen to {@link CommonFoldingFeature} changes */ public void addFoldingStateChangedCallback(Consumer<List<CommonFoldingFeature>> consumer) { mFoldingFeatureProducer.addDataChangedCallback(consumer); } /** * Adds a listener interested in receiving updates to {@link WindowLayoutInfo} * Loading Loading @@ -225,12 +231,23 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { */ private List<DisplayFeature> getDisplayFeatures( @NonNull @UiContext Context context, List<CommonFoldingFeature> storedFeatures) { List<DisplayFeature> features = new ArrayList<>(); if (!shouldReportDisplayFeatures(context)) { return Collections.emptyList(); } return getDisplayFeatures(context.getDisplayId(), context.getResources().getConfiguration().windowConfiguration, storedFeatures); } /** @see #getDisplayFeatures(Context, List) */ private List<DisplayFeature> getDisplayFeatures(int displayId, @NonNull WindowConfiguration windowConfiguration, List<CommonFoldingFeature> storedFeatures) { List<DisplayFeature> features = new ArrayList<>(); if (displayId != DEFAULT_DISPLAY) { return features; } int displayId = context.getDisplay().getDisplayId(); for (CommonFoldingFeature baseFeature : storedFeatures) { Integer state = convertToExtensionState(baseFeature.getState()); if (state == null) { Loading @@ -238,7 +255,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } Rect featureRect = baseFeature.getRect(); rotateRectToDisplayRotation(displayId, featureRect); transformToWindowSpaceRect(context, featureRect); transformToWindowSpaceRect(windowConfiguration, featureRect); if (!isZero(featureRect)) { // TODO(b/228641877): Remove guarding when fixed. Loading @@ -263,6 +280,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { windowingMode = ActivityClient.getInstance().getTaskWindowingMode( context.getActivityToken()); } else { // TODO(b/242674941): use task windowing mode for window context that associates with // activity. windowingMode = context.getResources().getConfiguration().windowConfiguration .getWindowingMode(); } Loading
libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java +13 −4 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; Loading Loading @@ -89,13 +90,21 @@ public final class ExtensionHelper { /** Transforms rectangle from absolute coordinate space to the window coordinate space. */ public static void transformToWindowSpaceRect(@NonNull @UiContext Context context, Rect inOutRect) { Rect windowRect = getWindowBounds(context); if (!Rect.intersects(inOutRect, windowRect)) { transformToWindowSpaceRect(getWindowBounds(context), inOutRect); } /** @see ExtensionHelper#transformToWindowSpaceRect(Context, Rect) */ public static void transformToWindowSpaceRect(@NonNull WindowConfiguration windowConfiguration, Rect inOutRect) { transformToWindowSpaceRect(windowConfiguration.getBounds(), inOutRect); } private static void transformToWindowSpaceRect(@NonNull Rect bounds, @NonNull Rect inOutRect) { if (!inOutRect.intersect(bounds)) { inOutRect.setEmpty(); return; } inOutRect.intersect(windowRect); inOutRect.offset(-windowRect.left, -windowRect.top); inOutRect.offset(-bounds.left, -bounds.top); } /** Loading