Merge "Update rotation suggestion button position to align it with taskbar" into sc-v2-dev am: ecff0245a7 am: 1996fcf26b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15095931

Change-Id: Ic93ee74fa8bb4c37c9e7d7854e536089927171c0
This commit is contained in:
TreeHugger Robot
2021-07-14 11:27:30 +00:00
committed by Automerger Merge Worker
13 changed files with 475 additions and 272 deletions

View File

@@ -14,16 +14,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<com.android.systemui.navigationbar.buttons.KeyButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rotate_suggestion"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0"
android:scaleType="center"
android:visibility="invisible"
android:contentDescription="@string/accessibility_rotate_button"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
>
<com.android.systemui.navigationbar.buttons.KeyButtonView
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>

View File

@@ -62,7 +62,9 @@
<item name="navigation_luminance_change_threshold" type="dimen" format="float">0.05</item>
<dimen name="floating_rotation_button_diameter">40dp</dimen>
<dimen name="floating_rotation_button_min_margin">4dp</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>

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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<Boolean> 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<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> {
if (visible) {

View File

@@ -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<Boolean> 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();
}
}

View File

@@ -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<Boolean> visibilityChangedCallback) {
RotationButtonUpdatesCallback updatesCallback) {
mRotationButton = rotationButton;
mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback);
mRotationButton.setUpdatesCallback(updatesCallback);
}
void registerListeners() {

View File

@@ -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<Boolean> 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);
}
});
}

View File

@@ -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<Boolean> 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<Boolean> 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);
}
}
}

View File

@@ -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")
}
}

View File

@@ -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> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> 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) {}

View File

@@ -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();

View File

@@ -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<TestCase> =
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
}
}