Merge "Support mouse pointer on external displays (2/2)"

This commit is contained in:
TreeHugger Robot
2019-01-10 11:29:48 +00:00
committed by Android (Google) Code Review
7 changed files with 206 additions and 114 deletions

View File

@@ -89,10 +89,6 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
mLocked.animationPending = false;
mLocked.displayWidth = -1;
mLocked.displayHeight = -1;
mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
mLocked.presentation = PRESENTATION_POINTER;
mLocked.presentationChanged = false;
@@ -110,15 +106,6 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>&
mLocked.lastFrameUpdatedTime = 0;
mLocked.buttonState = 0;
mPolicy->loadPointerIcon(&mLocked.pointerIcon);
loadResources();
if (mLocked.pointerIcon.isValid()) {
mLocked.pointerIconChanged = true;
updatePointerLocked();
}
}
PointerController::~PointerController() {
@@ -144,23 +131,15 @@ bool PointerController::getBounds(float* outMinX, float* outMinY,
bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const {
if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
if (!mLocked.viewport.isValid()) {
return false;
}
*outMinX = 0;
*outMinY = 0;
switch (mLocked.displayOrientation) {
case DISPLAY_ORIENTATION_90:
case DISPLAY_ORIENTATION_270:
*outMaxX = mLocked.displayHeight - 1;
*outMaxY = mLocked.displayWidth - 1;
break;
default:
*outMaxX = mLocked.displayWidth - 1;
*outMaxY = mLocked.displayHeight - 1;
break;
}
*outMinX = mLocked.viewport.logicalLeft;
*outMinY = mLocked.viewport.logicalTop;
*outMaxX = mLocked.viewport.logicalRight - 1;
*outMaxY = mLocked.viewport.logicalBottom - 1;
return true;
}
@@ -231,6 +210,12 @@ void PointerController::getPosition(float* outX, float* outY) const {
*outY = mLocked.pointerY;
}
int32_t PointerController::getDisplayId() const {
AutoMutex _l(mLock);
return mLocked.viewport.displayId;
}
void PointerController::fade(Transition transition) {
AutoMutex _l(mLock);
@@ -355,48 +340,56 @@ void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout
void PointerController::reloadPointerResources() {
AutoMutex _l(mLock);
loadResources();
if (mLocked.presentation == PRESENTATION_POINTER) {
mLocked.additionalMouseResources.clear();
mLocked.animationResources.clear();
mPolicy->loadPointerIcon(&mLocked.pointerIcon);
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources);
}
mLocked.presentationChanged = true;
loadResourcesLocked();
updatePointerLocked();
}
void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
AutoMutex _l(mLock);
/**
* The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
* so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
*/
static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
width = viewport.deviceWidth;
height = viewport.deviceHeight;
// Adjust to use the display's unrotated coordinate frame.
if (orientation == DISPLAY_ORIENTATION_90
|| orientation == DISPLAY_ORIENTATION_270) {
int32_t temp = height;
height = width;
width = temp;
if (viewport.orientation == DISPLAY_ORIENTATION_90
|| viewport.orientation == DISPLAY_ORIENTATION_270) {
std::swap(width, height);
}
}
void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
AutoMutex _l(mLock);
if (viewport == mLocked.viewport) {
return;
}
if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
mLocked.displayWidth = width;
mLocked.displayHeight = height;
const DisplayViewport oldViewport = mLocked.viewport;
mLocked.viewport = viewport;
int32_t oldDisplayWidth, oldDisplayHeight;
getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
int32_t newDisplayWidth, newDisplayHeight;
getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
// Reset cursor position to center if size or display changed.
if (oldViewport.displayId != viewport.displayId
|| oldDisplayWidth != newDisplayWidth
|| oldDisplayHeight != newDisplayHeight) {
float minX, minY, maxX, maxY;
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
mLocked.pointerX = (minX + maxX) * 0.5f;
mLocked.pointerY = (minY + maxY) * 0.5f;
// Reload icon resources for density may be changed.
loadResourcesLocked();
} else {
mLocked.pointerX = 0;
mLocked.pointerY = 0;
}
fadeOutAndReleaseAllSpotsLocked();
}
if (mLocked.displayOrientation != orientation) {
} else if (oldViewport.orientation != viewport.orientation) {
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
// This creates an invariant frame of reference that we can easily rotate when
// taking into account that the pointer may be located at fractional pixel offsets.
@@ -405,37 +398,37 @@ void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_
float temp;
// Undo the previous rotation.
switch (mLocked.displayOrientation) {
switch (oldViewport.orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = mLocked.displayWidth - y;
x = oldViewport.deviceHeight - y;
y = temp;
break;
case DISPLAY_ORIENTATION_180:
x = mLocked.displayWidth - x;
y = mLocked.displayHeight - y;
x = oldViewport.deviceWidth - x;
y = oldViewport.deviceHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
x = y;
y = mLocked.displayHeight - temp;
y = oldViewport.deviceWidth - temp;
break;
}
// Perform the new rotation.
switch (orientation) {
switch (viewport.orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = y;
y = mLocked.displayWidth - temp;
y = viewport.deviceHeight - temp;
break;
case DISPLAY_ORIENTATION_180:
x = mLocked.displayWidth - x;
y = mLocked.displayHeight - y;
x = viewport.deviceWidth - x;
y = viewport.deviceHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
x = mLocked.displayHeight - y;
x = viewport.deviceWidth - y;
y = temp;
break;
}
@@ -444,7 +437,6 @@ void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_
// and save the results.
mLocked.pointerX = x - 0.5f;
mLocked.pointerY = y - 0.5f;
mLocked.displayOrientation = orientation;
}
updatePointerLocked();
@@ -614,11 +606,16 @@ void PointerController::removeInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
}
void PointerController::updatePointerLocked() {
void PointerController::updatePointerLocked() REQUIRES(mLock) {
if (!mLocked.viewport.isValid()) {
return;
}
mSpriteController->openTransaction();
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
if (mLocked.pointerAlpha > 0) {
mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
@@ -729,8 +726,18 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() {
}
}
void PointerController::loadResources() {
void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mPolicy->loadPointerResources(&mResources);
if (mLocked.presentation == PRESENTATION_POINTER) {
mLocked.additionalMouseResources.clear();
mLocked.animationResources.clear();
mPolicy->loadPointerIcon(&mLocked.pointerIcon);
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources);
}
mLocked.pointerIconChanged = true;
}

View File

@@ -23,6 +23,7 @@
#include <vector>
#include <ui/DisplayInfo.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <PointerControllerInterface.h>
#include <utils/BitSet.h>
@@ -96,6 +97,7 @@ public:
virtual int32_t getButtonState() const;
virtual void setPosition(float x, float y);
virtual void getPosition(float* outX, float* outY) const;
virtual int32_t getDisplayId() const;
virtual void fade(Transition transition);
virtual void unfade(Transition transition);
@@ -106,7 +108,7 @@ public:
void updatePointerIcon(int32_t iconId);
void setCustomPointerIcon(const SpriteIcon& icon);
void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
void setDisplayViewport(const DisplayViewport& viewport);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void reloadPointerResources();
@@ -156,9 +158,7 @@ private:
size_t animationFrameIndex;
nsecs_t lastFrameUpdatedTime;
int32_t displayWidth;
int32_t displayHeight;
int32_t displayOrientation;
DisplayViewport viewport;
InactivityTimeout inactivityTimeout;
@@ -182,7 +182,7 @@ private:
Vector<Spot*> spots;
Vector<sp<Sprite> > recycledSprites;
} mLocked;
} mLocked GUARDED_BY(mLock);
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
@@ -207,7 +207,7 @@ private:
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
void loadResources();
void loadResourcesLocked();
};
} // namespace android

View File

@@ -144,13 +144,16 @@ void SpriteController::doUpdateSprites() {
}
}
// Resize sprites if needed.
// Resize and/or reparent sprites if needed.
SurfaceComposerClient::Transaction t;
bool needApplyTransaction = false;
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
if (update.state.surfaceControl == nullptr) {
continue;
}
if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
if (update.state.wantSurfaceVisible()) {
int32_t desiredWidth = update.state.icon.bitmap.width();
int32_t desiredHeight = update.state.icon.bitmap.height();
if (update.state.surfaceWidth < desiredWidth
@@ -170,6 +173,12 @@ void SpriteController::doUpdateSprites() {
}
}
}
// If surface is a new one, we have to set right layer stack.
if (update.surfaceChanged || update.state.dirty & DIRTY_DISPLAY_ID) {
t.setLayerStack(update.state.surfaceControl, update.state.displayId);
needApplyTransaction = true;
}
}
if (needApplyTransaction) {
t.apply();
@@ -236,7 +245,7 @@ void SpriteController::doUpdateSprites() {
if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
|| (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
| DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
| DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
| DIRTY_VISIBILITY | DIRTY_HOTSPOT | DIRTY_DISPLAY_ID))))) {
needApplyTransaction = true;
if (wantSurfaceVisibleAndDrawn
@@ -445,6 +454,15 @@ void SpriteController::SpriteImpl::setTransformationMatrix(
}
}
void SpriteController::SpriteImpl::setDisplayId(int32_t displayId) {
AutoMutex _l(mController->mLock);
if (mLocked.state.displayId != displayId) {
mLocked.state.displayId = displayId;
invalidateLocked(DIRTY_DISPLAY_ID);
}
}
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
bool wasDirty = mLocked.state.dirty;
mLocked.state.dirty |= dirty;

View File

@@ -125,6 +125,9 @@ public:
/* Sets the sprite transformation matrix. */
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
/* Sets the id of the display where the sprite should be shown. */
virtual void setDisplayId(int32_t displayId) = 0;
};
/*
@@ -170,6 +173,7 @@ private:
DIRTY_LAYER = 1 << 4,
DIRTY_VISIBILITY = 1 << 5,
DIRTY_HOTSPOT = 1 << 6,
DIRTY_DISPLAY_ID = 1 << 7,
};
/* Describes the state of a sprite.
@@ -180,7 +184,7 @@ private:
struct SpriteState {
inline SpriteState() :
dirty(0), visible(false),
positionX(0), positionY(0), layer(0), alpha(1.0f),
positionX(0), positionY(0), layer(0), alpha(1.0f), displayId(ADISPLAY_ID_DEFAULT),
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
}
@@ -193,6 +197,7 @@ private:
int32_t layer;
float alpha;
SpriteTransformationMatrix transformationMatrix;
int32_t displayId;
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth;
@@ -225,6 +230,7 @@ private:
virtual void setLayer(int32_t layer);
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
virtual void setDisplayId(int32_t displayId);
inline const SpriteState& getStateLocked() const {
return mLocked.state;

View File

@@ -1950,6 +1950,11 @@ public class InputManagerService extends IInputManager.Stub
return PointerIcon.getDefaultIcon(mContext);
}
// Native callback.
private int getPointerDisplayId() {
return mWindowManagerCallbacks.getPointerDisplayId();
}
// Native callback.
private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
if (!mSystemReady) {
@@ -2017,6 +2022,8 @@ public class InputManagerService extends IInputManager.Stub
KeyEvent event, int policyFlags);
public int getPointerLayer();
public int getPointerDisplayId();
}
/**

View File

@@ -1,5 +1,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -9,7 +10,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.os.Debug;
import android.os.IBinder;
import android.util.Slog;
import android.view.InputApplicationHandle;
import android.view.KeyEvent;
import android.view.WindowManager;
@@ -204,6 +204,37 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
+ WindowManagerService.TYPE_LAYER_OFFSET;
}
/** Callback to get pointer display id. */
@Override
public int getPointerDisplayId() {
synchronized (mService.mGlobalLock) {
// If desktop mode is not enabled, show on the default display.
if (!mService.mForceDesktopModeOnExternalDisplays) {
return DEFAULT_DISPLAY;
}
// Look for the topmost freeform display.
int firstExternalDisplayId = DEFAULT_DISPLAY;
for (int i = mService.mRoot.mChildren.size() - 1; i >= 0; --i) {
final DisplayContent displayContent = mService.mRoot.mChildren.get(i);
// Heuristic solution here. Currently when "Freeform windows" developer option is
// enabled we automatically put secondary displays in freeform mode and emulating
// "desktop mode". It also makes sense to show the pointer on the same display.
if (displayContent.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
return displayContent.getDisplayId();
}
if (firstExternalDisplayId == DEFAULT_DISPLAY
&& displayContent.getDisplayId() != DEFAULT_DISPLAY) {
firstExternalDisplayId = displayContent.getDisplayId();
}
}
// Look for the topmost non-default display
return firstExternalDisplayId;
}
}
/** Waits until the built-in input devices have been configured. */
public boolean waitForInputDevicesReady(long timeoutMillis) {
synchronized (mInputDevicesReadyMonitor) {

View File

@@ -107,6 +107,7 @@ static struct {
jmethodID getLongPressTimeout;
jmethodID getPointerLayer;
jmethodID getPointerIcon;
jmethodID getPointerDisplayId;
jmethodID getKeyboardLayoutOverlay;
jmethodID getDeviceAlias;
jmethodID getTouchCalibrationForInputDevice;
@@ -174,15 +175,6 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl
loadSystemIconAsSpriteWithPointerIcon(env, contextObj, style, &pointerIcon, outSpriteIcon);
}
static void updatePointerControllerFromViewport(
sp<PointerController> controller, const DisplayViewport* const viewport) {
if (controller != nullptr && viewport != nullptr) {
const int32_t width = viewport->logicalRight - viewport->logicalLeft;
const int32_t height = viewport->logicalBottom - viewport->logicalTop;
controller->setDisplayViewport(width, height, viewport->orientation);
}
}
enum {
WM_ACTION_PASS_TO_USER = 1,
};
@@ -310,14 +302,19 @@ private:
// Input devices to be disabled
SortedVector<int32_t> disabledInputDevices;
// Associated Pointer controller display.
int32_t pointerDisplayId;
} mLocked GUARDED_BY(mLock);
std::atomic<bool> mInteractive;
void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
void updateInactivityTimeoutLocked();
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
void ensureSpriteControllerLocked();
const DisplayViewport* findDisplayViewportLocked(int32_t displayId);
int32_t getPointerDisplayId();
void updatePointerDisplayLocked();
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
static inline JNIEnv* jniEnv() {
@@ -342,6 +339,7 @@ NativeInputManager::NativeInputManager(jobject contextObj,
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
@@ -391,9 +389,10 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c
return false;
}
static const DisplayViewport* findInternalViewport(const std::vector<DisplayViewport>& viewports) {
for (const DisplayViewport& v : viewports) {
if (v.type == ViewportType::VIEWPORT_INTERNAL) {
const DisplayViewport* NativeInputManager::findDisplayViewportLocked(int32_t displayId)
REQUIRES(mLock) {
for (const DisplayViewport& v : mLocked.viewports) {
if (v.displayId == displayId) {
return &v;
}
}
@@ -420,20 +419,14 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO
}
}
const DisplayViewport* newInternalViewport = findInternalViewport(viewports);
{
// Get the preferred pointer controller displayId.
int32_t pointerDisplayId = getPointerDisplayId();
{ // acquire lock
AutoMutex _l(mLock);
const DisplayViewport* oldInternalViewport = findInternalViewport(mLocked.viewports);
// Internal viewport has changed if there wasn't one earlier, and there is one now, or,
// if they are different.
const bool internalViewportChanged = (newInternalViewport != nullptr) &&
(oldInternalViewport == nullptr || (*oldInternalViewport != *newInternalViewport));
if (internalViewportChanged) {
sp<PointerController> controller = mLocked.pointerController.promote();
updatePointerControllerFromViewport(controller, newInternalViewport);
}
mLocked.viewports = viewports;
}
mLocked.pointerDisplayId = pointerDisplayId;
} // release lock
mInputManager->getReader()->requestRefreshConfiguration(
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -556,15 +549,42 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
controller = new PointerController(this, mLooper, mLocked.spriteController);
mLocked.pointerController = controller;
const DisplayViewport* internalViewport = findInternalViewport(mLocked.viewports);
updatePointerControllerFromViewport(controller, internalViewport);
updateInactivityTimeoutLocked(controller);
updateInactivityTimeoutLocked();
}
updatePointerDisplayLocked();
return controller;
}
int32_t NativeInputManager::getPointerDisplayId() {
JNIEnv* env = jniEnv();
jint pointerDisplayId = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getPointerDisplayId);
if (checkAndClearExceptionFromCallback(env, "getPointerDisplayId")) {
pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
return pointerDisplayId;
}
void NativeInputManager::updatePointerDisplayLocked() REQUIRES(mLock) {
ATRACE_CALL();
sp<PointerController> controller = mLocked.pointerController.promote();
if (controller != nullptr) {
const DisplayViewport* viewport = findDisplayViewportLocked(mLocked.pointerDisplayId);
if (viewport == nullptr) {
ALOGW("Can't find pointer display viewport, fallback to default display.");
viewport = findDisplayViewportLocked(ADISPLAY_ID_DEFAULT);
}
if (viewport != nullptr) {
controller->setDisplayViewport(*viewport);
}
}
}
void NativeInputManager::ensureSpriteControllerLocked() REQUIRES(mLock) {
if (mLocked.spriteController == nullptr) {
JNIEnv* env = jniEnv();
@@ -821,16 +841,16 @@ void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
if (mLocked.systemUiVisibility != visibility) {
mLocked.systemUiVisibility = visibility;
sp<PointerController> controller = mLocked.pointerController.promote();
if (controller != nullptr) {
updateInactivityTimeoutLocked(controller);
}
updateInactivityTimeoutLocked();
}
}
void NativeInputManager::updateInactivityTimeoutLocked(const sp<PointerController>& controller)
REQUIRES(mLock) {
void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
sp<PointerController> controller = mLocked.pointerController.promote();
if (controller == nullptr) {
return;
}
bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
controller->setInactivityTimeout(lightsOut
? PointerController::INACTIVITY_TIMEOUT_SHORT
@@ -1824,6 +1844,9 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
"getPointerIcon", "()Landroid/view/PointerIcon;");
GET_METHOD_ID(gServiceClassInfo.getPointerDisplayId, clazz,
"getPointerDisplayId", "()I");
GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
"getKeyboardLayoutOverlay",
"(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;");