1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.autofill.ui;
18 
19 import static com.android.server.autofill.Helper.sDebug;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.IntentSender;
24 import android.os.IBinder;
25 import android.service.autofill.IInlineSuggestionUiCallback;
26 import android.service.autofill.InlinePresentation;
27 import android.util.Slog;
28 
29 import com.android.server.LocalServices;
30 import com.android.server.autofill.Helper;
31 import com.android.server.autofill.RemoteInlineSuggestionRenderService;
32 import com.android.server.inputmethod.InputMethodManagerInternal;
33 
34 import java.util.function.Consumer;
35 
36 /**
37  * Wraps the parameters needed to create a new inline suggestion view in the remote renderer
38  * service, and handles the callback from the events on the created remote view.
39  */
40 final class RemoteInlineSuggestionViewConnector {
41     private static final String TAG = RemoteInlineSuggestionViewConnector.class.getSimpleName();
42 
43     @Nullable private final RemoteInlineSuggestionRenderService mRemoteRenderService;
44     @NonNull private final InlinePresentation mInlinePresentation;
45     @Nullable private final IBinder mHostInputToken;
46     private final int mDisplayId;
47     private final int mUserId;
48     private final int mSessionId;
49 
50     @NonNull private final Runnable mOnAutofillCallback;
51     @NonNull private final Runnable mOnErrorCallback;
52     @NonNull private final Runnable mOnInflateCallback;
53     @NonNull private final Consumer<IntentSender> mStartIntentSenderFromClientApp;
54 
RemoteInlineSuggestionViewConnector( @onNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo, @NonNull InlinePresentation inlinePresentation, @NonNull Runnable onAutofillCallback, @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback)55     RemoteInlineSuggestionViewConnector(
56             @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
57             @NonNull InlinePresentation inlinePresentation,
58             @NonNull Runnable onAutofillCallback,
59             @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
60         mRemoteRenderService = inlineFillUiInfo.mRemoteRenderService;
61         mInlinePresentation = inlinePresentation;
62         mHostInputToken = inlineFillUiInfo.mInlineRequest.getHostInputToken();
63         mDisplayId = inlineFillUiInfo.mInlineRequest.getHostDisplayId();
64         mUserId = inlineFillUiInfo.mUserId;
65         mSessionId = inlineFillUiInfo.mSessionId;
66 
67         mOnAutofillCallback = onAutofillCallback;
68         mOnErrorCallback = uiCallback::onError;
69         mOnInflateCallback = uiCallback::onInflate;
70         mStartIntentSenderFromClientApp = uiCallback::startIntentSender;
71     }
72 
73     /**
74      * Calls the remote renderer service to create a new inline suggestion view.
75      *
76      * @return true if the call is made to the remote renderer service, false otherwise.
77      */
renderSuggestion( int width, int height, @NonNull IInlineSuggestionUiCallback callback)78     public boolean renderSuggestion(
79             int width, int height, @NonNull IInlineSuggestionUiCallback callback) {
80         if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) {
81             if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion.");
82             return false;
83         }
84         if (mRemoteRenderService != null) {
85             if (sDebug) Slog.d(TAG, "Request to recreate the UI");
86             mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height,
87                     mHostInputToken, mDisplayId, mUserId, mSessionId);
88             return true;
89         }
90         return false;
91     }
92 
93     /**
94      * Handles the callback for the event of remote view being clicked.
95      */
onClick()96     public void onClick() {
97         mOnAutofillCallback.run();
98     }
99 
100     /**
101      * Handles the callback for the remote error when creating or interacting with the view.
102      */
onError()103     public void onError() {
104         mOnErrorCallback.run();
105     }
106 
onRender()107     public void onRender() {
108         mOnInflateCallback.run();
109     }
110 
111     /**
112      * Handles the callback for transferring the touch event on the remote view to the IME
113      * process.
114      */
onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId)115     public void onTransferTouchFocusToImeWindow(IBinder sourceInputToken, int displayId) {
116         final InputMethodManagerInternal inputMethodManagerInternal =
117                 LocalServices.getService(InputMethodManagerInternal.class);
118         if (!inputMethodManagerInternal.transferTouchFocusToImeWindow(sourceInputToken,
119                 displayId)) {
120             Slog.e(TAG, "Cannot transfer touch focus from suggestion to IME");
121             mOnErrorCallback.run();
122         }
123     }
124 
125     /**
126      * Handles starting an intent sender from the client app's process.
127      */
onStartIntentSender(IntentSender intentSender)128     public void onStartIntentSender(IntentSender intentSender) {
129         mStartIntentSenderFromClientApp.accept(intentSender);
130     }
131 }
132