diff options
20 files changed, 460 insertions, 218 deletions
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 4e578615f30f..c1c15d12dee1 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -81,7 +81,6 @@ <dimen name="fab_margin">24dp</dimen> <dimen name="navigation_key_width">128dp</dimen> - <dimen name="navigation_key_padding">25dp</dimen> <!-- Keyboard shortcuts helper --> <dimen name="ksh_layout_width">488dp</dimen> diff --git a/packages/SystemUI/res/values-sw900dp/dimens.xml b/packages/SystemUI/res/values-sw900dp/dimens.xml index 2cff97692d9d..ebae8c4bfa4c 100644 --- a/packages/SystemUI/res/values-sw900dp/dimens.xml +++ b/packages/SystemUI/res/values-sw900dp/dimens.xml @@ -21,11 +21,4 @@ <dimen name="navigation_side_padding">@dimen/button_size</dimen> <dimen name="navigation_key_width">@dimen/button_size</dimen> <dimen name="navigation_extra_key_width">@dimen/button_size</dimen> - - <!-- The maximum width of the navigation bar ripples. --> - <dimen name="key_button_ripple_max_width">76dp</dimen> - - <!-- The padding around the navigation buttons --> - <dimen name="navigation_key_padding">0dp</dimen> - </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index db6985d2b61f..46869a0087a4 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -56,11 +56,6 @@ <!-- The amount by which the arrow is shifted to avoid the finger--> <dimen name="navigation_edge_finger_offset">48dp</dimen> - <dimen name="floating_rotation_button_diameter">40dp</dimen> - <dimen name="floating_rotation_button_min_margin">20dp</dimen> - <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen> - <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen> - <!-- Height of notification icons in the status bar --> <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen> @@ -361,8 +356,6 @@ <!-- The width/height of the icon of a navigation button --> <dimen name="navigation_icon_size">32dp</dimen> - <dimen name="navigation_key_padding">0dp</dimen> - <!-- The width of the view containing the menu/ime navigation bar icons --> <dimen name="navigation_extra_key_width">36dp</dimen> @@ -974,9 +967,6 @@ <dimen name="signal_indicator_to_icon_frame_spacing">3dp</dimen> - <!-- The maximum width of the navigation bar ripples. --> - <dimen name="key_button_ripple_max_width">95dp</dimen> - <!-- Inset shadow for FakeShadowDrawable. It is used to avoid gaps between the card and the shadow. --> <dimen name="fake_shadow_inset">1dp</dimen> @@ -1166,7 +1156,6 @@ <!-- The absolute side margins of quick settings --> <dimen name="quick_settings_bottom_margin_media">8dp</dimen> - <dimen name="rounded_corner_content_padding">0dp</dimen> <dimen name="nav_content_padding">0dp</dimen> <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen> <dimen name="nav_quick_scrub_track_thickness">10dp</dimen> diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 4880b124fcdb..62e9d8bb2395 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -45,7 +45,9 @@ android_library { ":wm_shell-aidls", ":wm_shell_util-sources", ], - + resource_dirs: [ + "res", + ], static_libs: [ "PluginCoreLib", "androidx.dynamicanimation_dynamicanimation", diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/shared/res/layout/rotate_suggestion.xml index 1c3eedba4f6f..2fb775cbc9be 100644 --- a/packages/SystemUI/res/layout/rotate_suggestion.xml +++ b/packages/SystemUI/shared/res/layout/rotate_suggestion.xml @@ -18,15 +18,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - - <com.android.systemui.navigationbar.buttons.KeyButtonView + <com.android.systemui.shared.rotation.FloatingRotationButtonView android:id="@+id/rotate_suggestion" android:layout_width="@dimen/floating_rotation_button_diameter" android:layout_height="@dimen/floating_rotation_button_diameter" - android:contentDescription="@string/accessibility_rotate_button" android:paddingStart="@dimen/navigation_key_padding" android:paddingEnd="@dimen/navigation_key_padding" android:layout_gravity="bottom|left" android:scaleType="center" android:visibility="invisible" /> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/packages/SystemUI/shared/res/values-sw600dp/dimens.xml b/packages/SystemUI/shared/res/values-sw600dp/dimens.xml new file mode 100644 index 000000000000..5d9e0596b5c1 --- /dev/null +++ b/packages/SystemUI/shared/res/values-sw600dp/dimens.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + * Copyright (c) 2021, 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. +*/ +--> +<resources> + <dimen name="navigation_key_padding">25dp</dimen> +</resources> diff --git a/packages/SystemUI/shared/res/values-sw900dp/dimens.xml b/packages/SystemUI/shared/res/values-sw900dp/dimens.xml new file mode 100644 index 000000000000..3efa5e3ecf70 --- /dev/null +++ b/packages/SystemUI/shared/res/values-sw900dp/dimens.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + * Copyright (c) 2021, 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. +*/ +--> +<resources> + <!-- The maximum width of the navigation bar ripples. --> + <dimen name="key_button_ripple_max_width">76dp</dimen> + + <!-- The padding around the navigation buttons --> + <dimen name="navigation_key_padding">0dp</dimen> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/shared/res/values/dimens.xml b/packages/SystemUI/shared/res/values/dimens.xml new file mode 100644 index 000000000000..b7f332846858 --- /dev/null +++ b/packages/SystemUI/shared/res/values/dimens.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + * Copyright (c) 2021, 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. +*/ +--> +<resources> + <!-- The maximum width of the navigation bar ripples. --> + <dimen name="key_button_ripple_max_width">95dp</dimen> + + <dimen name="rounded_corner_content_padding">0dp</dimen> + + <dimen name="navigation_key_padding">0dp</dimen> + + <!-- Floating rotation button --> + <dimen name="floating_rotation_button_diameter">40dp</dimen> + <dimen name="floating_rotation_button_min_margin">20dp</dimen> + <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen> + <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen> +</resources> diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java index 00124ac01cc4..53df0f3ab533 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java +++ b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java @@ -33,12 +33,12 @@ import android.view.RenderNodeAnimator; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; - -import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; +import android.view.animation.PathInterpolator; import androidx.annotation.Keep; +import com.android.systemui.shared.R; + import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +49,8 @@ public class KeyButtonRipple extends Drawable { private static final float GLOW_MAX_ALPHA_DARK = 0.1f; private static final int ANIMATION_DURATION_SCALE = 350; private static final int ANIMATION_DURATION_FADE = 450; + private static final Interpolator ALPHA_OUT_INTERPOLATOR = + new PathInterpolator(0f, 0f, 0.8f, 1f); private Paint mRipplePaint; private CanvasProperty<Float> mLeftProp; @@ -336,7 +338,7 @@ public class KeyButtonRipple extends Drawable { private void exitSoftware() { ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f); - alphaAnimator.setInterpolator(Interpolators.ALPHA_OUT); + alphaAnimator.setInterpolator(ALPHA_OUT_INTERPOLATOR); alphaAnimator.setDuration(ANIMATION_DURATION_FADE); alphaAnimator.addListener(mAnimatorListener); alphaAnimator.start(); @@ -459,7 +461,7 @@ public class KeyButtonRipple extends Drawable { final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp, RenderNodeAnimator.PAINT_ALPHA, 0); opacityAnim.setDuration(ANIMATION_DURATION_FADE); - opacityAnim.setInterpolator(Interpolators.ALPHA_OUT); + opacityAnim.setInterpolator(ALPHA_OUT_INTERPOLATOR); opacityAnim.addListener(mAnimatorListener); opacityAnim.addListener(mExitHwTraceAnimator); opacityAnim.setTarget(mTargetView); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java index 46057952e079..be3d7800bb74 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java @@ -14,12 +14,14 @@ * limitations under the License. */ -package com.android.systemui.navigationbar.gestural; +package com.android.systemui.shared.rotation; +import android.annotation.StringRes; import android.content.Context; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.PixelFormat; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -27,28 +29,25 @@ import android.view.WindowManager; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.FrameLayout; -import com.android.systemui.R; -import com.android.systemui.navigationbar.RotationButton; -import com.android.systemui.navigationbar.RotationButtonController; -import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; -import com.android.systemui.navigationbar.buttons.KeyButtonView; -import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position; +import androidx.core.view.OneShotPreDrawListener; + +import com.android.systemui.shared.R; +import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position; /** * Containing logic for the rotation button on the physical left bottom corner of the screen. */ public class FloatingRotationButton implements RotationButton { - private static final float BACKGROUND_ALPHA = 0.92f; private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300; private final WindowManager mWindowManager; private final ViewGroup mKeyButtonContainer; - private final KeyButtonView mKeyButtonView; + private final FloatingRotationButtonView mKeyButtonView; private final int mContainerSize; - private KeyButtonDrawable mKeyButtonDrawable; + private AnimatedVectorDrawable mAnimatedDrawable; private boolean mIsShowing; private boolean mCanShow = true; private int mDisplayRotation; @@ -62,12 +61,13 @@ public class FloatingRotationButton implements RotationButton { private RotationButtonUpdatesCallback mUpdatesCallback; private Position mPosition; - public FloatingRotationButton(Context context) { + public FloatingRotationButton(Context context, @StringRes int contentDescription) { mWindowManager = context.getSystemService(WindowManager.class); mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate( R.layout.rotate_suggestion, null); mKeyButtonView = mKeyButtonContainer.findViewById(R.id.rotate_suggestion); mKeyButtonView.setVisibility(View.VISIBLE); + mKeyButtonView.setContentDescription(context.getString(contentDescription)); Resources res = context.getResources(); @@ -113,6 +113,10 @@ public class FloatingRotationButton implements RotationButton { mIsShowing = true; int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + + // TODO(b/200103245): add new window type that has z-index above + // TYPE_NAVIGATION_BAR_PANEL as currently it could be below the taskbar which has + // the same window type final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( mContainerSize, mContainerSize, @@ -134,14 +138,18 @@ public class FloatingRotationButton implements RotationButton { updateTranslation(mPosition, /* animate */ false); mWindowManager.addView(mKeyButtonContainer, lp); - if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) { - mKeyButtonDrawable.resetAnimation(); - mKeyButtonDrawable.startAnimation(); + if (mAnimatedDrawable != null) { + mAnimatedDrawable.reset(); + mAnimatedDrawable.start(); } - if (mUpdatesCallback != null) { - mUpdatesCallback.onVisibilityChanged(true); - } + // Notify about visibility only after first traversal so we can properly calculate + // the touch region for the button + OneShotPreDrawListener.add(mKeyButtonView, () -> { + if (mIsShowing && mUpdatesCallback != null) { + mUpdatesCallback.onVisibilityChanged(true); + } + }); return true; } @@ -166,12 +174,10 @@ public class FloatingRotationButton implements RotationButton { @Override public void updateIcon(int lightIconColor, int darkIconColor) { - Color ovalBackgroundColor = Color.valueOf(Color.red(darkIconColor), - Color.green(darkIconColor), Color.blue(darkIconColor), BACKGROUND_ALPHA); - mKeyButtonDrawable = KeyButtonDrawable.create(mRotationButtonController.getContext(), - lightIconColor, darkIconColor, mRotationButtonController.getIconResId(), - false /* shadow */, ovalBackgroundColor); - mKeyButtonView.setImageDrawable(mKeyButtonDrawable); + mAnimatedDrawable = (AnimatedVectorDrawable) mKeyButtonView.getContext() + .getDrawable(mRotationButtonController.getIconResId()); + mKeyButtonView.setImageDrawable(mAnimatedDrawable); + mKeyButtonView.setColors(lightIconColor, darkIconColor); } @Override @@ -185,8 +191,8 @@ public class FloatingRotationButton implements RotationButton { } @Override - public KeyButtonDrawable getImageDrawable() { - return mKeyButtonDrawable; + public Drawable getImageDrawable() { + return mAnimatedDrawable; } @Override @@ -202,6 +208,7 @@ public class FloatingRotationButton implements RotationButton { } } + @Override public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) { mIsTaskbarVisible = taskbarVisible; mIsTaskbarStashed = taskbarStashed; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt index 3ce51ad331c5..ec3c073dc68d 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt @@ -1,4 +1,4 @@ -package com.android.systemui.navigationbar.gestural +package com.android.systemui.shared.rotation import android.view.Gravity import android.view.Surface @@ -7,7 +7,7 @@ import android.view.Surface * Calculates gravity and translation that is necessary to display * the button in the correct position based on the current state */ -internal class FloatingRotationButtonPositionCalculator( +class FloatingRotationButtonPositionCalculator( private val defaultMargin: Int, private val taskbarMarginLeft: Int, private val taskbarMarginBottom: Int diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java new file mode 100644 index 000000000000..e0187f41c68a --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 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.systemui.shared.rotation; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; + +import com.android.systemui.navigationbar.buttons.KeyButtonRipple; + +public class FloatingRotationButtonView extends ImageView { + + private static final float BACKGROUND_ALPHA = 0.92f; + + private final KeyButtonRipple mRipple; + private final Paint mOvalBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + + public FloatingRotationButtonView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FloatingRotationButtonView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + setClickable(true); + + mRipple = new KeyButtonRipple(context, this); + setBackground(mRipple); + setWillNotDraw(false); + forceHasOverlappingRendering(false); + } + + @Override + protected void onWindowVisibilityChanged(int visibility) { + super.onWindowVisibilityChanged(visibility); + if (visibility != View.VISIBLE) { + jumpDrawablesToCurrentState(); + } + } + + public void setColors(int lightColor, int darkColor) { + getDrawable().setColorFilter(new PorterDuffColorFilter(lightColor, PorterDuff.Mode.SRC_IN)); + + final int ovalBackgroundColor = Color.valueOf(Color.red(darkColor), + Color.green(darkColor), Color.blue(darkColor), BACKGROUND_ALPHA).toArgb(); + + mOvalBgPaint.setColor(ovalBackgroundColor); + mRipple.setType(KeyButtonRipple.Type.OVAL); + } + + public void setDarkIntensity(float darkIntensity) { + mRipple.setDarkIntensity(darkIntensity); + } + + @Override + public void draw(Canvas canvas) { + int d = Math.min(getWidth(), getHeight()); + canvas.drawOval(0, 0, d, d, mOvalBgPaint); + super.draw(canvas); + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java new file mode 100644 index 000000000000..89f71ebf3dce --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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.systemui.shared.rotation; + +import android.graphics.drawable.Drawable; +import android.view.View; + +/** + * Interface of a rotation button that interacts {@link RotationButtonController}. + * This interface exists because of the two different styles of rotation button in Sysui, + * one in contextual for 3 button nav and a floating rotation button for gestural. + */ +public interface RotationButton { + default void setRotationButtonController(RotationButtonController rotationButtonController) { } + default void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) { } + + default View getCurrentView() { + return null; + } + default boolean show() { return false; } + default boolean hide() { return false; } + default boolean isVisible() { + return false; + } + default void setCanShowRotationButton(boolean canShow) {} + default void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {} + default void updateIcon(int lightIconColor, int darkIconColor) { } + default void setOnClickListener(View.OnClickListener onClickListener) { } + default void setOnHoverListener(View.OnHoverListener onHoverListener) { } + default Drawable getImageDrawable() { + return null; + } + default void setDarkIntensity(float darkIntensity) { } + default boolean acceptRotationProposal() { + return getCurrentView() != null; + } + + /** + * Callback for updates provided by a rotation button + */ + interface RotationButtonUpdatesCallback { + default void onVisibilityChanged(boolean isVisible) {}; + default void onPositionChanged() {}; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java index 0f5c03a2a596..2dbd5dee76aa 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 2021 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. @@ -14,7 +14,9 @@ * limitations under the License. */ -package com.android.systemui.navigationbar; +package com.android.systemui.shared.rotation; + +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION; @@ -23,48 +25,51 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.ColorInt; import android.annotation.DrawableRes; +import android.annotation.SuppressLint; import android.app.StatusBarManager; import android.content.ContentResolver; import android.content.Context; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; -import android.view.IRotationWatcher.Stub; +import android.view.IRotationWatcher; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.WindowInsetsController; -import android.view.WindowInsetsController.Behavior; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; -import com.android.systemui.Dependency; -import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; -import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback; -import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; +import com.android.internal.view.RotationPolicy; +import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback; import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.recents.utilities.ViewRippler; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; -import com.android.systemui.statusbar.policy.RotationLockController; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Supplier; -/** Contains logic that deals with showing a rotate suggestion button with animation. */ +/** + * Contains logic that deals with showing a rotate suggestion button with animation. + */ public class RotationButtonController { private static final String TAG = "StatusBar/RotationButtonController"; private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100; private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000; + private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3; @@ -72,6 +77,7 @@ public class RotationButtonController { private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); private final ViewRippler mViewRippler = new ViewRippler(); + private final Supplier<Integer> mWindowRotationProvider; private RotationButton mRotationButton; private boolean mIsRecentsAnimationRunning; @@ -79,17 +85,30 @@ public class RotationButtonController { private int mLastRotationSuggestion; private boolean mPendingRotationSuggestion; private boolean mHoveringRotationSuggestion; - private RotationLockController mRotationLockController; - private AccessibilityManagerWrapper mAccessibilityManagerWrapper; - private TaskStackListenerImpl mTaskStackListener; + private final AccessibilityManager mAccessibilityManager; + private final TaskStackListenerImpl mTaskStackListener; private Consumer<Integer> mRotWatcherListener; + private boolean mListenersRegistered = false; private boolean mIsNavigationBarShowing; - private @Behavior int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT; + @SuppressLint("InlinedApi") + private @WindowInsetsController.Behavior + int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT; private boolean mSkipOverrideUserLockPrefsOnce; - private int mLightIconColor; - private int mDarkIconColor; - private int mIconResId = R.drawable.ic_sysbar_rotate_button_ccw_start_90; + private final int mLightIconColor; + private final int mDarkIconColor; + + @DrawableRes + private final int mIconCcwStart0ResId; + @DrawableRes + private final int mIconCcwStart90ResId; + @DrawableRes + private final int mIconCwStart0ResId; + @DrawableRes + private final int mIconCwStart90ResId; + + @DrawableRes + private int mIconResId; private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false /* visible */); @@ -97,19 +116,20 @@ public class RotationButtonController { () -> mPendingRotationSuggestion = false; private Animator mRotateHideAnimator; - private final Stub mRotationWatcher = new Stub() { + + private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() { @Override - public void onRotationChanged(final int rotation) throws RemoteException { + public void onRotationChanged(final int rotation) { // We need this to be scheduled as early as possible to beat the redrawing of // window in response to the orientation change. mMainThreadHandler.postAtFrontOfQueue(() -> { // If the screen rotation changes while locked, potentially update lock to flow with // new screen rotation and hide any showing suggestions. - if (mRotationLockController.isRotationLocked()) { + if (isRotationLocked()) { if (shouldOverrideUserLockPrefs(rotation)) { setRotationLockedAtAngle(rotation); } - setRotateSuggestionButtonState(false /* visible */, true /* hideImmediately */); + setRotateSuggestionButtonState(false /* visible */, true /* forced */); } if (mRotWatcherListener != null) { @@ -121,27 +141,39 @@ public class RotationButtonController { /** * Determines if rotation suggestions disabled2 flag exists in flag + * * @param disable2Flags see if rotation suggestion flag exists in this flag * @return whether flag exists */ - static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) { + public static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) { return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0; } - RotationButtonController(Context context, @ColorInt int lightIconColor, - @ColorInt int darkIconColor) { + public RotationButtonController(Context context, + @ColorInt int lightIconColor, @ColorInt int darkIconColor, + @DrawableRes int iconCcwStart0ResId, + @DrawableRes int iconCcwStart90ResId, + @DrawableRes int iconCwStart0ResId, + @DrawableRes int iconCwStart90ResId, + Supplier<Integer> windowRotationProvider) { + mContext = context; mLightIconColor = lightIconColor; mDarkIconColor = darkIconColor; - mIsNavigationBarShowing = true; - mRotationLockController = Dependency.get(RotationLockController.class); - mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class); + mIconCcwStart0ResId = iconCcwStart0ResId; + mIconCcwStart90ResId = iconCcwStart90ResId; + mIconCwStart0ResId = iconCwStart0ResId; + mIconCwStart90ResId = iconCwStart90ResId; + mIconResId = mIconCcwStart90ResId; + + mAccessibilityManager = AccessibilityManager.getInstance(context); mTaskStackListener = new TaskStackListenerImpl(); + mWindowRotationProvider = windowRotationProvider; } - void setRotationButton(RotationButton rotationButton, - RotationButtonUpdatesCallback updatesCallback) { + public void setRotationButton(RotationButton rotationButton, + RotationButtonUpdatesCallback updatesCallback) { mRotationButton = rotationButton; mRotationButton.setRotationButtonController(this); mRotationButton.setOnClickListener(this::onRotateSuggestionClick); @@ -149,7 +181,24 @@ public class RotationButtonController { mRotationButton.setUpdatesCallback(updatesCallback); } - void registerListeners() { + public Context getContext() { + return mContext; + } + + public void init() { + registerListeners(); + if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) { + // Currently there is no accelerometer sensor on non-default display, disable fixed + // rotation for non-default display + onDisable2FlagChanged(StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS); + } + } + + public void onDestroy() { + unregisterListeners(); + } + + public void registerListeners() { if (mListenersRegistered) { return; } @@ -157,18 +206,19 @@ public class RotationButtonController { mListenersRegistered = true; try { WindowManagerGlobal.getWindowManagerService() - .watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId()); + .watchRotation(mRotationWatcher, DEFAULT_DISPLAY); } catch (IllegalArgumentException e) { mListenersRegistered = false; Log.w(TAG, "RegisterListeners for the display failed"); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "RegisterListeners caught a RemoteException", e); + return; } TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); } - void unregisterListeners() { + public void unregisterListeners() { if (!mListenersRegistered) { return; } @@ -177,34 +227,31 @@ public class RotationButtonController { try { WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "UnregisterListeners caught a RemoteException", e); + return; } TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); } - void setRotationCallback(Consumer<Integer> watcher) { + public void setRotationCallback(Consumer<Integer> watcher) { mRotWatcherListener = watcher; } - void setRotationLockedAtAngle(int rotationSuggestion) { - mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion); + public void setRotationLockedAtAngle(int rotationSuggestion) { + RotationPolicy.setRotationLockAtAngle(mContext, true, rotationSuggestion); } public boolean isRotationLocked() { - return mRotationLockController.isRotationLocked(); + return RotationPolicy.isRotationLocked(mContext); } - void setRotateSuggestionButtonState(boolean visible) { - setRotateSuggestionButtonState(visible, false /* hideImmediately */); + public void setRotateSuggestionButtonState(boolean visible) { + setRotateSuggestionButtonState(visible, false /* force */); } - /** - * Change the visibility of rotate suggestion button. If {@code hideImmediately} is true, - * it doesn't wait until the completion of the running animation. - */ - void setRotateSuggestionButtonState(final boolean visible, final boolean hideImmediately) { - // At any point the the button can become invisible because an a11y service became active. + void setRotateSuggestionButtonState(final boolean visible, final boolean force) { + // At any point the button can become invisible because an a11y service became active. // Similarly, a call to make the button visible may be rejected because an a11y service is // active. Must account for this. // Rerun a show animation to indicate change but don't rerun a hide animation @@ -213,7 +260,7 @@ public class RotationButtonController { final View view = mRotationButton.getCurrentView(); if (view == null) return; - final KeyButtonDrawable currentDrawable = mRotationButton.getImageDrawable(); + final Drawable currentDrawable = mRotationButton.getImageDrawable(); if (currentDrawable == null) return; // Clear any pending suggestion flag as it has either been nullified or is being shown @@ -232,11 +279,13 @@ public class RotationButtonController { view.setAlpha(1f); // Run the rotate icon's animation if it has one - if (currentDrawable.canAnimate()) { - currentDrawable.resetAnimation(); - currentDrawable.startAnimation(); + if (currentDrawable instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) currentDrawable).reset(); + ((AnimatedVectorDrawable) currentDrawable).start(); } + // TODO(b/187754252): No idea why this doesn't work. If we remove the "false" + // we see the animation show the pressed state... but it only shows the first time. if (!isRotateSuggestionIntroduced()) mViewRippler.start(view); // Set visibility unless a11y service is active. @@ -244,7 +293,7 @@ public class RotationButtonController { } else { // Hide mViewRippler.stop(); // Prevent any pending ripples, force hide or not - if (hideImmediately) { + if (force) { // If a hide animator is running stop it and make invisible if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) { mRotateHideAnimator.pause(); @@ -258,7 +307,7 @@ public class RotationButtonController { ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f); fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS); - fadeOut.setInterpolator(Interpolators.LINEAR); + fadeOut.setInterpolator(LINEAR_INTERPOLATOR); fadeOut.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -271,29 +320,34 @@ public class RotationButtonController { } } - void setRecentsAnimationRunning(boolean running) { + public void setDarkIntensity(float darkIntensity) { + mRotationButton.setDarkIntensity(darkIntensity); + } + + public void setRecentsAnimationRunning(boolean running) { mIsRecentsAnimationRunning = running; updateRotationButtonStateInOverview(); } - void setHomeRotationEnabled(boolean enabled) { + public void setHomeRotationEnabled(boolean enabled) { mHomeRotationEnabled = enabled; updateRotationButtonStateInOverview(); } private void updateRotationButtonStateInOverview() { if (mIsRecentsAnimationRunning && !mHomeRotationEnabled) { - setRotateSuggestionButtonState(false, true /* hideImmediately */ ); + setRotateSuggestionButtonState(false, true /* hideImmediately */); } } - void setDarkIntensity(float darkIntensity) { - mRotationButton.setDarkIntensity(darkIntensity); - } + public void onRotationProposal(int rotation, boolean isValid) { + int windowRotation = mWindowRotationProvider.get(); + + if (!mRotationButton.acceptRotationProposal()) { + return; + } - void onRotationProposal(int rotation, int windowRotation, boolean isValid) { - if (!mRotationButton.acceptRotationProposal() || (!mHomeRotationEnabled - && mIsRecentsAnimationRunning)) { + if (!mHomeRotationEnabled && mIsRecentsAnimationRunning) { return; } @@ -316,13 +370,9 @@ public class RotationButtonController { mLastRotationSuggestion = rotation; // Remember rotation for click final boolean rotationCCW = Utilities.isRotationAnimationCCW(windowRotation, rotation); if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) { - mIconResId = rotationCCW - ? R.drawable.ic_sysbar_rotate_button_ccw_start_90 - : R.drawable.ic_sysbar_rotate_button_cw_start_90; + mIconResId = rotationCCW ? mIconCcwStart0ResId : mIconCwStart0ResId; } else { // 90 or 270 - mIconResId = rotationCCW - ? R.drawable.ic_sysbar_rotate_button_ccw_start_0 - : R.drawable.ic_sysbar_rotate_button_ccw_start_0; + mIconResId = rotationCCW ? mIconCcwStart90ResId : mIconCwStart90ResId; } mRotationButton.updateIcon(mLightIconColor, mDarkIconColor); @@ -339,56 +389,66 @@ public class RotationButtonController { } } - void onDisable2FlagChanged(int state2) { + public void onDisable2FlagChanged(int state2) { final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2); if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled(); } - void onNavigationBarWindowVisibilityChange(boolean showing) { - if (mIsNavigationBarShowing != showing) { - mIsNavigationBarShowing = showing; - showPendingRotationButtonIfNeeded(); + public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) { + if (DEFAULT_DISPLAY != displayId) { + return; } - } - void onBehaviorChanged(@Behavior int behavior) { if (mBehavior != behavior) { mBehavior = behavior; showPendingRotationButtonIfNeeded(); } } + public void onNavigationBarWindowVisibilityChange(boolean showing) { + if (mIsNavigationBarShowing != showing) { + mIsNavigationBarShowing = showing; + showPendingRotationButtonIfNeeded(); + } + } + + public void onTaskbarStateChange(boolean visible, boolean stashed) { + getRotationButton().onTaskbarStateChanged(visible, stashed); + } + private void showPendingRotationButtonIfNeeded() { if (canShowRotationButton() && mPendingRotationSuggestion) { showAndLogRotationSuggestion(); } } - /** Return true when either the nav bar is visible or it's in visual immersive mode. */ + /** + * Return true when either the task bar is visible or it's in visual immersive mode. + */ + @SuppressLint("InlinedApi") private boolean canShowRotationButton() { return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT; } - public Context getContext() { - return mContext; - } - - RotationButton getRotationButton() { - return mRotationButton; - } - - public @DrawableRes int getIconResId() { + @DrawableRes + public int getIconResId() { return mIconResId; } - public @ColorInt int getLightIconColor() { + @ColorInt + public int getLightIconColor() { return mLightIconColor; } - public @ColorInt int getDarkIconColor() { + @ColorInt + public int getDarkIconColor() { return mDarkIconColor; } + public RotationButton getRotationButton() { + return mRotationButton; + } + private void onRotateSuggestionClick(View v) { mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED); incrementNumAcceptedRotationSuggestionsIfNeeded(); @@ -420,7 +480,7 @@ public class RotationButtonController { * avoid losing original user rotation when display rotation is changed by entering the fixed * orientation overview. */ - void setSkipOverrideUserLockPrefsOnce() { + public void setSkipOverrideUserLockPrefsOnce() { mSkipOverrideUserLockPrefsOnce = true; } @@ -451,7 +511,7 @@ public class RotationButtonController { } private int computeRotationProposalTimeout() { - return mAccessibilityManagerWrapper.getRecommendedTimeoutMillis( + return mAccessibilityManager.getRecommendedTimeoutMillis( mHoveringRotationSuggestion ? 16000 : 5000, AccessibilityManager.FLAG_CONTENT_CONTROLS); } @@ -513,11 +573,15 @@ public class RotationButtonController { ROTATION_SUGGESTION_ACCEPTED(207); private final int mId; + RotationButtonEvent(int id) { mId = id; } - @Override public int getId() { + + @Override + public int getId() { return mId; } } } + diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 7809b5fb83ce..6a1eae75f9a9 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -131,6 +131,8 @@ import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; +import com.android.systemui.shared.rotation.RotationButton; +import com.android.systemui.shared.rotation.RotationButtonController; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -944,7 +946,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener, // not valid. Just ignore the rotation in this case. if (!mNavigationBarView.isAttachedToWindow()) return; - final int winRotation = mNavigationBarView.getDisplay().getRotation(); final boolean rotateSuggestionsDisabled = RotationButtonController .hasDisable2RotateSuggestionFlag(mDisabledFlags2); final RotationButtonController rotationButtonController = @@ -953,7 +954,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener, if (RotationContextButton.DEBUG_ROTATION) { Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation) - + ", winRotation=" + Surface.rotationToString(winRotation) + ", isValid=" + isValid + ", mNavBarWindowState=" + StatusBarManager.windowStateToString(mNavigationBarWindowState) + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled @@ -963,7 +963,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, // Respect the disabled flag, no need for action as flag change callback will handle hiding if (rotateSuggestionsDisabled) return; - rotationButtonController.onRotationProposal(rotation, winRotation, isValid); + rotationButtonController.onRotationProposal(rotation, isValid); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index c02cc8dda4c4..cba76e004558 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -67,7 +67,6 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback; import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.navigationbar.buttons.ContextualButton; import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; @@ -76,9 +75,11 @@ import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.NearestTouchFrame; import com.android.systemui.navigationbar.buttons.RotationContextButton; import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; -import com.android.systemui.navigationbar.gestural.FloatingRotationButton; +import com.android.systemui.shared.rotation.FloatingRotationButton; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; +import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback; +import com.android.systemui.shared.rotation.RotationButtonController; import com.android.systemui.shared.navigationbar.RegionSamplingHelper; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; @@ -322,9 +323,15 @@ public class NavigationBarView extends FrameLayout implements mContextualButtonGroup.addButton(accessibilityButton); mRotationContextButton = new RotationContextButton(R.id.rotate_suggestion, mLightContext, R.drawable.ic_sysbar_rotate_button_ccw_start_0); - mFloatingRotationButton = new FloatingRotationButton(context); - mRotationButtonController = new RotationButtonController(mLightContext, - mLightIconColor, mDarkIconColor); + mFloatingRotationButton = new FloatingRotationButton(context, + R.string.accessibility_rotate_button); + mRotationButtonController = new RotationButtonController(mLightContext, mLightIconColor, + mDarkIconColor, R.drawable.ic_sysbar_rotate_button_ccw_start_0, + R.drawable.ic_sysbar_rotate_button_ccw_start_90, + R.drawable.ic_sysbar_rotate_button_cw_start_0, + R.drawable.ic_sysbar_rotate_button_cw_start_90, + () -> getDisplay().getRotation()); + updateRotationButton(); mOverviewProxyService = Dependency.get(OverviewProxyService.class); @@ -661,7 +668,7 @@ public class NavigationBarView extends FrameLayout implements } public void setBehavior(@Behavior int behavior) { - mRotationButtonController.onBehaviorChanged(behavior); + mRotationButtonController.onBehaviorChanged(Display.DEFAULT_DISPLAY, behavior); } @Override @@ -1277,6 +1284,7 @@ public class NavigationBarView extends FrameLayout implements mButtonDispatchers.valueAt(i).onDestroy(); } if (mRotationButtonController != null) { + mFloatingRotationButton.hide(); mRotationButtonController.unregisterListeners(); } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java deleted file mode 100644 index 3486c6e75931..000000000000 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2020 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.systemui.navigationbar; - -import android.view.View; - -import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; - -/** Interface of a rotation button that interacts {@link RotationButtonController}. */ -public interface RotationButton { - void setRotationButtonController(RotationButtonController rotationButtonController); - void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback); - View getCurrentView(); - boolean show(); - boolean hide(); - boolean isVisible(); - void updateIcon(int lightIconColor, int darkIconColor); - void setOnClickListener(View.OnClickListener onClickListener); - void setOnHoverListener(View.OnHoverListener onHoverListener); - KeyButtonDrawable getImageDrawable(); - void setDarkIntensity(float darkIntensity); - default void setCanShowRotationButton(boolean canShow) {} - default boolean acceptRotationProposal() { - return getCurrentView() != null; - } - - /** - * Callback for updates provided by a rotation button - */ - interface RotationButtonUpdatesCallback { - void onVisibilityChanged(boolean isVisible); - void onPositionChanged(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java index ebb67af43a37..ac014b5b4a64 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java @@ -21,8 +21,8 @@ import android.annotation.IdRes; import android.content.Context; import android.view.View; -import com.android.systemui.navigationbar.RotationButton; -import com.android.systemui.navigationbar.RotationButtonController; +import com.android.systemui.shared.rotation.RotationButton; +import com.android.systemui.shared.rotation.RotationButtonController; /** Containing logic for the rotation button in nav bar. */ public class RotationContextButton extends ContextualButton implements RotationButton { diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java index a6ff2e8d2e15..85bc634c28b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.view.Display; import android.view.View; import android.view.WindowInsetsController; @@ -31,6 +32,8 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; +import com.android.systemui.shared.rotation.RotationButton; +import com.android.systemui.shared.rotation.RotationButtonController; import com.android.systemui.statusbar.policy.RotationLockController; import org.junit.Before; @@ -39,6 +42,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; +import java.util.function.Supplier; + /** atest NavigationBarRotationContextTest */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -50,6 +55,8 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { InstrumentationRegistry.getContext(), getLeakCheck()); private RotationButtonController mRotationButtonController; private RotationButton mRotationButton; + private int mWindowRotation = DEFAULT_ROTATE; + private Supplier<Integer> mWindowRotationSupplier = () -> mWindowRotation; @Before public void setup() { @@ -58,7 +65,15 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { final View view = new View(mContext); mRotationButton = mock(RotationButton.class); - mRotationButtonController = new RotationButtonController(mContext, 0, 0); + mRotationButtonController = new RotationButtonController(mContext, + /* lightIconColor */ 0, + /* darkIconColor */ 0, + /* iconCcwStart0 */ 0, + /* iconCcwStart90 */ 0, + /* iconCwStart0 */ 0, + /* iconCwStart90 */ 0, + mWindowRotationSupplier + ); mRotationButtonController.setRotationButton(mRotationButton, new RotationButton.RotationButtonUpdatesCallback() { @Override @@ -77,16 +92,16 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { @Test public void testOnInvalidRotationProposal() { - mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, - false /* isValid */); + mWindowRotation = DEFAULT_ROTATE + 1; + mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, false /* isValid */); verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState( false /* visible */); } @Test public void testOnSameRotationProposal() { - mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE, - true /* isValid */); + mWindowRotation = DEFAULT_ROTATE; + mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */); verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState( false /* visible */); } @@ -94,17 +109,17 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { @Test public void testOnRotationProposalShowButtonShowNav() { // No navigation bar should not call to set visibility state - mRotationButtonController.onBehaviorChanged( + mRotationButtonController.onBehaviorChanged(Display.DEFAULT_DISPLAY, WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); mRotationButtonController.onNavigationBarWindowVisibilityChange(false /* showing */); verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState( false /* visible */); verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState( true /* visible */); + mWindowRotation = DEFAULT_ROTATE + 1; // No navigation bar with rotation change should not call to set visibility state - mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, - true /* isValid */); + mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */); verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState( false /* visible */); verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState( @@ -124,10 +139,10 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { false /* visible */); verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState( true /* visible */); + mWindowRotation = DEFAULT_ROTATE + 1; // Navigation bar is visible and rotation requested - mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1, - true /* isValid */); + mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */); verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState( true /* visible */); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt index 0a2000107053..36e02cb1df06 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt @@ -4,7 +4,8 @@ import android.view.Gravity import android.view.Surface import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position +import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator +import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith |