diff options
7 files changed, 334 insertions, 10 deletions
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index da20e336627c..805f8e7551a5 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -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; @@ -453,6 +454,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; + } } } } @@ -1128,6 +1182,12 @@ public final class InputMethodManager { } @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; @@ -3269,6 +3338,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 * specified. diff --git a/core/java/com/android/internal/inputmethod/InputBindResult.java b/core/java/com/android/internal/inputmethod/InputBindResult.java index e83840177a73..f7341a5c4574 100644 --- a/core/java/com/android/internal/inputmethod/InputBindResult.java +++ b/core/java/com/android/internal/inputmethod/InputBindResult.java @@ -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,12 +204,29 @@ 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}. * * @param result A result code defined in {@link ResultCode}. @@ -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); } /** diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java index f81fd376fef0..7f11e3018849 100644 --- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java +++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java @@ -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; } diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl index 8430c0859bc9..8952474924bb 100644 --- a/core/java/com/android/internal/view/IInputMethodClient.aidl +++ b/core/java/com/android/internal/view/IInputMethodClient.aidl @@ -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); } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index c5346b95440b..616411fee5f2 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -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(); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index d2d80ffde532..0de523c5f3f6 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -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, diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index d6131d162173..c10402653408 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -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. */ @@ -562,6 +595,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; @@ -4310,6 +4396,104 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @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 // also the current IME client. |