diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
index 194d2e063e970..1c3eedba4f6fb 100644
--- a/packages/SystemUI/res/layout/rotate_suggestion.xml
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -14,16 +14,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-
\ No newline at end of file
+ >
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2e2d53be4fa1f..411e6851a0130 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -62,7 +62,9 @@
- 0.05
40dp
- 4dp
+ 20dp
+ 20dp
+ 10dp
@*android:dimen/status_bar_icon_size
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index f72245b9b252e..11557ad87929b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -140,5 +140,8 @@ interface ISystemUiProxy {
/** Notifies that a swipe-up gesture has started */
oneway void notifySwipeUpGestureStarted() = 46;
- // Next id = 47
+ /** Notifies when taskbar status updated */
+ oneway void notifyTaskbarStatus(boolean visible, boolean stashed) = 47;
+
+ // Next id = 48
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 90afec6a24c1b..3073f8353d38e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -383,6 +383,13 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
}
+ @Override
+ public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
+ mNavigationBarView
+ .getFloatingRotationButton()
+ .onTaskbarStateChanged(visible, stashed);
+ }
+
@Override
public void onToggleRecentApps() {
// The same case as onOverviewShown but only for 3-button navigation.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 4816f1cf8d6a6..23c066a75732a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -69,6 +69,7 @@ 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;
@@ -275,14 +276,23 @@ public class NavigationBarView extends FrameLayout implements
false /* inScreen */, false /* useNearestRegion */));
};
- private final Consumer mRotationButtonListener = (visible) -> {
- if (visible) {
- // If the button will actually become visible and the navbar is about to hide,
- // tell the statusbar to keep it around for longer
- mAutoHideController.touchAutoHide();
- }
- notifyActiveTouchRegions();
- };
+ private final RotationButtonUpdatesCallback mRotationButtonListener =
+ new RotationButtonUpdatesCallback() {
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ if (visible) {
+ // If the button will actually become visible and the navbar is about
+ // to hide, tell the statusbar to keep it around for longer
+ mAutoHideController.touchAutoHide();
+ }
+ notifyActiveTouchRegions();
+ }
+
+ @Override
+ public void onPositionChanged() {
+ notifyActiveTouchRegions();
+ }
+ };
private final Consumer mNavbarOverlayVisibilityChangeCallback = (visible) -> {
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
index e487858443470..3486c6e759315 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
@@ -20,12 +20,10 @@ import android.view.View;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-import java.util.function.Consumer;
-
/** Interface of a rotation button that interacts {@link RotationButtonController}. */
public interface RotationButton {
void setRotationButtonController(RotationButtonController rotationButtonController);
- void setVisibilityChangedCallback(Consumer visibilityChangedCallback);
+ void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback);
View getCurrentView();
boolean show();
boolean hide();
@@ -39,4 +37,12 @@ public interface RotationButton {
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/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index a5b7911d3b3da..196625b3630e6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -46,6 +46,7 @@ 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.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.utilities.ViewRippler;
@@ -140,12 +141,12 @@ public class RotationButtonController {
}
void setRotationButton(RotationButton rotationButton,
- Consumer visibilityChangedCallback) {
+ RotationButtonUpdatesCallback updatesCallback) {
mRotationButton = rotationButton;
mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
- mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback);
+ mRotationButton.setUpdatesCallback(updatesCallback);
}
void registerListeners() {
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 6a97a3379939d..ebb67af43a374 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
@@ -23,10 +23,6 @@ import android.view.View;
import com.android.systemui.navigationbar.RotationButton;
import com.android.systemui.navigationbar.RotationButtonController;
-import com.android.systemui.navigationbar.buttons.ContextualButton;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-
-import java.util.function.Consumer;
/** Containing logic for the rotation button in nav bar. */
public class RotationContextButton extends ContextualButton implements RotationButton {
@@ -48,13 +44,10 @@ public class RotationContextButton extends ContextualButton implements RotationB
}
@Override
- public void setVisibilityChangedCallback(Consumer visibilityChangedCallback) {
- setListener(new ContextButtonListener() {
- @Override
- public void onVisibilityChanged(ContextualButton button, boolean visible) {
- if (visibilityChangedCallback != null) {
- visibilityChangedCallback.accept(visible);
- }
+ public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
+ setListener((button, visible) -> {
+ if (updatesCallback != null) {
+ updatesCallback.onVisibilityChanged(visible);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
index 61118c5d26ac4..46057952e0792 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
@@ -20,48 +20,72 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.Surface;
import android.view.View;
+import android.view.ViewGroup;
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 java.util.function.Consumer;
-
-/** Containing logic for the rotation button on the physical left bottom corner of the screen. */
+/**
+ * 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 Context mContext;
private final WindowManager mWindowManager;
+ private final ViewGroup mKeyButtonContainer;
private final KeyButtonView mKeyButtonView;
- private final int mDiameter;
- private final int mMargin;
+
+ private final int mContainerSize;
+
private KeyButtonDrawable mKeyButtonDrawable;
private boolean mIsShowing;
private boolean mCanShow = true;
+ private int mDisplayRotation;
+
+ private boolean mIsTaskbarVisible = false;
+ private boolean mIsTaskbarStashed = false;
+
+ private final FloatingRotationButtonPositionCalculator mPositionCalculator;
private RotationButtonController mRotationButtonController;
- private Consumer mVisibilityChangedCallback;
+ private RotationButtonUpdatesCallback mUpdatesCallback;
+ private Position mPosition;
public FloatingRotationButton(Context context) {
- mContext = context;
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mKeyButtonView = (KeyButtonView) LayoutInflater.from(mContext).inflate(
+ 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);
- Resources res = mContext.getResources();
- mDiameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
- mMargin = Math.max(res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
+ Resources res = context.getResources();
+
+ int defaultMargin = Math.max(
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
res.getDimensionPixelSize(R.dimen.rounded_corner_content_padding));
+
+ int taskbarMarginLeft =
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_left_margin);
+ int taskbarMarginBottom =
+ res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_bottom_margin);
+
+ mPositionCalculator = new FloatingRotationButtonPositionCalculator(defaultMargin,
+ taskbarMarginLeft, taskbarMarginBottom);
+
+ final int diameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
+ mContainerSize = diameter + Math.max(defaultMargin, Math.max(taskbarMarginLeft,
+ taskbarMarginBottom));
}
@Override
@@ -72,8 +96,8 @@ public class FloatingRotationButton implements RotationButton {
}
@Override
- public void setVisibilityChangedCallback(Consumer visibilityChangedCallback) {
- mVisibilityChangedCallback = visibilityChangedCallback;
+ public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
+ mUpdatesCallback = updatesCallback;
}
@Override
@@ -86,45 +110,39 @@ public class FloatingRotationButton implements RotationButton {
if (!mCanShow || mIsShowing) {
return false;
}
+
mIsShowing = true;
int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(mDiameter, mDiameter,
- mMargin, mMargin, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags,
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ mContainerSize,
+ mContainerSize,
+ 0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags,
PixelFormat.TRANSLUCENT);
+
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("FloatingRotationButton");
lp.setFitInsetsTypes(0 /*types */);
- switch (mWindowManager.getDefaultDisplay().getRotation()) {
- case Surface.ROTATION_0:
- lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
- break;
- case Surface.ROTATION_90:
- lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
- break;
- case Surface.ROTATION_180:
- lp.gravity = Gravity.TOP | Gravity.RIGHT;
- break;
- case Surface.ROTATION_270:
- lp.gravity = Gravity.TOP | Gravity.LEFT;
- break;
- default:
- break;
- }
- mWindowManager.addView(mKeyButtonView, lp);
+
+ mDisplayRotation = mWindowManager.getDefaultDisplay().getRotation();
+ mPosition = mPositionCalculator
+ .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed);
+
+ lp.gravity = mPosition.getGravity();
+ ((FrameLayout.LayoutParams) mKeyButtonView.getLayoutParams()).gravity =
+ mPosition.getGravity();
+
+ updateTranslation(mPosition, /* animate */ false);
+
+ mWindowManager.addView(mKeyButtonContainer, lp);
if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) {
mKeyButtonDrawable.resetAnimation();
mKeyButtonDrawable.startAnimation();
}
- mKeyButtonView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5,
- int i6, int i7) {
- if (mIsShowing && mVisibilityChangedCallback != null) {
- mVisibilityChangedCallback.accept(true);
- }
- mKeyButtonView.removeOnLayoutChangeListener(this);
- }
- });
+
+ if (mUpdatesCallback != null) {
+ mUpdatesCallback.onVisibilityChanged(true);
+ }
+
return true;
}
@@ -133,10 +151,10 @@ public class FloatingRotationButton implements RotationButton {
if (!mIsShowing) {
return false;
}
- mWindowManager.removeViewImmediate(mKeyButtonView);
+ mWindowManager.removeViewImmediate(mKeyButtonContainer);
mIsShowing = false;
- if (mVisibilityChangedCallback != null) {
- mVisibilityChangedCallback.accept(false);
+ if (mUpdatesCallback != null) {
+ mUpdatesCallback.onVisibilityChanged(false);
}
return true;
}
@@ -183,4 +201,43 @@ public class FloatingRotationButton implements RotationButton {
hide();
}
}
+
+ public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {
+ mIsTaskbarVisible = taskbarVisible;
+ mIsTaskbarStashed = taskbarStashed;
+
+ if (!mIsShowing) return;
+
+ final Position newPosition = mPositionCalculator
+ .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed);
+
+ if (newPosition.getTranslationX() != mPosition.getTranslationX()
+ || newPosition.getTranslationY() != mPosition.getTranslationY()) {
+ updateTranslation(newPosition, /* animate */ true);
+ mPosition = newPosition;
+ }
+ }
+
+ private void updateTranslation(Position position, boolean animate) {
+ final int translationX = position.getTranslationX();
+ final int translationY = position.getTranslationY();
+
+ if (animate) {
+ mKeyButtonView
+ .animate()
+ .translationX(translationX)
+ .translationY(translationY)
+ .setDuration(MARGIN_ANIMATION_DURATION_MILLIS)
+ .setInterpolator(new AccelerateDecelerateInterpolator())
+ .withEndAction(() -> {
+ if (mUpdatesCallback != null && mIsShowing) {
+ mUpdatesCallback.onPositionChanged();
+ }
+ })
+ .start();
+ } else {
+ mKeyButtonView.setTranslationX(translationX);
+ mKeyButtonView.setTranslationY(translationY);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt
new file mode 100644
index 0000000000000..3ce51ad331c5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt
@@ -0,0 +1,65 @@
+package com.android.systemui.navigationbar.gestural
+
+import android.view.Gravity
+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(
+ private val defaultMargin: Int,
+ private val taskbarMarginLeft: Int,
+ private val taskbarMarginBottom: Int
+) {
+
+ fun calculatePosition(
+ currentRotation: Int,
+ taskbarVisible: Boolean,
+ taskbarStashed: Boolean
+ ): Position {
+
+ val isTaskbarSide = currentRotation == Surface.ROTATION_0
+ || currentRotation == Surface.ROTATION_90
+ val useTaskbarMargin = isTaskbarSide && taskbarVisible && !taskbarStashed
+
+ val gravity = resolveGravity(currentRotation)
+
+ val marginLeft = if (useTaskbarMargin) taskbarMarginLeft else defaultMargin
+ val marginBottom = if (useTaskbarMargin) taskbarMarginBottom else defaultMargin
+
+ val translationX =
+ if (gravity and Gravity.RIGHT == Gravity.RIGHT) {
+ -marginLeft
+ } else {
+ marginLeft
+ }
+ val translationY =
+ if (gravity and Gravity.BOTTOM == Gravity.BOTTOM) {
+ -marginBottom
+ } else {
+ marginBottom
+ }
+
+ return Position(
+ gravity = gravity,
+ translationX = translationX,
+ translationY = translationY
+ )
+ }
+
+ data class Position(
+ val gravity: Int,
+ val translationX: Int,
+ val translationY: Int
+ )
+
+ private fun resolveGravity(rotation: Int): Int =
+ when (rotation) {
+ Surface.ROTATION_0 -> Gravity.BOTTOM or Gravity.LEFT
+ Surface.ROTATION_90 -> Gravity.BOTTOM or Gravity.RIGHT
+ Surface.ROTATION_180 -> Gravity.TOP or Gravity.RIGHT
+ Surface.ROTATION_270 -> Gravity.TOP or Gravity.LEFT
+ else -> throw IllegalArgumentException("Invalid rotation $rotation")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 53259435da02f..da9d8882c0911 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -110,6 +110,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
+import java.util.function.Supplier;
import javax.inject.Inject;
@@ -172,55 +173,34 @@ public class OverviewProxyService extends CurrentUserTracker implements
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@Override
public void startScreenPinning(int taskId) {
- if (!verifyCaller("startScreenPinning")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
+ verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () ->
mStatusBarOptionalLazy.ifPresent(
statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId,
- false /* allowCancel */));
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ false /* allowCancel */)));
}
@Override
public void stopScreenPinning() {
- if (!verifyCaller("stopScreenPinning")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- try {
- ActivityTaskManager.getService().stopSystemLockTaskMode();
- } catch (RemoteException e) {
- Log.e(TAG_OPS, "Failed to stop screen pinning");
- }
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> {
+ try {
+ ActivityTaskManager.getService().stopSystemLockTaskMode();
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to stop screen pinning");
+ }
+ });
}
// TODO: change the method signature to use (boolean inputFocusTransferStarted)
@Override
public void onStatusBarMotionEvent(MotionEvent event) {
- if (!verifyCaller("onStatusBarMotionEvent")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
+ verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> {
// TODO move this logic to message queue
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
StatusBar statusBar = statusBarLazy.get();
if (event.getActionMasked() == ACTION_DOWN) {
statusBar.getPanelController().startExpandLatencyTracking();
}
- mHandler.post(()-> {
+ mHandler.post(() -> {
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true;
@@ -232,50 +212,38 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false;
+ float velocity = (event.getY() - mInputFocusTransferStartY)
+ / (event.getEventTime() - mInputFocusTransferStartMillis);
statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
action == ACTION_CANCEL,
- (event.getY() - mInputFocusTransferStartY)
- / (event.getEventTime() - mInputFocusTransferStartMillis));
+ velocity);
}
event.recycle();
});
});
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ });
}
@Override
public void onBackPressed() throws RemoteException {
- if (!verifyCaller("onBackPressed")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
- sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
+ verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
+ sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
+ sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
- notifyBackAction(true, -1, -1, true, false);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ notifyBackAction(true, -1, -1, true, false);
+ });
}
@Override
public void setHomeRotationEnabled(boolean enabled) {
- if (!verifyCaller("setHomeRotationEnabled")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- mHandler.post(() -> notifyHomeRotationEnabled(enabled));
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () ->
+ mHandler.post(() -> notifyHomeRotationEnabled(enabled)));
+ }
+
+ @Override
+ public void notifyTaskbarStatus(boolean visible, boolean stashed) {
+ verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () ->
+ onTaskbarStatusUpdated(visible, stashed));
}
private boolean sendEvent(int action, int code) {
@@ -292,124 +260,74 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void onOverviewShown(boolean fromHome) {
- if (!verifyCaller("onOverviewShown")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> {
- for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onOverviewShown(fromHome);
- }
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onOverviewShown(fromHome);
+ }
+ });
}
@Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
- if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
- return null;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- return mLegacySplitScreenOptional.map(splitScreen ->
- splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
- .orElse(null);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ return verifyCallerAndClearCallingIdentity(
+ "getNonMinimizedSplitScreenSecondaryBounds",
+ () -> mLegacySplitScreenOptional.map(splitScreen ->
+ splitScreen
+ .getDividerView()
+ .getNonMinimizedSplitScreenSecondaryBounds())
+ .orElse(null)
+ );
}
@Override
public void setNavBarButtonAlpha(float alpha, boolean animate) {
- if (!verifyCaller("setNavBarButtonAlpha")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mNavBarButtonAlpha = alpha;
- mHandler.post(() -> notifyNavBarButtonAlphaChanged(alpha, animate));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
+ notifyNavBarButtonAlphaChanged(alpha, animate));
}
@Override
public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
- if (!verifyCaller("onAssistantProgress")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyAssistantProgress(progress));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
+ notifyAssistantProgress(progress));
}
@Override
public void onAssistantGestureCompletion(float velocity) {
- if (!verifyCaller("onAssistantGestureCompletion")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyAssistantGestureCompletion(velocity));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () ->
+ notifyAssistantGestureCompletion(velocity));
}
@Override
public void startAssistant(Bundle bundle) {
- if (!verifyCaller("startAssistant")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyStartAssistant(bundle));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("startAssistant", () ->
+ notifyStartAssistant(bundle));
}
@Override
public void notifyAccessibilityButtonClicked(int displayId) {
- if (!verifyCaller("notifyAccessibilityButtonClicked")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- AccessibilityManager.getInstance(mContext)
- .notifyAccessibilityButtonClicked(displayId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () ->
+ AccessibilityManager.getInstance(mContext)
+ .notifyAccessibilityButtonClicked(displayId));
}
@Override
public void notifyAccessibilityButtonLongClicked() {
- if (!verifyCaller("notifyAccessibilityButtonLongClicked")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- final Intent intent =
- new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
- final String chooserClassName = AccessibilityButtonChooserActivity.class.getName();
- intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked",
+ () -> {
+ final Intent intent =
+ new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
+ final String chooserClassName = AccessibilityButtonChooserActivity
+ .class.getName();
+ intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ });
}
@Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
- Insets visibleInsets, int taskId) {
+ Insets visibleInsets, int taskId) {
// Deprecated
}
@@ -421,43 +339,22 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void notifySwipeToHomeFinished() {
- if (!verifyCaller("notifySwipeToHomeFinished")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mPipOptional.ifPresent(
- pip -> pip.setPinnedStackAnimationType(
- PipAnimationController.ANIM_TYPE_ALPHA));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () ->
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationType(
+ PipAnimationController.ANIM_TYPE_ALPHA)));
}
@Override
public void notifySwipeUpGestureStarted() {
- if (!verifyCaller("notifySwipeUpGestureStarted")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifySwipeUpGestureStartedInternal());
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () ->
+ notifySwipeUpGestureStartedInternal());
}
@Override
public void notifyPrioritizedRotation(@Surface.Rotation int rotation) {
- if (!verifyCaller("notifyPrioritizedRotation")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(() -> notifyPrioritizedRotationInternal(rotation));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () ->
+ notifyPrioritizedRotationInternal(rotation));
}
@Override
@@ -477,15 +374,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void expandNotificationPanel() {
- if (!verifyCaller("expandNotificationPanel")) {
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ verifyCallerAndClearCallingIdentity("expandNotificationPanel",
+ () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
}
private boolean verifyCaller(String reason) {
@@ -497,6 +387,29 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
return true;
}
+
+ private T verifyCallerAndClearCallingIdentity(String reason, Supplier supplier) {
+ if (!verifyCaller(reason)) {
+ return null;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return supplier.get();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) {
+ verifyCallerAndClearCallingIdentity(reason, () -> {
+ runnable.run();
+ return null;
+ });
+ }
+
+ private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) {
+ verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable));
+ }
};
private final Runnable mDeferredConnectionCallback = () -> {
@@ -883,6 +796,12 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
+ private void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed);
+ }
+ }
+
private void notifyConnectionChanged() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
@@ -1049,6 +968,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
/** Notify changes in the nav bar button alpha */
default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
default void onHomeRotationEnabled(boolean enabled) {}
+ default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
default void onSystemUiStateChanged(int sysuiStateFlags) {}
default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
default void onAssistantGestureCompletion(float velocity) {}
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 b9919767d63f8..a6ff2e8d2e153 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
@@ -59,7 +59,16 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
final View view = new View(mContext);
mRotationButton = mock(RotationButton.class);
mRotationButtonController = new RotationButtonController(mContext, 0, 0);
- mRotationButtonController.setRotationButton(mRotationButton, (visibility) -> {});
+ mRotationButtonController.setRotationButton(mRotationButton,
+ new RotationButton.RotationButtonUpdatesCallback() {
+ @Override
+ public void onVisibilityChanged(boolean isVisible) {
+ }
+
+ @Override
+ public void onPositionChanged() {
+ }
+ });
// Due to a mockito issue, only spy the object after setting the initial state
mRotationButtonController = spy(mRotationButtonController);
doReturn(view).when(mRotationButton).getCurrentView();
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
new file mode 100644
index 0000000000000..0a20001070530
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
@@ -0,0 +1,127 @@
+package com.android.systemui.navigationbar.gestural
+
+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.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@SmallTest
+internal class FloatingRotationButtonPositionCalculatorTest(private val testCase: TestCase)
+ : SysuiTestCase() {
+
+ private val calculator = FloatingRotationButtonPositionCalculator(
+ MARGIN_DEFAULT, MARGIN_TASKBAR_LEFT, MARGIN_TASKBAR_BOTTOM
+ )
+
+ @Test
+ fun calculatePosition() {
+ val position = calculator.calculatePosition(
+ testCase.rotation,
+ testCase.taskbarVisible,
+ testCase.taskbarStashed
+ )
+
+ assertThat(position).isEqualTo(testCase.expectedPosition)
+ }
+
+ internal class TestCase(
+ val rotation: Int,
+ val taskbarVisible: Boolean,
+ val taskbarStashed: Boolean,
+ val expectedPosition: Position
+ ) {
+ override fun toString(): String =
+ "when rotation = $rotation, " +
+ "taskbarVisible = $taskbarVisible, " +
+ "taskbarStashed = $taskbarStashed - " +
+ "expected $expectedPosition"
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection =
+ listOf(
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_90,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.RIGHT,
+ translationX = -MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_180,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.TOP or Gravity.RIGHT,
+ translationX = -MARGIN_DEFAULT,
+ translationY = MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_270,
+ taskbarVisible = false,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.TOP or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = true,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_TASKBAR_LEFT,
+ translationY = -MARGIN_TASKBAR_BOTTOM
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_0,
+ taskbarVisible = true,
+ taskbarStashed = true,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.LEFT,
+ translationX = MARGIN_DEFAULT,
+ translationY = -MARGIN_DEFAULT
+ )
+ ),
+ TestCase(
+ rotation = Surface.ROTATION_90,
+ taskbarVisible = true,
+ taskbarStashed = false,
+ expectedPosition = Position(
+ gravity = Gravity.BOTTOM or Gravity.RIGHT,
+ translationX = -MARGIN_TASKBAR_LEFT,
+ translationY = -MARGIN_TASKBAR_BOTTOM
+ )
+ )
+ )
+
+ private const val MARGIN_DEFAULT = 10
+ private const val MARGIN_TASKBAR_LEFT = 20
+ private const val MARGIN_TASKBAR_BOTTOM = 30
+ }
+}