diff options
Diffstat (limited to 'libs')
24 files changed, 505 insertions, 120 deletions
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 0f4521951e3d..c7c94246b96a 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -49,6 +49,7 @@ filegroup { "src/com/android/wm/shell/animation/Interpolators.java", "src/com/android/wm/shell/pip/PipContentOverlay.java", "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java", + "src/com/android/wm/shell/draganddrop/DragAndDropConstants.java", ], path: "src", } diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background.xml deleted file mode 100644 index 0d8811357c05..000000000000 --- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 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. - --> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <solid android:color="@color/letterbox_education_accent_primary"/> - <corners android:radius="12dp"/> -</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml index 42572d64b96f..a2699681e656 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml @@ -14,7 +14,30 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/letterbox_education_dismiss_button_background_ripple"> - <item android:drawable="@drawable/letterbox_education_dismiss_button_background"/> -</ripple>
\ No newline at end of file +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetTop="@dimen/letterbox_education_dialog_vertical_inset" + android:insetBottom="@dimen/letterbox_education_dialog_vertical_inset"> + <ripple android:color="@color/letterbox_education_dismiss_button_background_ripple"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/letterbox_education_dialog_button_radius"/> + <solid android:color="@android:color/white"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/letterbox_education_accent_primary"/> + <corners android:radius="@dimen/letterbox_education_dialog_button_radius"/> + <padding android:left="@dimen/letterbox_education_dialog_horizontal_padding" + android:top="@dimen/letterbox_education_dialog_vertical_padding" + android:right="@dimen/letterbox_education_dialog_horizontal_padding" + android:bottom="@dimen/letterbox_education_dialog_vertical_padding"/> + </shape> + </item> + </ripple> +</inset> diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml deleted file mode 100644 index 60f3cfe6dde6..000000000000 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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. - --> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:shape="rectangle"> - <solid android:color="?androidprv:attr/colorAccentPrimaryVariant"/> - <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> -</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml index ef97ea19e993..1f125148775d 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml @@ -14,7 +14,31 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/letterbox_restart_button_background_ripple"> - <item android:drawable="@drawable/letterbox_restart_button_background"/> -</ripple>
\ No newline at end of file +<inset xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:insetTop="@dimen/letterbox_restart_dialog_vertical_inset" + android:insetBottom="@dimen/letterbox_restart_dialog_vertical_inset"> + <ripple android:color="@color/letterbox_restart_dismiss_button_background_ripple"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> + <solid android:color="@android:color/white"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="?androidprv:attr/colorAccentPrimaryVariant"/> + <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> + <padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding" + android:top="@dimen/letterbox_restart_dialog_vertical_padding" + android:right="@dimen/letterbox_restart_dialog_horizontal_padding" + android:bottom="@dimen/letterbox_restart_dialog_vertical_padding"/> + </shape> + </item> + </ripple> +</inset>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml deleted file mode 100644 index af89d41ee6b5..000000000000 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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. - --> -<shape xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:shape="rectangle"> - <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant" android:width="1dp"/> - <solid android:color="?androidprv:attr/colorSurface" /> - <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> -</shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml index e32aefca78ac..3aa0981e45aa 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml @@ -14,7 +14,33 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/letterbox_restart_dismiss_button_background_ripple"> - <item android:drawable="@drawable/letterbox_restart_dismiss_button_background"/> -</ripple>
\ No newline at end of file +<inset xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:insetTop="@dimen/letterbox_restart_dialog_vertical_inset" + android:insetBottom="@dimen/letterbox_restart_dialog_vertical_inset"> + <ripple android:color="@color/letterbox_restart_dismiss_button_background_ripple"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> + <solid android:color="@android:color/white"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant" + android:width="1dp"/> + <solid android:color="?androidprv:attr/colorSurface"/> + <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> + <padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding" + android:top="@dimen/letterbox_restart_dialog_vertical_padding" + android:right="@dimen/letterbox_restart_dialog_horizontal_padding" + android:bottom="@dimen/letterbox_restart_dialog_vertical_padding"/> + </shape> + </item> + </ripple> +</inset>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 6f31d0674246..336c156e831a 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -273,6 +273,18 @@ <!-- The space between two actions in the letterbox education dialog --> <dimen name="letterbox_education_dialog_space_between_actions">24dp</dimen> + <!-- The corner radius of the buttons in the letterbox education dialog --> + <dimen name="letterbox_education_dialog_button_radius">12dp</dimen> + + <!-- The horizontal padding for the buttons in the letterbox education dialog --> + <dimen name="letterbox_education_dialog_horizontal_padding">16dp</dimen> + + <!-- The vertical padding for the buttons in the letterbox education dialog --> + <dimen name="letterbox_education_dialog_vertical_padding">8dp</dimen> + + <!-- The insets for the buttons in the letterbox education dialog --> + <dimen name="letterbox_education_dialog_vertical_inset">6dp</dimen> + <!-- The margin between the dialog container and its parent. --> <dimen name="letterbox_restart_dialog_margin">24dp</dimen> @@ -306,6 +318,15 @@ <!-- The corner radius of the buttons in the restart dialog --> <dimen name="letterbox_restart_dialog_button_radius">18dp</dimen> + <!-- The insets for the buttons in the letterbox restart dialog --> + <dimen name="letterbox_restart_dialog_vertical_inset">6dp</dimen> + + <!-- The horizontal padding for the buttons in the letterbox restart dialog --> + <dimen name="letterbox_restart_dialog_horizontal_padding">16dp</dimen> + + <!-- The vertical padding for the buttons in the letterbox restart dialog --> + <dimen name="letterbox_restart_dialog_vertical_padding">8dp</dimen> + <!-- The width of the brand image on staring surface. --> <dimen name="starting_surface_brand_image_width">200dp</dimen> @@ -331,30 +352,6 @@ --> <dimen name="overridable_minimal_size_pip_resizable_task">48dp</dimen> - <!-- The size of the drag handle / menu shown along with a floating task. --> - <dimen name="floating_task_menu_size">32dp</dimen> - - <!-- The size of menu items in the floating task menu. --> - <dimen name="floating_task_menu_item_size">24dp</dimen> - - <!-- The horizontal margin of menu items in the floating task menu. --> - <dimen name="floating_task_menu_item_padding">5dp</dimen> - - <!-- The width of visible floating view region when stashed. --> - <dimen name="floating_task_stash_offset">32dp</dimen> - - <!-- The amount of elevation for a floating task. --> - <dimen name="floating_task_elevation">8dp</dimen> - - <!-- The amount of padding around the bottom and top of the task. --> - <dimen name="floating_task_vertical_padding">8dp</dimen> - - <!-- The normal size of the dismiss target. --> - <dimen name="floating_task_dismiss_circle_size">150dp</dimen> - - <!-- The smaller size of the dismiss target (shrinks when something is in the target). --> - <dimen name="floating_dismiss_circle_small">120dp</dimen> - <!-- The thickness of shadows of a window that has focus in DIP. --> <dimen name="freeform_decor_shadow_focused_thickness">20dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java index 88525aabe53b..e2012b4e36dc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java @@ -16,6 +16,8 @@ package com.android.wm.shell; +import android.os.Build; + import com.android.wm.shell.protolog.ShellProtoLogImpl; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; @@ -41,6 +43,9 @@ public class ProtoLogController implements ShellCommandHandler.ShellCommandActio void onInit() { mShellCommandHandler.addCommandCallback("protolog", this, this); + if (Build.IS_DEBUGGABLE) { + mShellProtoLog.startProtoLog(null /* PrintWriter */); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java new file mode 100644 index 000000000000..22587f4c6456 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DevicePostureController.java @@ -0,0 +1,147 @@ +/* + * 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.common; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; +import android.util.SparseIntArray; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.sysui.ShellInit; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Wrapper class to track the device posture change on Fold-ables. + * See also <a + * href="https://developer.android.com/guide/topics/large-screens/learn-about-foldables + * #foldable_postures">Foldable states and postures</a> for reference. + * + * Note that most of the implementation here inherits from + * {@link com.android.systemui.statusbar.policy.DevicePostureController}. + */ +public class DevicePostureController { + @IntDef(prefix = {"DEVICE_POSTURE_"}, value = { + DEVICE_POSTURE_UNKNOWN, + DEVICE_POSTURE_CLOSED, + DEVICE_POSTURE_HALF_OPENED, + DEVICE_POSTURE_OPENED, + DEVICE_POSTURE_FLIPPED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DevicePostureInt {} + + // NOTE: These constants **must** match those defined for Jetpack Sidecar. This is because we + // use the Device State -> Jetpack Posture map to translate between the two. + public static final int DEVICE_POSTURE_UNKNOWN = 0; + public static final int DEVICE_POSTURE_CLOSED = 1; + public static final int DEVICE_POSTURE_HALF_OPENED = 2; + public static final int DEVICE_POSTURE_OPENED = 3; + public static final int DEVICE_POSTURE_FLIPPED = 4; + + private final Context mContext; + private final ShellExecutor mMainExecutor; + private final List<OnDevicePostureChangedListener> mListeners = new ArrayList<>(); + private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray(); + + private int mDevicePosture = DEVICE_POSTURE_UNKNOWN; + + public DevicePostureController( + Context context, ShellInit shellInit, ShellExecutor mainExecutor) { + mContext = context; + mMainExecutor = mainExecutor; + shellInit.addInitCallback(this::onInit, this); + } + + private void onInit() { + // Most of this is borrowed from WindowManager/Jetpack/DeviceStateManagerPostureProducer. + // Using the sidecar/extension libraries directly brings in a new dependency that it'd be + // good to avoid (along with the fact that sidecar is deprecated, and extensions isn't fully + // ready yet), and we'd have to make our own layer over the sidecar library anyway to easily + // allow the implementation to change, so it was easier to just interface with + // DeviceStateManager directly. + String[] deviceStatePosturePairs = mContext.getResources() + .getStringArray(R.array.config_device_state_postures); + for (String deviceStatePosturePair : deviceStatePosturePairs) { + String[] deviceStatePostureMapping = deviceStatePosturePair.split(":"); + if (deviceStatePostureMapping.length != 2) { + continue; + } + + int deviceState; + int posture; + try { + deviceState = Integer.parseInt(deviceStatePostureMapping[0]); + posture = Integer.parseInt(deviceStatePostureMapping[1]); + } catch (NumberFormatException e) { + continue; + } + + mDeviceStateToPostureMap.put(deviceState, posture); + } + + final DeviceStateManager deviceStateManager = mContext.getSystemService( + DeviceStateManager.class); + if (deviceStateManager != null) { + deviceStateManager.registerCallback(mMainExecutor, state -> onDevicePostureChanged( + mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN))); + } + } + + @VisibleForTesting + void onDevicePostureChanged(int devicePosture) { + if (devicePosture == mDevicePosture) return; + mDevicePosture = devicePosture; + mListeners.forEach(l -> l.onDevicePostureChanged(mDevicePosture)); + } + + /** + * Register {@link OnDevicePostureChangedListener} for device posture changes. + * The listener will receive callback with current device posture upon registration. + */ + public void registerOnDevicePostureChangedListener( + @NonNull OnDevicePostureChangedListener listener) { + if (mListeners.contains(listener)) return; + mListeners.add(listener); + listener.onDevicePostureChanged(mDevicePosture); + } + + /** + * Unregister {@link OnDevicePostureChangedListener} for device posture changes. + */ + public void unregisterOnDevicePostureChangedListener( + @NonNull OnDevicePostureChangedListener listener) { + mListeners.remove(listener); + } + + /** + * Listener interface for device posture change. + */ + public interface OnDevicePostureChangedListener { + /** + * Callback when device posture changes. + * See {@link DevicePostureInt} for callback values. + */ + void onDevicePostureChanged(@DevicePostureInt int posture); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 25c430c27457..72dc771ee08c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -41,6 +41,7 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.back.BackAnimationController; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.common.DevicePostureController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; @@ -160,6 +161,16 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides + static DevicePostureController provideDevicePostureController( + Context context, + ShellInit shellInit, + @ShellMainThread ShellExecutor mainExecutor + ) { + return new DevicePostureController(context, shellInit, mainExecutor); + } + + @WMSingleton + @Provides static DragAndDropController provideDragAndDropController(Context context, ShellInit shellInit, ShellController shellController, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index efc7d1ff0bb9..1239cdc5b606 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -558,16 +558,18 @@ public abstract class WMShellModule { static FullscreenUnfoldTaskAnimator provideFullscreenUnfoldTaskAnimator( Context context, UnfoldBackgroundController unfoldBackgroundController, + ShellController shellController, DisplayInsetsController displayInsetsController ) { return new FullscreenUnfoldTaskAnimator(context, unfoldBackgroundController, - displayInsetsController); + shellController, displayInsetsController); } @Provides static SplitTaskUnfoldAnimator provideSplitTaskUnfoldAnimatorBase( Context context, UnfoldBackgroundController backgroundController, + ShellController shellController, @ShellMainThread ShellExecutor executor, Lazy<Optional<SplitScreenController>> splitScreenOptional, DisplayInsetsController displayInsetsController @@ -577,7 +579,7 @@ public abstract class WMShellModule { // controller directly once we refactor ShellTaskOrganizer to not depend on the unfold // animation controller directly. return new SplitTaskUnfoldAnimator(context, executor, splitScreenOptional, - backgroundController, displayInsetsController); + shellController, backgroundController, displayInsetsController); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java new file mode 100644 index 000000000000..20da54efd286 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropConstants.java @@ -0,0 +1,27 @@ +/* + * 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.draganddrop; + +/** Constants that can be used by both Shell and other users of the library, e.g. Launcher */ +public class DragAndDropConstants { + + /** + * An Intent extra that Launcher can use to specify a region of the screen where Shell should + * ignore drag events. + */ + public static final String EXTRA_DISALLOW_HIT_REGION = "DISALLOW_HIT_REGION"; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index d93a9012c8f1..df94b414c092 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -34,6 +34,7 @@ import static android.content.Intent.EXTRA_USER; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; +import static com.android.wm.shell.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT; @@ -53,6 +54,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.LauncherApps; import android.graphics.Insets; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; @@ -86,6 +88,7 @@ public class DragAndDropPolicy { private final Starter mStarter; private final SplitScreenController mSplitScreen; private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>(); + private final RectF mDisallowHitRegion = new RectF(); private InstanceId mLoggerSessionId; private DragSession mSession; @@ -111,6 +114,12 @@ public class DragAndDropPolicy { mSession = new DragSession(mActivityTaskManager, displayLayout, data); // TODO(b/169894807): Also update the session data with task stack changes mSession.update(); + RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION); + if (disallowHitRegion == null) { + mDisallowHitRegion.setEmpty(); + } else { + mDisallowHitRegion.set(disallowHitRegion); + } } /** @@ -218,6 +227,9 @@ public class DragAndDropPolicy { */ @Nullable Target getTargetAtLocation(int x, int y) { + if (mDisallowHitRegion.contains(x, y)) { + return null; + } for (int i = mTargets.size() - 1; i >= 0; i--) { DragAndDropPolicy.Target t = mTargets.get(i); if (t.hitRegion.contains(x, y)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 3ade1ed9392f..44fd8eec4d06 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -118,7 +118,7 @@ public class DragLayout extends LinearLayout { @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout()); + mInsets = insets.getInsets(Type.tappableElement() | Type.displayCutout()); recomputeDropTargets(); final int orientation = getResources().getConfiguration().orientation; @@ -369,7 +369,9 @@ public class DragLayout extends LinearLayout { // Start animating the drop UI out with the drag surface hide(event, dropCompleteCallback); - hideDragSurface(dragSurface); + if (handledDrop) { + hideDragSurface(dragSurface); + } return handledDrop; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index d9ac76e833d8..23f73f614294 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -209,7 +209,7 @@ public class PipAnimationController { /** * Quietly cancel the animator by removing the listeners first. */ - static void quietCancel(@NonNull ValueAnimator animator) { + public static void quietCancel(@NonNull ValueAnimator animator) { animator.removeAllUpdateListeners(); animator.removeAllListeners(); animator.cancel(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index ec34f73126fb..fa3efeb51bd0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -715,6 +715,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) { if (!mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) { + PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null && animator.isRunning()) { + // cancel any running animator, as it is using stale display layout information + PipAnimationController.quietCancel(animator); + } onDisplayChangedUncheck(layout, saveRestoreSnapFraction); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java index 93ffb3dc8115..c59c42dadb9d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java @@ -31,8 +31,7 @@ import java.io.PrintWriter; */ public class ShellProtoLogImpl extends BaseProtoLogImpl { private static final String TAG = "ProtoLogImpl"; - private static final int BUFFER_CAPACITY = 1024 * 1024; - // TODO: find a proper location to save the protolog message file + private static final int BUFFER_CAPACITY = 128 * 1024; private static final String LOG_FILENAME = "/data/misc/wmtrace/shell_log.winscope"; private static final String VIEWER_CONFIG_FILENAME = "/system_ext/etc/wmshell.protolog.json.gz"; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 0c3eaf0b904f..746bfad56ea8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -499,6 +499,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, break; } } + } else if (mSideStage.getChildCount() != 0) { + // There are chances the entering app transition got canceled by performing + // rotation transition. Checks if there is any child task existed in split + // screen before fallback to cancel entering flow. + openingToSide = true; } if (isEnteringSplit && !openingToSide) { @@ -515,7 +520,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } - if (!isEnteringSplit && openingToSide) { + if (!isEnteringSplit && apps != null) { final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictNonOpeningChildTasks(position, apps, evictWct); mSyncQueue.queue(evictWct); @@ -598,6 +603,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, break; } } + } else if (mSideStage.getChildCount() != 0) { + // There are chances the entering app transition got canceled by performing + // rotation transition. Checks if there is any child task existed in split + // screen before fallback to cancel entering flow. + openingToSide = true; } if (isEnteringSplit && !openingToSide && apps != null) { @@ -624,7 +634,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } - if (!isEnteringSplit && openingToSide) { + if (!isEnteringSplit && apps != null) { final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictNonOpeningChildTasks(position, apps, evictWct); mSyncQueue.queue(evictWct); @@ -1685,9 +1695,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } mSyncQueue.queue(wct); - mSyncQueue.runInSync(t -> { - setDividerVisibility(mainStageVisible, t); - }); + setDividerVisibility(mainStageVisible, null); } private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) { @@ -1769,6 +1777,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onAnimationEnd(Animator animation) { + if (dividerLeash != null && dividerLeash.isValid()) { + transaction.setAlpha(dividerLeash, 1); + transaction.apply(); + } mTransactionPool.release(transaction); mDividerFadeInAnimator = null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java index eab82f00e962..e0f3fcd932c2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/FullscreenUnfoldTaskAnimator.java @@ -26,8 +26,10 @@ import android.animation.TypeEvaluator; import android.annotation.NonNull; import android.app.TaskInfo; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.Trace; import android.util.SparseArray; import android.view.InsetsSource; import android.view.InsetsState; @@ -36,6 +38,8 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.wm.shell.common.DisplayInsetsController; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.UnfoldBackgroundController; @@ -51,7 +55,7 @@ import com.android.wm.shell.unfold.UnfoldBackgroundController; * instances of FullscreenUnfoldTaskAnimator. */ public class FullscreenUnfoldTaskAnimator implements UnfoldTaskAnimator, - DisplayInsetsController.OnInsetsChangedListener { + DisplayInsetsController.OnInsetsChangedListener, ConfigurationChangeListener { private static final float[] FLOAT_9 = new float[9]; private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect()); @@ -63,17 +67,21 @@ public class FullscreenUnfoldTaskAnimator implements UnfoldTaskAnimator, private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>(); private final int mExpandedTaskBarHeight; - private final float mWindowCornerRadiusPx; private final DisplayInsetsController mDisplayInsetsController; private final UnfoldBackgroundController mBackgroundController; + private final Context mContext; + private final ShellController mShellController; private InsetsSource mTaskbarInsetsSource; + private float mWindowCornerRadiusPx; public FullscreenUnfoldTaskAnimator(Context context, @NonNull UnfoldBackgroundController backgroundController, - DisplayInsetsController displayInsetsController) { + ShellController shellController, DisplayInsetsController displayInsetsController) { + mContext = context; mDisplayInsetsController = displayInsetsController; mBackgroundController = backgroundController; + mShellController = shellController; mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.taskbar_frame_height); mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(context); @@ -81,6 +89,14 @@ public class FullscreenUnfoldTaskAnimator implements UnfoldTaskAnimator, public void init() { mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this); + mShellController.addConfigurationChangeListener(this); + } + + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + Trace.beginSection("FullscreenUnfoldTaskAnimator#onConfigurationChanged"); + mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(mContext); + Trace.endSection(); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java index 6e10ebe94c5d..addd0a6012c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java @@ -28,8 +28,10 @@ import android.animation.RectEvaluator; import android.animation.TypeEvaluator; import android.app.TaskInfo; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.Rect; +import android.os.Trace; import android.util.SparseArray; import android.view.InsetsSource; import android.view.InsetsState; @@ -42,6 +44,8 @@ import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.UnfoldBackgroundController; @@ -62,16 +66,18 @@ import dagger.Lazy; * They use independent instances of SplitTaskUnfoldAnimator. */ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator, - DisplayInsetsController.OnInsetsChangedListener, SplitScreenListener { + DisplayInsetsController.OnInsetsChangedListener, SplitScreenListener, + ConfigurationChangeListener { private static final TypeEvaluator<Rect> RECT_EVALUATOR = new RectEvaluator(new Rect()); private static final float CROPPING_START_MARGIN_FRACTION = 0.05f; + private final Context mContext; private final Executor mExecutor; private final DisplayInsetsController mDisplayInsetsController; private final SparseArray<AnimationContext> mAnimationContextByTaskId = new SparseArray<>(); private final int mExpandedTaskBarHeight; - private final float mWindowCornerRadiusPx; + private final ShellController mShellController; private final Lazy<Optional<SplitScreenController>> mSplitScreenController; private final UnfoldBackgroundController mUnfoldBackgroundController; @@ -79,6 +85,7 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator, private final Rect mSideStageBounds = new Rect(); private final Rect mRootStageBounds = new Rect(); + private float mWindowCornerRadiusPx; private InsetsSource mTaskbarInsetsSource; @SplitPosition @@ -88,10 +95,12 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator, public SplitTaskUnfoldAnimator(Context context, Executor executor, Lazy<Optional<SplitScreenController>> splitScreenController, - UnfoldBackgroundController unfoldBackgroundController, + ShellController shellController, UnfoldBackgroundController unfoldBackgroundController, DisplayInsetsController displayInsetsController) { mDisplayInsetsController = displayInsetsController; mExecutor = executor; + mContext = context; + mShellController = shellController; mUnfoldBackgroundController = unfoldBackgroundController; mSplitScreenController = splitScreenController; mExpandedTaskBarHeight = context.getResources().getDimensionPixelSize( @@ -103,6 +112,14 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator, @Override public void init() { mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY, this); + mShellController.addConfigurationChangeListener(this); + } + + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + Trace.beginSection("SplitTaskUnfoldAnimator#onConfigurationChanged"); + mWindowCornerRadiusPx = ScreenDecorationsUtils.getWindowCornerRadius(mContext); + Trace.endSection(); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 245cc8d7ee87..0779f1d72551 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -213,6 +213,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); handle.setOnTouchListener(mOnCaptionTouchListener); handle.setOnClickListener(mOnCaptionButtonClickListener); + if (DesktopModeStatus.isProto1Enabled()) { + final View back = caption.findViewById(R.id.back_button); + back.setOnClickListener(mOnCaptionButtonClickListener); + final View close = caption.findViewById(R.id.close_window); + close.setOnClickListener(mOnCaptionButtonClickListener); + } updateButtonVisibility(); } @@ -319,6 +325,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final View handle = caption.findViewById(R.id.caption_handle); final Drawable handleBackground = handle.getBackground(); handleBackground.setTintList(buttonTintColor); + if (DesktopModeStatus.isProto1Enabled()) { + final View back = caption.findViewById(R.id.back_button); + final Drawable backBackground = back.getBackground(); + backBackground.setTintList(buttonTintColor); + final View close = caption.findViewById(R.id.close_window); + final Drawable closeBackground = close.getBackground(); + closeBackground.setTintList(buttonTintColor); + } } private void closeDragResizeListener() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index 7d954ad92285..81c4176b0f39 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -215,6 +215,7 @@ class DragResizeInputListener implements AutoCloseable { @Override public void close() { + mInputEventReceiver.dispose(); mInputChannel.dispose(); try { mWindowSession.remove(mFakeWindow); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java new file mode 100644 index 000000000000..f8ee300e411c --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java @@ -0,0 +1,109 @@ +/* + * 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.common; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.content.Context; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.sysui.ShellInit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class DevicePostureControllerTest { + @Mock + private Context mContext; + + @Mock + private ShellInit mShellInit; + + @Mock + private ShellExecutor mMainExecutor; + + @Captor + private ArgumentCaptor<Integer> mDevicePostureCaptor; + + @Mock + private DevicePostureController.OnDevicePostureChangedListener mOnDevicePostureChangedListener; + + private DevicePostureController mDevicePostureController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mDevicePostureController = new DevicePostureController(mContext, mShellInit, mMainExecutor); + } + + @Test + public void instantiateController_addInitCallback() { + verify(mShellInit, times(1)).addInitCallback(any(), eq(mDevicePostureController)); + } + + @Test + public void registerOnDevicePostureChangedListener_callbackCurrentPosture() { + mDevicePostureController.registerOnDevicePostureChangedListener( + mOnDevicePostureChangedListener); + verify(mOnDevicePostureChangedListener, times(1)) + .onDevicePostureChanged(anyInt()); + } + + @Test + public void onDevicePostureChanged_differentPosture_callbackListener() { + mDevicePostureController.registerOnDevicePostureChangedListener( + mOnDevicePostureChangedListener); + verify(mOnDevicePostureChangedListener).onDevicePostureChanged( + mDevicePostureCaptor.capture()); + clearInvocations(mOnDevicePostureChangedListener); + + int differentDevicePosture = mDevicePostureCaptor.getValue() + 1; + mDevicePostureController.onDevicePostureChanged(differentDevicePosture); + + verify(mOnDevicePostureChangedListener, times(1)) + .onDevicePostureChanged(differentDevicePosture); + } + + @Test + public void onDevicePostureChanged_samePosture_doesNotCallbackListener() { + mDevicePostureController.registerOnDevicePostureChangedListener( + mOnDevicePostureChangedListener); + verify(mOnDevicePostureChangedListener).onDevicePostureChanged( + mDevicePostureCaptor.capture()); + clearInvocations(mOnDevicePostureChangedListener); + + int sameDevicePosture = mDevicePostureCaptor.getValue(); + mDevicePostureController.onDevicePostureChanged(sameDevicePosture); + + verifyZeroInteractions(mOnDevicePostureChangedListener); + } +} |