Add private API InputMethodManager#reportVirtualDisplayGeometry

This logically relands the change [1] which added an @hide api
InputMethodManager#reportActivityView() with renaming as
reportVirtualDisplayGeometry().

Because ActivityView was removed, this API was removed [2] once.
However, because this API is useful for OEM customization, this change
adds the same API with a generalized method name.

Note that there was a change on how cross-display input connection
cursor update is blocked [3]. Thus, this CL adapts to it.

[1] Id0411a80456182111bb5b681c6d1230b58e7ec2e
[2] Idd60d96a39f827197d189beb5de016446576d9cd
[3] Iec12733d37e112b7271436bba15094ae2a55a450

Bug: 224424149
Test: manual. Cursor is updated in cross-display connection.
Change-Id: I35b491da5a340844e17542d7a6198f8152bbeda3
This commit is contained in:
Hiroki Sato
2022-03-24 15:41:48 +09:00
parent 62af809a65
commit 708c957fa3
7 changed files with 334 additions and 10 deletions

View File

@@ -53,6 +53,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Binder;
@@ -452,6 +453,18 @@ public final class InputMethodManager {
*/
private CursorAnchorInfo mCursorAnchorInfo = null;
/**
* A special {@link Matrix} that can be provided by the system when this instance is running
* inside a virtual display.
*
* <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
* should be adjusted with this {@link Matrix}.</p>
*
* <p>{@code null} when not used.</p>
*/
@GuardedBy("mH")
private Matrix mVirtualDisplayToScreenMatrix = null;
/**
* As reported by {@link InputBindResult}. This value is determined by
* {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
@@ -528,6 +541,7 @@ public final class InputMethodManager {
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
static final int MSG_BIND_ACCESSIBILITY_SERVICE = 11;
static final int MSG_UNBIND_ACCESSIBILITY_SERVICE = 12;
static final int MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX = 30;
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -892,6 +906,7 @@ public final class InputMethodManager {
InputMethodSessionWrapper.createOrNull(res.method);
mCurId = res.id;
mBindSequence = res.sequence;
mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
mIsInputMethodSuppressingSpellChecker =
res.isInputMethodSuppressingSpellChecker;
}
@@ -1063,6 +1078,45 @@ public final class InputMethodManager {
}
return;
}
case MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX: {
final float[] matrixValues = (float[]) msg.obj;
final int bindSequence = msg.arg1;
synchronized (mH) {
if (mBindSequence != bindSequence) {
return;
}
if (matrixValues == null || mVirtualDisplayToScreenMatrix == null) {
// Either InputBoundResult#mVirtualDisplayToScreenMatrixValues is null
// OR this app is unbound from the parent VirtualDisplay. In this case,
// calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
mVirtualDisplayToScreenMatrix = null;
return;
}
final float[] currentValues = new float[9];
mVirtualDisplayToScreenMatrix.getValues(currentValues);
if (Arrays.equals(currentValues, matrixValues)) {
return;
}
mVirtualDisplayToScreenMatrix.setValues(matrixValues);
if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
|| mServedInputConnection == null) {
return;
}
final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
& InputConnection.CURSOR_UPDATE_MONITOR) != 0;
if (!isMonitoring) {
return;
}
// Since the host VirtualDisplay is moved, we need to issue
// IMS#updateCursorAnchorInfo() again.
mCurrentInputMethodSession.updateCursorAnchorInfo(
CursorAnchorInfo.createForAdditionalParentMatrix(
mCursorAnchorInfo, mVirtualDisplayToScreenMatrix));
}
return;
}
}
}
}
@@ -1127,6 +1181,12 @@ public final class InputMethodManager {
.sendToTarget();
}
@Override
public void updateVirtualDisplayToScreenMatrix(int bindSequence, float[] matrixValues) {
mH.obtainMessage(MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX, bindSequence, 0,
matrixValues).sendToTarget();
}
@Override
public void setImeTraceEnabled(boolean enabled) {
ImeTracing.getInstance().setEnabled(enabled);
@@ -1596,7 +1656,9 @@ public final class InputMethodManager {
* Disconnect any existing input connection, clearing the served view.
*/
@UnsupportedAppUsage
@GuardedBy("mH")
void finishInputLocked() {
mVirtualDisplayToScreenMatrix = null;
mIsInputMethodSuppressingSpellChecker = false;
setNextServedViewLocked(null);
if (getServedViewLocked() != null) {
@@ -2275,6 +2337,7 @@ public final class InputMethodManager {
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
return false;
}
mVirtualDisplayToScreenMatrix = res.getVirtualDisplayToScreenMatrix();
mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
if (res.id != null) {
setInputChannelLocked(res.channel);
@@ -2695,7 +2758,13 @@ public final class InputMethodManager {
return;
}
if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
if (mVirtualDisplayToScreenMatrix != null) {
mCurrentInputMethodSession.updateCursorAnchorInfo(
CursorAnchorInfo.createForAdditionalParentMatrix(
cursorAnchorInfo, mVirtualDisplayToScreenMatrix));
} else {
mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
}
mCursorAnchorInfo = cursorAnchorInfo;
// Clear immediate bit (if any).
mRequestUpdateCursorAnchorInfoMonitorMode &= ~CURSOR_UPDATE_IMMEDIATE;
@@ -3268,6 +3337,43 @@ public final class InputMethodManager {
}
}
/**
* An internal API for {@link android.hardware.display.VirtualDisplay} to report where its
* embedded virtual display is placed.
*
* @param childDisplayId Display ID of the embedded virtual display.
* @param matrix {@link Matrix} to convert virtual display screen coordinates to
* the host screen coordinates. {@code null} to clear the relationship.
* @hide
*/
public void reportVirtualDisplayGeometry(int childDisplayId, @Nullable Matrix matrix) {
try {
final float[] matrixValues;
if (matrix == null) {
matrixValues = null;
} else {
matrixValues = new float[9];
matrix.getValues(matrixValues);
}
mService.reportVirtualDisplayGeometryAsync(mClient, childDisplayId, matrixValues);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* An internal API that returns if the current display has a transformation matrix to apply.
*
* @return {@code true} if {@link Matrix} to convert virtual display screen coordinates to
* the host screen coordinates is set.
* @hide
*/
public boolean hasVirtualDisplayToScreenMatrix() {
synchronized (mH) {
return mVirtualDisplayToScreenMatrix != null;
}
}
/**
* Force switch to the last used input method and subtype. If the last input method didn't have
* any subtypes, the framework will simply switch to the last input method with no subtype

View File

@@ -19,9 +19,11 @@ package com.android.internal.inputmethod;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Matrix;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -202,11 +204,28 @@ public final class InputBindResult implements Parcelable {
*/
public final int sequence;
@Nullable
private final float[] mVirtualDisplayToScreenMatrixValues;
/**
* {@code true} if the IME explicitly specifies {@code suppressesSpellChecker="true"}.
*/
public final boolean isInputMethodSuppressingSpellChecker;
/**
* @return {@link Matrix} that corresponds to {@link #mVirtualDisplayToScreenMatrixValues}.
* {@code null} if {@link #mVirtualDisplayToScreenMatrixValues} is {@code null}.
*/
@Nullable
public Matrix getVirtualDisplayToScreenMatrix() {
if (mVirtualDisplayToScreenMatrixValues == null) {
return null;
}
final Matrix matrix = new Matrix();
matrix.setValues(mVirtualDisplayToScreenMatrixValues);
return matrix;
}
/**
* Creates a new instance of {@link InputBindResult}.
*
@@ -225,6 +244,7 @@ public final class InputBindResult implements Parcelable {
public InputBindResult(@ResultCode int result,
IInputMethodSession method, SparseArray<IInputMethodSession> accessibilitySessions,
InputChannel channel, String id, int sequence,
@Nullable Matrix virtualDisplayToScreenMatrix,
boolean isInputMethodSuppressingSpellChecker) {
this.result = result;
this.method = method;
@@ -232,6 +252,12 @@ public final class InputBindResult implements Parcelable {
this.channel = channel;
this.id = id;
this.sequence = sequence;
if (virtualDisplayToScreenMatrix == null) {
mVirtualDisplayToScreenMatrixValues = null;
} else {
mVirtualDisplayToScreenMatrixValues = new float[9];
virtualDisplayToScreenMatrix.getValues(mVirtualDisplayToScreenMatrixValues);
}
this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
}
@@ -258,6 +284,7 @@ public final class InputBindResult implements Parcelable {
}
id = source.readString();
sequence = source.readInt();
mVirtualDisplayToScreenMatrixValues = source.createFloatArray();
isInputMethodSuppressingSpellChecker = source.readBoolean();
}
@@ -268,6 +295,7 @@ public final class InputBindResult implements Parcelable {
public String toString() {
return "InputBindResult{result=" + getResultString() + " method=" + method + " id=" + id
+ " sequence=" + sequence
+ " virtualDisplayToScreenMatrix=" + getVirtualDisplayToScreenMatrix()
+ " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
+ "}";
}
@@ -299,6 +327,7 @@ public final class InputBindResult implements Parcelable {
}
dest.writeString(id);
dest.writeInt(sequence);
dest.writeFloatArray(mVirtualDisplayToScreenMatrixValues);
dest.writeBoolean(isInputMethodSuppressingSpellChecker);
}
@@ -366,7 +395,7 @@ public final class InputBindResult implements Parcelable {
}
private static InputBindResult error(@ResultCode int result) {
return new InputBindResult(result, null, null, null, null, -1, false);
return new InputBindResult(result, null, null, null, null, -1, null, false);
}
/**

View File

@@ -987,7 +987,8 @@ public final class RemoteInputConnectionImpl extends IInputContext.Stub {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
return false;
}
if (mParentInputMethodManager.getDisplayId() != imeDisplayId) {
if (mParentInputMethodManager.getDisplayId() != imeDisplayId
&& !mParentInputMethodManager.hasVirtualDisplayToScreenMatrix()) {
// requestCursorUpdates() is not currently supported across displays.
return false;
}

View File

@@ -30,6 +30,7 @@ oneway interface IInputMethodClient {
void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
void updateVirtualDisplayToScreenMatrix(int bindSequence, in float[] matrixValues);
void setImeTraceEnabled(boolean enabled);
void throwExceptionFromSystem(String message);
}

View File

@@ -69,6 +69,9 @@ interface IInputMethodManager {
// TODO(Bug 113914148): Consider removing this.
int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
oneway void reportVirtualDisplayGeometryAsync(in IInputMethodClient parentClient,
int childDisplayId, in float[] matrixValues);
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
void removeImeSurface();

View File

@@ -427,7 +427,7 @@ final class InputMethodBindingController {
addFreshWindowToken();
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, null, mCurId, mCurSeq, false);
null, null, null, mCurId, mCurSeq, null, false);
}
Slog.w(InputMethodManagerService.TAG,

View File

@@ -88,6 +88,8 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Matrix;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
@@ -124,6 +126,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.View;
@@ -298,6 +301,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
final ImePlatformCompatUtils mImePlatformCompatUtils;
private final DisplayManagerInternal mDisplayManagerInternal;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
@@ -465,6 +469,35 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
private static final class VirtualDisplayInfo {
/**
* {@link ClientState} where {@link android.hardware.display.VirtualDisplay} is running.
*/
private final ClientState mParentClient;
/**
* {@link Matrix} to convert screen coordinates in the embedded virtual display to
* screen coordinates where {@link #mParentClient} exists.
*/
private final Matrix mMatrix;
VirtualDisplayInfo(ClientState parentClient, Matrix matrix) {
mParentClient = parentClient;
mMatrix = matrix;
}
}
/**
* A mapping table from virtual display IDs created for
* {@link android.hardware.display.VirtualDisplay} to its parent IME client where the embedded
* virtual display is running.
*
* <p>Note: this can be used only for virtual display IDs created by
* {@link android.hardware.display.VirtualDisplay}.</p>
*/
@GuardedBy("ImfLock.class")
private final SparseArray<VirtualDisplayInfo> mVirtualDisplayIdToParentMap =
new SparseArray<>();
/**
* Set once the system is ready to run third party code.
*/
@@ -561,6 +594,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
*/
EditorInfo mCurAttribute;
/**
* A special {@link Matrix} to convert virtual screen coordinates to the IME target display
* coordinates.
*
* <p>Used only while the IME client is running in a virtual display. {@code null}
* otherwise.</p>
*/
@Nullable
private Matrix mCurVirtualDisplayToScreenMatrix = null;
/**
* Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
* connected to or in the process of connecting to.
@@ -1660,6 +1703,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mImePlatformCompatUtils = new ImePlatformCompatUtils();
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -2333,6 +2377,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
clearClientSessionLocked(cs);
clearClientSessionForAccessibilityLocked(cs);
final int numItems = mVirtualDisplayIdToParentMap.size();
for (int i = numItems - 1; i >= 0; --i) {
final VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.valueAt(i);
if (info.mParentClient == cs) {
mVirtualDisplayIdToParentMap.removeAt(i);
}
}
if (mCurClient == cs) {
hideCurrentInputLocked(
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2348,6 +2401,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
mBoundToAccessibility = false;
mCurClient = null;
mCurVirtualDisplayToScreenMatrix = null;
}
if (mCurFocusedWindowClient == cs) {
mCurFocusedWindowClient = null;
@@ -2432,6 +2486,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient.sessionRequested = false;
mCurClient.mSessionRequestedForAccessibility = false;
mCurClient = null;
mCurVirtualDisplayToScreenMatrix = null;
mMenuController.hideInputMethodMenuLocked();
}
@@ -2517,7 +2572,33 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.session, accessibilityInputMethodSessions,
(session.channel != null ? session.channel.dup() : null),
curId, getSequenceNumberLocked(), suppressesSpellChecker);
curId, getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix,
suppressesSpellChecker);
}
@GuardedBy("ImfLock.class")
@Nullable
private Matrix getVirtualDisplayToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
if (clientDisplayId == imeDisplayId) {
return null;
}
int displayId = clientDisplayId;
Matrix matrix = null;
while (true) {
final VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.get(displayId);
if (info == null) {
return null;
}
if (matrix == null) {
matrix = new Matrix(info.mMatrix);
} else {
matrix.postConcat(info.mMatrix);
}
if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
return matrix;
}
displayId = info.mParentClient.selfReportedDisplayId;
}
}
@GuardedBy("ImfLock.class")
@@ -2551,7 +2632,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION,
imeSession, accessibilityInputMethodSessions, null,
getCurIdLocked(), getSequenceNumberLocked(), false);
getCurIdLocked(), getSequenceNumberLocked(), mCurVirtualDisplayToScreenMatrix,
false);
}
return null;
}
@@ -2594,7 +2676,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
null, null, null, selectedMethodId, getSequenceNumberLocked(), false);
null, null, null, selectedMethodId, getSequenceNumberLocked(), null, false);
}
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2625,6 +2707,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
advanceSequenceNumberLocked();
mCurClient = cs;
mCurInputContext = inputContext;
mCurVirtualDisplayToScreenMatrix =
getVirtualDisplayToScreenMatrixLocked(cs.selfReportedDisplayId,
mDisplayIdToShowIme);
mCurAttribute = attribute;
// If configured, we want to avoid starting up the IME if it is not supposed to be showing
@@ -2728,7 +2813,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
requestClientSessionForAccessibilityLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
null, null, null, getCurIdLocked(), getSequenceNumberLocked(), null, false);
} else {
long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
if (bindingDuration < TIME_TO_RECONNECT) {
@@ -2741,7 +2826,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
null, null, null, getCurIdLocked(), getSequenceNumberLocked(), null,
false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
getSelectedMethodIdLocked(), bindingDuration, 0);
@@ -3790,7 +3876,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, null, -1, false);
null, null, null, null, -1, null, false);
}
mCurFocusedWindow = windowToken;
@@ -4309,6 +4395,104 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();
}
@Override
public void reportVirtualDisplayGeometryAsync(IInputMethodClient parentClient,
int childDisplayId, float[] matrixValues) {
try {
final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
if (displayInfo == null) {
throw new IllegalArgumentException(
"Cannot find display for non-existent displayId: " + childDisplayId);
}
final int callingUid = Binder.getCallingUid();
if (callingUid != displayInfo.ownerUid) {
throw new SecurityException("The caller doesn't own the display.");
}
synchronized (ImfLock.class) {
final ClientState cs = mClients.get(parentClient.asBinder());
if (cs == null) {
return;
}
// null matrixValues means that the entry needs to be removed.
if (matrixValues == null) {
final VirtualDisplayInfo info =
mVirtualDisplayIdToParentMap.get(childDisplayId);
if (info == null) {
return;
}
if (info.mParentClient != cs) {
throw new SecurityException("Only the owner client can clear"
+ " VirtualDisplayGeometry for display #" + childDisplayId);
}
mVirtualDisplayIdToParentMap.remove(childDisplayId);
return;
}
VirtualDisplayInfo info = mVirtualDisplayIdToParentMap.get(childDisplayId);
if (info != null && info.mParentClient != cs) {
throw new InvalidParameterException("Display #" + childDisplayId
+ " is already registered by " + info.mParentClient);
}
if (info == null) {
if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
throw new SecurityException(cs + " cannot access to display #"
+ childDisplayId);
}
info = new VirtualDisplayInfo(cs, new Matrix());
mVirtualDisplayIdToParentMap.put(childDisplayId, info);
}
info.mMatrix.setValues(matrixValues);
if (mCurClient == null || mCurClient.curSession == null) {
return;
}
Matrix matrix = null;
int displayId = mCurClient.selfReportedDisplayId;
boolean needToNotify = false;
while (true) {
needToNotify |= (displayId == childDisplayId);
final VirtualDisplayInfo next = mVirtualDisplayIdToParentMap.get(displayId);
if (next == null) {
break;
}
if (matrix == null) {
matrix = new Matrix(next.mMatrix);
} else {
matrix.postConcat(next.mMatrix);
}
if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
if (needToNotify) {
final float[] values = new float[9];
matrix.getValues(values);
try {
mCurClient.client.updateVirtualDisplayToScreenMatrix(
getSequenceNumberLocked(), values);
} catch (RemoteException e) {
Slog.e(TAG,
"Exception calling updateVirtualDisplayToScreenMatrix()",
e);
}
}
break;
}
displayId = info.mParentClient.selfReportedDisplayId;
}
}
} catch (Throwable t) {
if (parentClient != null) {
try {
parentClient.throwExceptionFromSystem(t.toString());
} catch (RemoteException e) {
Slog.e(TAG, "Exception calling throwExceptionFromSystem()", e);
}
}
}
}
@Override
public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {
// No permission check, because we'll only execute the request if the calling window is