Merge "Update rotation suggestion button position to align it with taskbar" into sc-v2-dev

This commit is contained in:
TreeHugger Robot
2021-07-14 10:59:26 +00:00
committed by Android (Google) Code Review
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 ~ See the License for the specific language governing permissions and
~ limitations under the License ~ limitations under the License
--> -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.systemui.navigationbar.buttons.KeyButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rotate_suggestion"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="0" >
android:scaleType="center"
android:visibility="invisible" <com.android.systemui.navigationbar.buttons.KeyButtonView
android:contentDescription="@string/accessibility_rotate_button" android:id="@+id/rotate_suggestion"
android:paddingStart="@dimen/navigation_key_padding" android:layout_width="@dimen/floating_rotation_button_diameter"
android:paddingEnd="@dimen/navigation_key_padding" 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> <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_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 --> <!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen> <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 */ /** Notifies that a swipe-up gesture has started */
oneway void notifySwipeUpGestureStarted() = 46; 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(); mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
} }
@Override
public void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
mNavigationBarView
.getFloatingRotationButton()
.onTaskbarStateChanged(visible, stashed);
}
@Override @Override
public void onToggleRecentApps() { public void onToggleRecentApps() {
// The same case as onOverviewShown but only for 3-button navigation. // 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.R;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState; 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.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton; import com.android.systemui.navigationbar.buttons.ContextualButton;
import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; import com.android.systemui.navigationbar.buttons.ContextualButtonGroup;
@@ -275,14 +276,23 @@ public class NavigationBarView extends FrameLayout implements
false /* inScreen */, false /* useNearestRegion */)); false /* inScreen */, false /* useNearestRegion */));
}; };
private final Consumer<Boolean> mRotationButtonListener = (visible) -> { private final RotationButtonUpdatesCallback mRotationButtonListener =
if (visible) { new RotationButtonUpdatesCallback() {
// If the button will actually become visible and the navbar is about to hide, @Override
// tell the statusbar to keep it around for longer public void onVisibilityChanged(boolean visible) {
mAutoHideController.touchAutoHide(); if (visible) {
} // If the button will actually become visible and the navbar is about
notifyActiveTouchRegions(); // 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) -> { private final Consumer<Boolean> mNavbarOverlayVisibilityChangeCallback = (visible) -> {
if (visible) { if (visible) {

View File

@@ -20,12 +20,10 @@ import android.view.View;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import java.util.function.Consumer;
/** Interface of a rotation button that interacts {@link RotationButtonController}. */ /** Interface of a rotation button that interacts {@link RotationButtonController}. */
public interface RotationButton { public interface RotationButton {
void setRotationButtonController(RotationButtonController rotationButtonController); void setRotationButtonController(RotationButtonController rotationButtonController);
void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback); void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback);
View getCurrentView(); View getCurrentView();
boolean show(); boolean show();
boolean hide(); boolean hide();
@@ -39,4 +37,12 @@ public interface RotationButton {
default boolean acceptRotationProposal() { default boolean acceptRotationProposal() {
return getCurrentView() != null; 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.Dependency;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.utilities.ViewRippler; import com.android.systemui.shared.recents.utilities.ViewRippler;
@@ -140,12 +141,12 @@ public class RotationButtonController {
} }
void setRotationButton(RotationButton rotationButton, void setRotationButton(RotationButton rotationButton,
Consumer<Boolean> visibilityChangedCallback) { RotationButtonUpdatesCallback updatesCallback) {
mRotationButton = rotationButton; mRotationButton = rotationButton;
mRotationButton.setRotationButtonController(this); mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick); mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
mRotationButton.setOnHoverListener(this::onRotateSuggestionHover); mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback); mRotationButton.setUpdatesCallback(updatesCallback);
} }
void registerListeners() { void registerListeners() {

View File

@@ -23,10 +23,6 @@ import android.view.View;
import com.android.systemui.navigationbar.RotationButton; import com.android.systemui.navigationbar.RotationButton;
import com.android.systemui.navigationbar.RotationButtonController; 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. */ /** Containing logic for the rotation button in nav bar. */
public class RotationContextButton extends ContextualButton implements RotationButton { public class RotationContextButton extends ContextualButton implements RotationButton {
@@ -48,13 +44,10 @@ public class RotationContextButton extends ContextualButton implements RotationB
} }
@Override @Override
public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
setListener(new ContextButtonListener() { setListener((button, visible) -> {
@Override if (updatesCallback != null) {
public void onVisibilityChanged(ContextualButton button, boolean visible) { updatesCallback.onVisibilityChanged(visible);
if (visibilityChangedCallback != null) {
visibilityChangedCallback.accept(visible);
}
} }
}); });
} }

View File

@@ -20,48 +20,72 @@ import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.navigationbar.RotationButton; import com.android.systemui.navigationbar.RotationButton;
import com.android.systemui.navigationbar.RotationButtonController; import com.android.systemui.navigationbar.RotationButtonController;
import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.navigationbar.buttons.KeyButtonView; 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 { public class FloatingRotationButton implements RotationButton {
private static final float BACKGROUND_ALPHA = 0.92f; 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 WindowManager mWindowManager;
private final ViewGroup mKeyButtonContainer;
private final KeyButtonView mKeyButtonView; private final KeyButtonView mKeyButtonView;
private final int mDiameter;
private final int mMargin; private final int mContainerSize;
private KeyButtonDrawable mKeyButtonDrawable; private KeyButtonDrawable mKeyButtonDrawable;
private boolean mIsShowing; private boolean mIsShowing;
private boolean mCanShow = true; private boolean mCanShow = true;
private int mDisplayRotation;
private boolean mIsTaskbarVisible = false;
private boolean mIsTaskbarStashed = false;
private final FloatingRotationButtonPositionCalculator mPositionCalculator;
private RotationButtonController mRotationButtonController; private RotationButtonController mRotationButtonController;
private Consumer<Boolean> mVisibilityChangedCallback; private RotationButtonUpdatesCallback mUpdatesCallback;
private Position mPosition;
public FloatingRotationButton(Context context) { public FloatingRotationButton(Context context) {
mContext = context; mWindowManager = context.getSystemService(WindowManager.class);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(
mKeyButtonView = (KeyButtonView) LayoutInflater.from(mContext).inflate(
R.layout.rotate_suggestion, null); R.layout.rotate_suggestion, null);
mKeyButtonView = mKeyButtonContainer.findViewById(R.id.rotate_suggestion);
mKeyButtonView.setVisibility(View.VISIBLE); mKeyButtonView.setVisibility(View.VISIBLE);
Resources res = mContext.getResources(); Resources res = context.getResources();
mDiameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
mMargin = Math.max(res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin), int defaultMargin = Math.max(
res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
res.getDimensionPixelSize(R.dimen.rounded_corner_content_padding)); 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 @Override
@@ -72,8 +96,8 @@ public class FloatingRotationButton implements RotationButton {
} }
@Override @Override
public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { public void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) {
mVisibilityChangedCallback = visibilityChangedCallback; mUpdatesCallback = updatesCallback;
} }
@Override @Override
@@ -86,45 +110,39 @@ public class FloatingRotationButton implements RotationButton {
if (!mCanShow || mIsShowing) { if (!mCanShow || mIsShowing) {
return false; return false;
} }
mIsShowing = true; mIsShowing = true;
int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(mDiameter, mDiameter, final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mMargin, mMargin, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags, mContainerSize,
mContainerSize,
0, 0, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, flags,
PixelFormat.TRANSLUCENT); PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("FloatingRotationButton"); lp.setTitle("FloatingRotationButton");
lp.setFitInsetsTypes(0 /*types */); lp.setFitInsetsTypes(0 /*types */);
switch (mWindowManager.getDefaultDisplay().getRotation()) {
case Surface.ROTATION_0: mDisplayRotation = mWindowManager.getDefaultDisplay().getRotation();
lp.gravity = Gravity.BOTTOM | Gravity.LEFT; mPosition = mPositionCalculator
break; .calculatePosition(mDisplayRotation, mIsTaskbarVisible, mIsTaskbarStashed);
case Surface.ROTATION_90:
lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; lp.gravity = mPosition.getGravity();
break; ((FrameLayout.LayoutParams) mKeyButtonView.getLayoutParams()).gravity =
case Surface.ROTATION_180: mPosition.getGravity();
lp.gravity = Gravity.TOP | Gravity.RIGHT;
break; updateTranslation(mPosition, /* animate */ false);
case Surface.ROTATION_270:
lp.gravity = Gravity.TOP | Gravity.LEFT; mWindowManager.addView(mKeyButtonContainer, lp);
break;
default:
break;
}
mWindowManager.addView(mKeyButtonView, lp);
if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) { if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) {
mKeyButtonDrawable.resetAnimation(); mKeyButtonDrawable.resetAnimation();
mKeyButtonDrawable.startAnimation(); mKeyButtonDrawable.startAnimation();
} }
mKeyButtonView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override if (mUpdatesCallback != null) {
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, mUpdatesCallback.onVisibilityChanged(true);
int i6, int i7) { }
if (mIsShowing && mVisibilityChangedCallback != null) {
mVisibilityChangedCallback.accept(true);
}
mKeyButtonView.removeOnLayoutChangeListener(this);
}
});
return true; return true;
} }
@@ -133,10 +151,10 @@ public class FloatingRotationButton implements RotationButton {
if (!mIsShowing) { if (!mIsShowing) {
return false; return false;
} }
mWindowManager.removeViewImmediate(mKeyButtonView); mWindowManager.removeViewImmediate(mKeyButtonContainer);
mIsShowing = false; mIsShowing = false;
if (mVisibilityChangedCallback != null) { if (mUpdatesCallback != null) {
mVisibilityChangedCallback.accept(false); mUpdatesCallback.onVisibilityChanged(false);
} }
return true; return true;
} }
@@ -183,4 +201,43 @@ public class FloatingRotationButton implements RotationButton {
hide(); 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.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;
import javax.inject.Inject; import javax.inject.Inject;
@@ -172,55 +173,34 @@ public class OverviewProxyService extends CurrentUserTracker implements
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() { public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@Override @Override
public void startScreenPinning(int taskId) { public void startScreenPinning(int taskId) {
if (!verifyCaller("startScreenPinning")) { verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () ->
return;
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
mStatusBarOptionalLazy.ifPresent( mStatusBarOptionalLazy.ifPresent(
statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId, statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId,
false /* allowCancel */)); false /* allowCancel */)));
});
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void stopScreenPinning() { public void stopScreenPinning() {
if (!verifyCaller("stopScreenPinning")) { verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> {
return; try {
} ActivityTaskManager.getService().stopSystemLockTaskMode();
final long token = Binder.clearCallingIdentity(); } catch (RemoteException e) {
try { Log.e(TAG_OPS, "Failed to stop screen pinning");
mHandler.post(() -> { }
try { });
ActivityTaskManager.getService().stopSystemLockTaskMode();
} catch (RemoteException e) {
Log.e(TAG_OPS, "Failed to stop screen pinning");
}
});
} finally {
Binder.restoreCallingIdentity(token);
}
} }
// TODO: change the method signature to use (boolean inputFocusTransferStarted) // TODO: change the method signature to use (boolean inputFocusTransferStarted)
@Override @Override
public void onStatusBarMotionEvent(MotionEvent event) { public void onStatusBarMotionEvent(MotionEvent event) {
if (!verifyCaller("onStatusBarMotionEvent")) { verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> {
return;
}
final long token = Binder.clearCallingIdentity();
try {
// TODO move this logic to message queue // TODO move this logic to message queue
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> { mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
StatusBar statusBar = statusBarLazy.get(); StatusBar statusBar = statusBarLazy.get();
if (event.getActionMasked() == ACTION_DOWN) { if (event.getActionMasked() == ACTION_DOWN) {
statusBar.getPanelController().startExpandLatencyTracking(); statusBar.getPanelController().startExpandLatencyTracking();
} }
mHandler.post(()-> { mHandler.post(() -> {
int action = event.getActionMasked(); int action = event.getActionMasked();
if (action == ACTION_DOWN) { if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true; mInputFocusTransferStarted = true;
@@ -232,50 +212,38 @@ public class OverviewProxyService extends CurrentUserTracker implements
} }
if (action == ACTION_UP || action == ACTION_CANCEL) { if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false; mInputFocusTransferStarted = false;
float velocity = (event.getY() - mInputFocusTransferStartY)
/ (event.getEventTime() - mInputFocusTransferStartMillis);
statusBar.onInputFocusTransfer(mInputFocusTransferStarted, statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
action == ACTION_CANCEL, action == ACTION_CANCEL,
(event.getY() - mInputFocusTransferStartY) velocity);
/ (event.getEventTime() - mInputFocusTransferStartMillis));
} }
event.recycle(); event.recycle();
}); });
}); });
} finally { });
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void onBackPressed() throws RemoteException { public void onBackPressed() throws RemoteException {
if (!verifyCaller("onBackPressed")) { verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
return; sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
} sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
notifyBackAction(true, -1, -1, true, false); notifyBackAction(true, -1, -1, true, false);
}); });
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void setHomeRotationEnabled(boolean enabled) { public void setHomeRotationEnabled(boolean enabled) {
if (!verifyCaller("setHomeRotationEnabled")) { verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () ->
return; mHandler.post(() -> notifyHomeRotationEnabled(enabled)));
} }
final long token = Binder.clearCallingIdentity();
try { @Override
mHandler.post(() -> { public void notifyTaskbarStatus(boolean visible, boolean stashed) {
mHandler.post(() -> notifyHomeRotationEnabled(enabled)); verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () ->
}); onTaskbarStatusUpdated(visible, stashed));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
private boolean sendEvent(int action, int code) { private boolean sendEvent(int action, int code) {
@@ -292,124 +260,74 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override @Override
public void onOverviewShown(boolean fromHome) { public void onOverviewShown(boolean fromHome) {
if (!verifyCaller("onOverviewShown")) { verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> {
return; for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
} mConnectionCallbacks.get(i).onOverviewShown(fromHome);
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);
}
} }
@Override @Override
public Rect getNonMinimizedSplitScreenSecondaryBounds() { public Rect getNonMinimizedSplitScreenSecondaryBounds() {
if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) { return verifyCallerAndClearCallingIdentity(
return null; "getNonMinimizedSplitScreenSecondaryBounds",
} () -> mLegacySplitScreenOptional.map(splitScreen ->
final long token = Binder.clearCallingIdentity(); splitScreen
try { .getDividerView()
return mLegacySplitScreenOptional.map(splitScreen -> .getNonMinimizedSplitScreenSecondaryBounds())
splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds()) .orElse(null)
.orElse(null); );
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void setNavBarButtonAlpha(float alpha, boolean animate) { public void setNavBarButtonAlpha(float alpha, boolean animate) {
if (!verifyCaller("setNavBarButtonAlpha")) { verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
return; notifyNavBarButtonAlphaChanged(alpha, animate));
}
final long token = Binder.clearCallingIdentity();
try {
mNavBarButtonAlpha = alpha;
mHandler.post(() -> notifyNavBarButtonAlphaChanged(alpha, animate));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) { public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
if (!verifyCaller("onAssistantProgress")) { verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
return; notifyAssistantProgress(progress));
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyAssistantProgress(progress));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void onAssistantGestureCompletion(float velocity) { public void onAssistantGestureCompletion(float velocity) {
if (!verifyCaller("onAssistantGestureCompletion")) { verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () ->
return; notifyAssistantGestureCompletion(velocity));
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyAssistantGestureCompletion(velocity));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void startAssistant(Bundle bundle) { public void startAssistant(Bundle bundle) {
if (!verifyCaller("startAssistant")) { verifyCallerAndClearCallingIdentityPostMain("startAssistant", () ->
return; notifyStartAssistant(bundle));
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyStartAssistant(bundle));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void notifyAccessibilityButtonClicked(int displayId) { public void notifyAccessibilityButtonClicked(int displayId) {
if (!verifyCaller("notifyAccessibilityButtonClicked")) { verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () ->
return; AccessibilityManager.getInstance(mContext)
} .notifyAccessibilityButtonClicked(displayId));
final long token = Binder.clearCallingIdentity();
try {
AccessibilityManager.getInstance(mContext)
.notifyAccessibilityButtonClicked(displayId);
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void notifyAccessibilityButtonLongClicked() { public void notifyAccessibilityButtonLongClicked() {
if (!verifyCaller("notifyAccessibilityButtonLongClicked")) { verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked",
return; () -> {
} final Intent intent =
final long token = Binder.clearCallingIdentity(); new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
try { final String chooserClassName = AccessibilityButtonChooserActivity
final Intent intent = .class.getName();
new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
final String chooserClassName = AccessibilityButtonChooserActivity.class.getName(); intent.addFlags(
intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); mContext.startActivityAsUser(intent, UserHandle.CURRENT);
mContext.startActivityAsUser(intent, UserHandle.CURRENT); });
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen, public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
Insets visibleInsets, int taskId) { Insets visibleInsets, int taskId) {
// Deprecated // Deprecated
} }
@@ -421,43 +339,22 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override @Override
public void notifySwipeToHomeFinished() { public void notifySwipeToHomeFinished() {
if (!verifyCaller("notifySwipeToHomeFinished")) { verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () ->
return; mPipOptional.ifPresent(
} pip -> pip.setPinnedStackAnimationType(
final long token = Binder.clearCallingIdentity(); PipAnimationController.ANIM_TYPE_ALPHA)));
try {
mPipOptional.ifPresent(
pip -> pip.setPinnedStackAnimationType(
PipAnimationController.ANIM_TYPE_ALPHA));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void notifySwipeUpGestureStarted() { public void notifySwipeUpGestureStarted() {
if (!verifyCaller("notifySwipeUpGestureStarted")) { verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () ->
return; notifySwipeUpGestureStartedInternal());
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifySwipeUpGestureStartedInternal());
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
public void notifyPrioritizedRotation(@Surface.Rotation int rotation) { public void notifyPrioritizedRotation(@Surface.Rotation int rotation) {
if (!verifyCaller("notifyPrioritizedRotation")) { verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () ->
return; notifyPrioritizedRotationInternal(rotation));
}
final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyPrioritizedRotationInternal(rotation));
} finally {
Binder.restoreCallingIdentity(token);
}
} }
@Override @Override
@@ -477,15 +374,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override @Override
public void expandNotificationPanel() { public void expandNotificationPanel() {
if (!verifyCaller("expandNotificationPanel")) { verifyCallerAndClearCallingIdentity("expandNotificationPanel",
return; () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
}
final long token = Binder.clearCallingIdentity();
try {
mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
} finally {
Binder.restoreCallingIdentity(token);
}
} }
private boolean verifyCaller(String reason) { private boolean verifyCaller(String reason) {
@@ -497,6 +387,29 @@ public class OverviewProxyService extends CurrentUserTracker implements
} }
return true; 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 = () -> { 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() { private void notifyConnectionChanged() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null); mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
@@ -1049,6 +968,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
/** Notify changes in the nav bar button alpha */ /** Notify changes in the nav bar button alpha */
default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {} default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
default void onHomeRotationEnabled(boolean enabled) {} default void onHomeRotationEnabled(boolean enabled) {}
default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
default void onSystemUiStateChanged(int sysuiStateFlags) {} default void onSystemUiStateChanged(int sysuiStateFlags) {}
default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {} default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
default void onAssistantGestureCompletion(float velocity) {} default void onAssistantGestureCompletion(float velocity) {}

View File

@@ -59,7 +59,16 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
final View view = new View(mContext); final View view = new View(mContext);
mRotationButton = mock(RotationButton.class); mRotationButton = mock(RotationButton.class);
mRotationButtonController = new RotationButtonController(mContext, 0, 0); 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 // Due to a mockito issue, only spy the object after setting the initial state
mRotationButtonController = spy(mRotationButtonController); mRotationButtonController = spy(mRotationButtonController);
doReturn(view).when(mRotationButton).getCurrentView(); 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
}
}