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

Commit a7d2fd1a authored by Feng Cao's avatar Feng Cao Committed by Automerger Merge Worker
Browse files

Merge "Reusing the remote inline suggestion view during autofill filtering"...

Merge "Reusing the remote inline suggestion view during autofill filtering" into rvc-dev am: aca49a44

Change-Id: I7ebc3c8711dac4854dd67423469e574228869b66
parents 927995db aca49a44
Loading
Loading
Loading
Loading
+54 −17
Original line number Diff line number Diff line
@@ -17,17 +17,17 @@
package com.android.server.autofill;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Bundle;
import android.os.Handler;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;

import com.android.internal.annotations.GuardedBy;
import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;

import java.util.Collections;
import java.util.Optional;
import java.util.function.Consumer;

@@ -46,8 +46,12 @@ final class AutofillInlineSessionController {
    @NonNull
    private final Handler mHandler;

    @Nullable
    @GuardedBy("mLock")
    private AutofillInlineSuggestionsRequestSession mSession;
    @Nullable
    @GuardedBy("mLock")
    private InlineFillUi mInlineFillUi;

    AutofillInlineSessionController(InputMethodManagerInternal inputMethodManagerInternal,
            int userId, ComponentName componentName, Handler handler, Object lock) {
@@ -72,16 +76,16 @@ final class AutofillInlineSessionController {
        // TODO(b/151123764): rename the method to better reflect what it does.
        if (mSession != null) {
            // Send an empty response to IME and destroy the existing session.
            mSession.onInlineSuggestionsResponseLocked(mSession.getAutofillIdLocked(),
                    new InlineSuggestionsResponse(Collections.EMPTY_LIST));
            mSession.onInlineSuggestionsResponseLocked(
                    InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
            mSession.destroySessionLocked();
            mInlineFillUi = null;
        }
        // TODO(b/151123764): consider reusing the same AutofillInlineSession object for the
        // same field.
        mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId,
                mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras);
        mSession.onCreateInlineSuggestionsRequestLocked();

    }

    /**
@@ -101,30 +105,63 @@ final class AutofillInlineSessionController {

    /**
     * Requests the IME to hide the current suggestions, if any. Returns true if the message is sent
     * to the IME.
     * to the IME. This only hides the UI temporarily. For example if user starts typing/deleting
     * characters, new filterText will kick in and may revive the suggestion UI.
     */
    @GuardedBy("mLock")
    boolean hideInlineSuggestionsUiLocked(@NonNull AutofillId autofillId) {
        if (mSession != null) {
            return mSession.onInlineSuggestionsResponseLocked(autofillId,
                    new InlineSuggestionsResponse(Collections.EMPTY_LIST));
            return mSession.onInlineSuggestionsResponseLocked(InlineFillUi.emptyUi(autofillId));
        }
        return false;
    }

    /**
     * Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
     * well.
     */
    @GuardedBy("mLock")
    boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
        mInlineFillUi = null;
        return hideInlineSuggestionsUiLocked(autofillId);
    }

    /**
     * Updates the inline fill UI with the filter text. It'll send updated inline suggestions to
     * the IME.
     */
    @GuardedBy("mLock")
    boolean filterInlineFillUiLocked(@NonNull AutofillId autofillId, @Nullable String filterText) {
        if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
            mInlineFillUi.setFilterText(filterText);
            return requestImeToShowInlineSuggestionsLocked();
        }
        return false;
    }

    /**
     * Requests showing the inline suggestion in the IME when the IME becomes visible and is focused
     * on the {@code autofillId}.
     * Set the current inline fill UI. It'll request the IME to show the inline suggestions when
     * the IME becomes visible and is focused on the {@code autofillId}.
     *
     * @return false if there is no session, or if the IME callback is not available in the session.
     * @return false if the suggestions are not sent to IME because there is no session, or if the
     * IME callback is not available in the session.
     */
    @GuardedBy("mLock")
    boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
            @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
        // TODO(b/151123764): rename the method to better reflect what it does.
        if (mSession != null) {
            return mSession.onInlineSuggestionsResponseLocked(autofillId,
                    inlineSuggestionsResponse);
    boolean setInlineFillUiLocked(@NonNull InlineFillUi inlineFillUi) {
        mInlineFillUi = inlineFillUi;
        return requestImeToShowInlineSuggestionsLocked();
    }

    /**
     * Sends the suggestions from the current inline fill UI to the IME.
     *
     * @return false if the suggestions are not sent to IME because there is no session, or if the
     * IME callback is not available in the session.
     */
    @GuardedBy("mLock")
    private boolean requestImeToShowInlineSuggestionsLocked() {
        if (mSession != null && mInlineFillUi != null) {
            return mSession.onInlineSuggestionsResponseLocked(mInlineFillUi);
        }
        return false;
    }
+27 −26
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.content.ComponentName;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
@@ -37,7 +36,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
import com.android.server.autofill.ui.InlineSuggestionFactory;
import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;

import java.lang.ref.WeakReference;
@@ -106,7 +105,7 @@ final class AutofillInlineSuggestionsRequestSession {
    private boolean mImeInputViewStarted;
    @GuardedBy("mLock")
    @Nullable
    private InlineSuggestionsResponse mInlineSuggestionsResponse;
    private InlineFillUi mInlineFillUi;
    @GuardedBy("mLock")
    private boolean mPreviousResponseIsNotEmpty;

@@ -156,18 +155,20 @@ final class AutofillInlineSuggestionsRequestSession {
     * @return false if the IME callback is not available.
     */
    @GuardedBy("mLock")
    boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
            @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
    boolean onInlineSuggestionsResponseLocked(@NonNull InlineFillUi inlineFillUi) {
        if (mDestroyed) {
            return false;
        }
        if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked called for:" + autofillId);
        if (sDebug) {
            Slog.d(TAG,
                    "onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
        }
        if (mImeRequest == null || mResponseCallback == null) {
            return false;
        }
        // TODO(b/151123764): each session should only correspond to one field.
        mAutofillId = autofillId;
        mInlineSuggestionsResponse = inlineSuggestionsResponse;
        mAutofillId = inlineFillUi.getAutofillId();
        mInlineFillUi = inlineFillUi;
        maybeUpdateResponseToImeLocked();
        return true;
    }
@@ -191,12 +192,12 @@ final class AutofillInlineSuggestionsRequestSession {
        if (mDestroyed) {
            return;
        }
        if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
        if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
        mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
                new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
                new InlineSuggestionsRequestCallbackImpl(this));
        mTimeoutCallback = () -> {
            Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
            Slog.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
            handleOnReceiveImeRequest(null, null);
        };
        mHandler.postDelayed(mTimeoutCallback, CREATE_INLINE_SUGGESTIONS_REQUEST_TIMEOUT_MS);
@@ -207,7 +208,7 @@ final class AutofillInlineSuggestionsRequestSession {
     */
    @GuardedBy("mLock")
    private void maybeUpdateResponseToImeLocked() {
        if (sVerbose) Log.v(TAG, "maybeUpdateResponseToImeLocked called");
        if (sVerbose) Slog.v(TAG, "maybeUpdateResponseToImeLocked called");
        if (mDestroyed || mResponseCallback == null) {
            return;
        }
@@ -217,18 +218,19 @@ final class AutofillInlineSuggestionsRequestSession {
            // Although the inline suggestions should disappear when IME hides which removes them
            // from the view hierarchy, but we still send an empty response to be extra safe.

            if (sVerbose) Log.v(TAG, "Send empty inline response");
            if (sVerbose) Slog.v(TAG, "Send empty inline response");
            updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
            mPreviousResponseIsNotEmpty = false;
        } else if (mImeInputViewStarted && mInlineSuggestionsResponse != null && match(mAutofillId,
        } else if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
                mImeCurrentFieldId)) {
            // 2. if IME is visible, and response is not null, send the response
            boolean isEmptyResponse = mInlineSuggestionsResponse.getInlineSuggestions().isEmpty();
            InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
            boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
            if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
                // No-op if both the previous response and current response are empty.
                return;
            }
            updateResponseToImeUncheckLocked(mInlineSuggestionsResponse);
            updateResponseToImeUncheckLocked(response);
            mPreviousResponseIsNotEmpty = !isEmptyResponse;
        }
    }
@@ -241,10 +243,9 @@ final class AutofillInlineSuggestionsRequestSession {
        if (mDestroyed) {
            return;
        }
        if (sDebug) Log.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
        if (sDebug) Slog.d(TAG, "Send inline response: " + response.getInlineSuggestions().size());
        try {
            mResponseCallback.onInlineSuggestionsResponse(mAutofillId,
                    InlineSuggestionFactory.copy(response));
            mResponseCallback.onInlineSuggestionsResponse(mAutofillId, response);
        } catch (RemoteException e) {
            Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME");
        }
@@ -264,7 +265,7 @@ final class AutofillInlineSuggestionsRequestSession {
            mImeRequestReceived = true;

            if (mTimeoutCallback != null) {
                if (sVerbose) Log.v(TAG, "removing timeout callback");
                if (sVerbose) Slog.v(TAG, "removing timeout callback");
                mHandler.removeCallbacks(mTimeoutCallback);
                mTimeoutCallback = null;
            }
@@ -335,7 +336,7 @@ final class AutofillInlineSuggestionsRequestSession {
        @BinderThread
        @Override
        public void onInlineSuggestionsUnsupported() throws RemoteException {
            if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
            if (sDebug) Slog.d(TAG, "onInlineSuggestionsUnsupported() called.");
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
@@ -348,7 +349,7 @@ final class AutofillInlineSuggestionsRequestSession {
        @Override
        public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
                IInlineSuggestionsResponseCallback callback) {
            if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
            if (sDebug) Slog.d(TAG, "onInlineSuggestionsRequest() received: " + request);
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
@@ -359,7 +360,7 @@ final class AutofillInlineSuggestionsRequestSession {

        @Override
        public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException {
            if (sVerbose) Log.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
            if (sVerbose) Slog.v(TAG, "onInputMethodStartInput() received on " + imeFieldId);
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
@@ -371,14 +372,14 @@ final class AutofillInlineSuggestionsRequestSession {
        @Override
        public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException {
            if (sVerbose) {
                Log.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
                Slog.v(TAG, "onInputMethodShowInputRequested() received: " + requestResult);
            }
        }

        @BinderThread
        @Override
        public void onInputMethodStartInputView() {
            if (sVerbose) Log.v(TAG, "onInputMethodStartInputView() received");
            if (sVerbose) Slog.v(TAG, "onInputMethodStartInputView() received");
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
@@ -390,7 +391,7 @@ final class AutofillInlineSuggestionsRequestSession {
        @BinderThread
        @Override
        public void onInputMethodFinishInputView() {
            if (sVerbose) Log.v(TAG, "onInputMethodFinishInputView() received");
            if (sVerbose) Slog.v(TAG, "onInputMethodFinishInputView() received");
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
@@ -401,7 +402,7 @@ final class AutofillInlineSuggestionsRequestSession {

        @Override
        public void onInputMethodFinishInput() throws RemoteException {
            if (sVerbose) Log.v(TAG, "onInputMethodFinishInput() received");
            if (sVerbose) Slog.v(TAG, "onInputMethodFinishInput() received");
            final AutofillInlineSuggestionsRequestSession session = mSession.get();
            if (session != null) {
                session.mHandler.sendMessage(obtainMessage(
+17 −18
Original line number Diff line number Diff line
@@ -48,17 +48,15 @@ import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;

import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.InlineSuggestionFactory;
import com.android.server.autofill.ui.InlineFillUi;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -149,7 +147,7 @@ final class RemoteAugmentedAutofillService
            int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
            @Nullable AutofillValue focusedValue,
            @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
            @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
            @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
            @NonNull Runnable onErrorCallback,
            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
        long requestTime = SystemClock.elapsedRealtime();
@@ -173,7 +171,8 @@ final class RemoteAugmentedAutofillService
                                    mCallbacks.resetLastResponse();
                                    maybeRequestShowInlineSuggestions(sessionId,
                                            inlineSuggestionsRequest, inlineSuggestionsData,
                                            clientState, focusedId, inlineSuggestionsCallback,
                                            clientState, focusedId, focusedValue,
                                            inlineSuggestionsCallback,
                                            client, onErrorCallback, remoteRenderService);
                                    requestAutofill.complete(null);
                                }
@@ -239,8 +238,8 @@ final class RemoteAugmentedAutofillService
    private void maybeRequestShowInlineSuggestions(int sessionId,
            @Nullable InlineSuggestionsRequest request,
            @Nullable List<Dataset> inlineSuggestionsData, @Nullable Bundle clientState,
            @NonNull AutofillId focusedId,
            @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
            @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue,
            @Nullable Function<InlineFillUi, Boolean> inlineSuggestionsCallback,
            @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
            @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
        if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
@@ -250,10 +249,14 @@ final class RemoteAugmentedAutofillService
        }
        mCallbacks.setLastResponse(sessionId);

        final InlineSuggestionsResponse inlineSuggestionsResponse =
                InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
                        request, inlineSuggestionsData, focusedId,
                        new InlineSuggestionFactory.InlineSuggestionUiCallback() {
        final String filterText =
                focusedValue != null && focusedValue.isText()
                        ? focusedValue.getTextValue().toString() : null;

        final InlineFillUi inlineFillUi =
                InlineFillUi.forAugmentedAutofill(
                        request, inlineSuggestionsData, focusedId, filterText,
                        new InlineFillUi.InlineSuggestionUiCallback() {
                            @Override
                            public void autofill(Dataset dataset) {
                                mCallbacks.logAugmentedAutofillSelected(sessionId,
@@ -265,8 +268,8 @@ final class RemoteAugmentedAutofillService
                                            && fieldIds.get(0).equals(focusedId);
                                    client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
                                            hideHighlight);
                                    inlineSuggestionsCallback.apply(new InlineSuggestionsResponse(
                                            Collections.EMPTY_LIST));
                                    inlineSuggestionsCallback.apply(
                                            InlineFillUi.emptyUi(focusedId));
                                } catch (RemoteException e) {
                                    Slog.w(TAG, "Encounter exception autofilling the values");
                                }
@@ -283,11 +286,7 @@ final class RemoteAugmentedAutofillService
                            }
                        }, onErrorCallback, remoteRenderService);

        if (inlineSuggestionsResponse == null) {
            Slog.w(TAG, "InlineSuggestionFactory created null response");
            return;
        }
        if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) {
        if (inlineSuggestionsCallback.apply(inlineFillUi)) {
            mCallbacks.logAugmentedAutofillShown(sessionId, clientState);
        }
    }
+23 −26
Original line number Diff line number Diff line
@@ -94,7 +94,6 @@ import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -102,7 +101,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.InlineSuggestionFactory;
import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.autofill.ui.PendingUi;
import com.android.server.inputmethod.InputMethodManagerInternal;

@@ -2662,10 +2661,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            }
        } else if (viewState.id.equals(this.mCurrentViewId)
                && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
            requestShowInlineSuggestionsLocked(viewState.getResponse(), filterText);
            if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
                final FillResponse response = viewState.getResponse();
                if (response != null) {
                    response.getDatasets().clear();
                }
                mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
            } else {
                mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
            }
        } else if (viewState.id.equals(this.mCurrentViewId)
                && (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
            if (!TextUtils.isEmpty(filterText)) {
                // TODO: we should be able to replace this with controller#filterInlineFillUiLocked
                // to accomplish filtering for augmented autofill.
                mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
            }
        }
@@ -2816,26 +2825,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            return false;
        }

        final ViewState currentView = mViewStates.get(focusedId);
        if ((currentView.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
            response.getDatasets().clear();
        }
        InlineSuggestionsResponse inlineSuggestionsResponse =
                InlineSuggestionFactory.createInlineSuggestionsResponse(
                        inlineSuggestionsRequest.get(), response, filterText, focusedId,
                        this, () -> {
        InlineFillUi inlineFillUi = InlineFillUi.forAutofill(
                inlineSuggestionsRequest.get(), response, focusedId, filterText,
                /*uiCallback*/this, /*onErrorCallback*/ () -> {
                    synchronized (mLock) {
                        mInlineSessionController.hideInlineSuggestionsUiLocked(
                                focusedId);
                    }
                }, remoteRenderService);
        if (inlineSuggestionsResponse == null) {
            Slog.w(TAG, "InlineSuggestionFactory created null response");
            return false;
        }

        return mInlineSessionController.onInlineSuggestionsResponseLocked(focusedId,
                inlineSuggestionsResponse);
        return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
    }

    boolean isDestroyed() {
@@ -3119,11 +3117,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState

        final AutofillId focusedId = mCurrentViewId;

        final Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsResponseCallback =
        final Function<InlineFillUi, Boolean> inlineSuggestionsResponseCallback =
                response -> {
                    synchronized (mLock) {
                        return mInlineSessionController.onInlineSuggestionsResponseLocked(
                                focusedId, response);
                        return mInlineSessionController.setInlineFillUiLocked(response);
                    }
                };
        final Consumer<InlineSuggestionsRequest> requestAugmentedAutofill =
+3 −3
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ final class FillUi {
    }

    FillUi(@NonNull Context context, @NonNull FillResponse response,
           @NonNull AutofillId focusedViewId, @NonNull @Nullable String filterText,
            @NonNull AutofillId focusedViewId, @Nullable String filterText,
            @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
            @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
        if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
Loading