Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32bd24d5 authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Automerger Merge Worker
Browse files

Merge "Remove InputMethodManager#reportActivityView()" into sc-dev am:...

Merge "Remove InputMethodManager#reportActivityView()" into sc-dev am: e738cfc8 am: e5648618 am: 170157f8

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

Change-Id: I1e0fd5ed7e8eb1221d5401ec5517fbc698f05e77
parents a8365cda 170157f8
Loading
Loading
Loading
Loading
+1 −92
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ 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;
@@ -442,17 +441,6 @@ 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 that is managed by {@link android.app.ActivityView}.
     *
     * <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>
     */
    private Matrix mActivityViewToScreenMatrix = null;

    /**
     * As reported by {@link InputBindResult}. This value is determined by
     * {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
@@ -520,7 +508,6 @@ public final class InputMethodManager {
    static final int MSG_TIMEOUT_INPUT_EVENT = 6;
    static final int MSG_FLUSH_INPUT_EVENT = 7;
    static final int MSG_REPORT_FULLSCREEN_MODE = 10;
    static final int MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX = 30;

    private static boolean isAutofillUIShowing(View servedView) {
        AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -895,7 +882,6 @@ public final class InputMethodManager {
                                InputMethodSessionWrapper.createOrNull(res.method);
                        mCurId = res.id;
                        mBindSequence = res.sequence;
                        mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
                        mIsInputMethodSuppressingSpellChecker =
                                res.isInputMethodSuppressingSpellChecker;
                    }
@@ -1002,45 +988,6 @@ public final class InputMethodManager {
                    }
                    return;
                }
                case MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX: {
                    final float[] matrixValues = (float[]) msg.obj;
                    final int bindSequence = msg.arg1;
                    synchronized (mH) {
                        if (mBindSequence != bindSequence) {
                            return;
                        }
                        if (matrixValues == null || mActivityViewToScreenMatrix == null) {
                            // Either InputBoundResult#mActivityViewToScreenMatrixValues is null
                            // OR this app is unbound from the parent ActivityView. In this case,
                            // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
                            mActivityViewToScreenMatrix = null;
                            return;
                        }

                        final float[] currentValues = new float[9];
                        mActivityViewToScreenMatrix.getValues(currentValues);
                        if (Arrays.equals(currentValues, matrixValues)) {
                            return;
                        }
                        mActivityViewToScreenMatrix.setValues(matrixValues);

                        if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
                                || mServedInputConnectionWrapper == null) {
                            return;
                        }
                        final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
                                & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
                        if (!isMonitoring) {
                            return;
                        }
                        // Since the host ActivityView is moved, we need to issue
                        // IMS#updateCursorAnchorInfo() again.
                        mCurrentInputMethodSession.updateCursorAnchorInfo(
                                CursorAnchorInfo.createForAdditionalParentMatrix(
                                        mCursorAnchorInfo, mActivityViewToScreenMatrix));
                    }
                    return;
                }
            }
        }
    }
@@ -1095,12 +1042,6 @@ public final class InputMethodManager {
                    .sendToTarget();
        }

        @Override
        public void updateActivityViewToScreenMatrix(int bindSequence, float[] matrixValues) {
            mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0,
                    matrixValues).sendToTarget();
        }

        @Override
        public void setImeTraceEnabled(boolean enabled) {
            ImeTracing.getInstance().setEnabled(enabled);
@@ -1557,7 +1498,6 @@ public final class InputMethodManager {
     */
    @UnsupportedAppUsage
    void finishInputLocked() {
        mActivityViewToScreenMatrix = null;
        mIsInputMethodSuppressingSpellChecker = false;
        setNextServedViewLocked(null);
        if (getServedViewLocked() != null) {
@@ -2110,7 +2050,6 @@ public final class InputMethodManager {
                        + InputMethodDebug.startInputFlagsToString(startInputFlags));
                return false;
            }
            mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
            mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
            if (res.id != null) {
                setInputChannelLocked(res.channel);
@@ -2499,13 +2438,7 @@ public final class InputMethodManager {
                return;
            }
            if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
            if (mActivityViewToScreenMatrix != null) {
                mCurrentInputMethodSession.updateCursorAnchorInfo(
                        CursorAnchorInfo.createForAdditionalParentMatrix(
                            cursorAnchorInfo, mActivityViewToScreenMatrix));
            } else {
            mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
            }
            mCursorAnchorInfo = cursorAnchorInfo;
            // Clear immediate bit (if any).
            mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
@@ -3096,30 +3029,6 @@ public final class InputMethodManager {
        }
    }

    /**
     * An internal API for {@link android.app.ActivityView} 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 reportActivityView(int childDisplayId, @Nullable Matrix matrix) {
        try {
            final float[] matrixValues;
            if (matrix == null) {
                matrixValues = null;
            } else {
                matrixValues = new float[9];
                matrix.getValues(matrixValues);
            }
            mService.reportActivityViewAsync(mClient, childDisplayId, matrixValues);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * 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
+0 −1
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ oneway interface IInputMethodClient {
    void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
    void scheduleStartInputIfNecessary(boolean fullscreen);
    void reportFullscreenMode(boolean fullscreen);
    void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
    void setImeTraceEnabled(boolean enabled);
    void throwExceptionFromSystem(String message);
}
+0 −3
Original line number Diff line number Diff line
@@ -88,9 +88,6 @@ interface IInputMethodManager {
    // TODO(Bug 113914148): Consider removing this.
    oneway void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback);

    oneway void reportActivityViewAsync(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. */
    oneway void removeImeSurface(in IVoidResultCallback resultCallback);
+1 −30
Original line number Diff line number Diff line
@@ -19,12 +19,10 @@ package com.android.internal.view;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
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;
@@ -201,40 +199,16 @@ public final class InputBindResult implements Parcelable {
     */
    public final int sequence;

    @Nullable
    private final float[] mActivityViewToScreenMatrixValues;

    public final boolean isInputMethodSuppressingSpellChecker;

    /**
     * @return {@link Matrix} that corresponds to {@link #mActivityViewToScreenMatrixValues}.
     *         {@code null} if {@link #mActivityViewToScreenMatrixValues} is {@code null}.
     */
    @Nullable
    public Matrix getActivityViewToScreenMatrix() {
        if (mActivityViewToScreenMatrixValues == null) {
            return null;
        }
        final Matrix matrix = new Matrix();
        matrix.setValues(mActivityViewToScreenMatrixValues);
        return matrix;
    }

    public InputBindResult(@ResultCode int _result,
            IInputMethodSession _method, InputChannel _channel, String _id, int _sequence,
            @Nullable Matrix activityViewToScreenMatrix,
            boolean isInputMethodSuppressingSpellChecker) {
        result = _result;
        method = _method;
        channel = _channel;
        id = _id;
        sequence = _sequence;
        if (activityViewToScreenMatrix == null) {
            mActivityViewToScreenMatrixValues = null;
        } else {
            mActivityViewToScreenMatrixValues = new float[9];
            activityViewToScreenMatrix.getValues(mActivityViewToScreenMatrixValues);
        }
        this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
    }

@@ -248,7 +222,6 @@ public final class InputBindResult implements Parcelable {
        }
        id = source.readString();
        sequence = source.readInt();
        mActivityViewToScreenMatrixValues = source.createFloatArray();
        isInputMethodSuppressingSpellChecker = source.readBoolean();
    }

@@ -256,7 +229,6 @@ public final class InputBindResult implements Parcelable {
    public String toString() {
        return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
                + " sequence=" + sequence
                + " activityViewToScreenMatrix=" + getActivityViewToScreenMatrix()
                + " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
                + "}";
    }
@@ -279,7 +251,6 @@ public final class InputBindResult implements Parcelable {
        }
        dest.writeString(id);
        dest.writeInt(sequence);
        dest.writeFloatArray(mActivityViewToScreenMatrixValues);
        dest.writeBoolean(isInputMethodSuppressingSpellChecker);
    }

@@ -347,7 +318,7 @@ public final class InputBindResult implements Parcelable {
    }

    private static InputBindResult error(@ResultCode int result) {
        return new InputBindResult(result, null, null, null, -1, null, false);
        return new InputBindResult(result, null, null, null, -1, false);
    }

    /**
+7 −179
Original line number Diff line number Diff line
@@ -89,8 +89,6 @@ 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;
@@ -126,10 +124,8 @@ import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.View;
@@ -313,7 +309,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    final WindowManagerInternal mWindowManagerInternal;
    final PackageManagerInternal mPackageManagerInternal;
    final InputManagerInternal mInputManagerInternal;
    private final DisplayManagerInternal mDisplayManagerInternal;
    final HandlerCaller mCaller;
    final boolean mHasFeature;
    private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
@@ -453,32 +448,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    @GuardedBy("mMethodMap")
    final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();

    private static final class ActivityViewInfo {
        /**
         * {@link ClientState} where {@link android.app.ActivityView} 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;

        ActivityViewInfo(ClientState parentClient, Matrix matrix) {
            mParentClient = parentClient;
            mMatrix = matrix;
        }
    }

    /**
     * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
     * to its parent IME client where {@link android.app.ActivityView} is running.
     *
     * <p>Note: this can be used only for virtual display IDs created by
     * {@link android.app.ActivityView}.</p>
     */
    private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();

    /**
     * Set once the system is ready to run third party code.
     */
@@ -563,16 +532,6 @@ public 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 inside
     * {@link android.app.ActivityView}. {@code null} otherwise.</p>
     */
    @Nullable
    private Matrix mCurActivityViewToScreenMatrix = null;

    /**
     * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
     * connected to or in the process of connecting to.
@@ -1648,7 +1607,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
        mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
        mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
            @Override
@@ -2262,15 +2220,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            if (cs != null) {
                client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
                clearClientSessionLocked(cs);

                final int numItems = mActivityViewDisplayIdToParentMap.size();
                for (int i = numItems - 1; i >= 0; --i) {
                    final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
                    if (info.mParentClient == cs) {
                        mActivityViewDisplayIdToParentMap.removeAt(i);
                    }
                }

                if (mCurClient == cs) {
                    hideCurrentInputLocked(
                            mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2282,7 +2231,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                        }
                    }
                    mCurClient = null;
                    mCurActivityViewToScreenMatrix = null;
                }
                if (mCurFocusedWindowClient == cs) {
                    mCurFocusedWindowClient = null;
@@ -2318,7 +2266,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
            mCurClient.sessionRequested = false;
            mCurClient = null;
            mCurActivityViewToScreenMatrix = null;

            mMenuController.hideInputMethodMenuLocked();
        }
@@ -2386,31 +2333,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
        return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
                session.session, (session.channel != null ? session.channel.dup() : null),
                mCurId, mCurSeq, mCurActivityViewToScreenMatrix, suppressesSpellChecker);
    }

    @Nullable
    private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
        if (clientDisplayId == imeDisplayId) {
            return null;
        }
        int displayId = clientDisplayId;
        Matrix matrix = null;
        while (true) {
            final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.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;
        }
                mCurId, mCurSeq, suppressesSpellChecker);
    }

    @GuardedBy("mMethodMap")
@@ -2428,7 +2351,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            // party code.
            return new InputBindResult(
                    InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
                    null, null, mCurMethodId, mCurSeq, null, false);
                    null, null, mCurMethodId, mCurSeq, false);
        }

        if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2474,10 +2397,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        if (mCurSeq <= 0) mCurSeq = 1;
        mCurClient = cs;
        mCurInputContext = inputContext;
        mCurActivityViewToScreenMatrix =
                getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
        if (cs.selfReportedDisplayId != displayIdToShowIme
                && mCurActivityViewToScreenMatrix == null) {
        if (cs.selfReportedDisplayId != displayIdToShowIme) {
            // CursorAnchorInfo API does not work as-is for cross-display scenario.  Pretend that
            // InputConnection#requestCursorUpdates() is not implemented in the application so that
            // IMEs will always receive false from this API.
@@ -2504,7 +2424,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    requestClientSessionLocked(cs);
                    return new InputBindResult(
                            InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
                            null, null, mCurId, mCurSeq, null, false);
                            null, null, mCurId, mCurSeq, false);
                } else if (SystemClock.uptimeMillis()
                        < (mLastBindTime+TIME_TO_RECONNECT)) {
                    // In this case we have connected to the service, but
@@ -2516,7 +2436,7 @@ public 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, mCurId, mCurSeq, null, false);
                            null, null, mCurId, mCurSeq, false);
                } else {
                    EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
                            mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -2556,7 +2476,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            }
            return new InputBindResult(
                    InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
                    null, null, mCurId, mCurSeq, null, false);
                    null, null, mCurId, mCurSeq, false);
        }
        mCurIntent = null;
        Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
@@ -3550,7 +3470,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            }
            return new InputBindResult(
                    InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
                    null, null, null, -1, null, false);
                    null, null, null, -1, false);
        }

        mCurFocusedWindow = windowToken;
@@ -4045,98 +3965,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        });
    }

    @Override
    public void reportActivityViewAsync(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 (mMethodMap) {
                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 ActivityViewInfo info =
                            mActivityViewDisplayIdToParentMap.get(childDisplayId);
                    if (info == null) {
                        return;
                    }
                    if (info.mParentClient != cs) {
                        throw new SecurityException("Only the owner client can clear"
                                + " ActivityViewGeometry for display #" + childDisplayId);
                    }
                    mActivityViewDisplayIdToParentMap.remove(childDisplayId);
                    return;
                }

                ActivityViewInfo info = mActivityViewDisplayIdToParentMap.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 ActivityViewInfo(cs, new Matrix());
                    mActivityViewDisplayIdToParentMap.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 ActivityViewInfo next = mActivityViewDisplayIdToParentMap.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.updateActivityViewToScreenMatrix(mCurSeq, values);
                            } catch (RemoteException e) {
                            }
                        }
                        break;
                    }
                    displayId = info.mParentClient.selfReportedDisplayId;
                }
            }
        } catch (Throwable t) {
            if (parentClient != null) {
                try {
                    parentClient.throwExceptionFromSystem(t.toString());
                } catch (RemoteException e) {
                }
            }
        }
    }

    @Override
    public void removeImeSurface(IVoidResultCallback resultCallback) {
        CallbackUtils.onResult(resultCallback, () -> {
Loading