1 /*
2  * Copyright (C) 2019 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 android.view.inputmethod;
18 
19 import android.annotation.BinderThread;
20 import android.annotation.CallbackExecutor;
21 import android.annotation.MainThread;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.TestApi;
25 import android.content.Context;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 import android.os.RemoteException;
31 import android.util.Size;
32 import android.util.Slog;
33 import android.view.SurfaceControlViewHost;
34 import android.view.View;
35 import android.view.ViewGroup;
36 import android.widget.inline.InlineContentView;
37 
38 import com.android.internal.util.DataClass;
39 import com.android.internal.util.Parcelling;
40 import com.android.internal.view.inline.IInlineContentCallback;
41 import com.android.internal.view.inline.IInlineContentProvider;
42 import com.android.internal.view.inline.InlineTooltipUi;
43 
44 import java.lang.ref.WeakReference;
45 import java.util.concurrent.Executor;
46 import java.util.function.Consumer;
47 
48 /**
49  * This class represents an inline suggestion which is made by one app and can be embedded into the
50  * UI of another. Suggestions may contain sensitive information not known to the host app which
51  * needs to be protected from spoofing. To address that the suggestion view inflated on demand for
52  * embedding is created in such a way that the hosting app cannot introspect its content and cannot
53  * interact with it.
54  */
55 @DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstDefs = true,
56         genHiddenConstructor = true)
57 public final class InlineSuggestion implements Parcelable {
58 
59     private static final String TAG = "InlineSuggestion";
60 
61     @NonNull
62     private final InlineSuggestionInfo mInfo;
63 
64     /**
65      * @hide
66      */
67     @Nullable
68     private final IInlineContentProvider mContentProvider;
69 
70     /**
71      * Used to keep a strong reference to the callback so it doesn't get garbage collected.
72      *
73      * @hide
74      */
75     @DataClass.ParcelWith(InlineContentCallbackImplParceling.class)
76     @Nullable
77     private InlineContentCallbackImpl mInlineContentCallback;
78 
79     /**
80      * Used to show up the inline suggestion tooltip.
81      *
82      * @hide
83      */
84     @Nullable
85     @DataClass.ParcelWith(InlineTooltipUiParceling.class)
86     private InlineTooltipUi mInlineTooltipUi;
87 
88     /**
89      * Creates a new {@link InlineSuggestion}, for testing purpose.
90      *
91      * @hide
92      */
93     @TestApi
94     @NonNull
newInlineSuggestion(@onNull InlineSuggestionInfo info)95     public static InlineSuggestion newInlineSuggestion(@NonNull InlineSuggestionInfo info) {
96         return new InlineSuggestion(info, null, /* inlineContentCallback */ null,
97                 /* inlineTooltipUi */ null);
98     }
99 
100     /**
101      * Creates a new {@link InlineSuggestion}.
102      *
103      * @hide
104      */
InlineSuggestion(@onNull InlineSuggestionInfo info, @Nullable IInlineContentProvider contentProvider)105     public InlineSuggestion(@NonNull InlineSuggestionInfo info,
106             @Nullable IInlineContentProvider contentProvider) {
107         this(info, contentProvider, /* inlineContentCallback */ null, /* inlineTooltipUi */ null);
108     }
109 
110     /**
111      * Inflates a view with the content of this suggestion at a specific size.
112      *
113      * <p> Each dimension of the size must satisfy one of the following conditions:
114      *
115      * <ol>
116      *     <li>between {@link android.widget.inline.InlinePresentationSpec#getMinSize()} and
117      * {@link android.widget.inline.InlinePresentationSpec#getMaxSize()} of the presentation spec
118      * from {@code mInfo}
119      *     <li>{@link ViewGroup.LayoutParams#WRAP_CONTENT}
120      * </ol>
121      *
122      * If the size is set to {@link
123      * ViewGroup.LayoutParams#WRAP_CONTENT}, then the size of the inflated view will be just large
124      * enough to fit the content, while still conforming to the min / max size specified by the
125      * {@link android.widget.inline.InlinePresentationSpec}.
126      *
127      * <p> The caller can attach an {@link android.view.View.OnClickListener} and/or an
128      * {@link android.view.View.OnLongClickListener} to the view in the {@code callback} to receive
129      * click and long click events on the view.
130      *
131      * @param context  Context in which to inflate the view.
132      * @param size     The size at which to inflate the suggestion. For each dimension, it maybe an
133      *                 exact value or {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
134      * @param callback Callback for receiving the inflated view, where the {@link
135      *                 ViewGroup.LayoutParams} of the view is set as the actual size of the
136      *                 underlying remote view.
137      * @throws IllegalArgumentException If an invalid argument is passed.
138      * @throws IllegalStateException    If this method is already called.
139      */
inflate(@onNull Context context, @NonNull Size size, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull Consumer<InlineContentView> callback)140     public void inflate(@NonNull Context context, @NonNull Size size,
141             @NonNull @CallbackExecutor Executor callbackExecutor,
142             @NonNull Consumer<InlineContentView> callback) {
143         final Size minSize = mInfo.getInlinePresentationSpec().getMinSize();
144         final Size maxSize = mInfo.getInlinePresentationSpec().getMaxSize();
145         if (!isValid(size.getWidth(), minSize.getWidth(), maxSize.getWidth())
146                 || !isValid(size.getHeight(), minSize.getHeight(), maxSize.getHeight())) {
147             throw new IllegalArgumentException(
148                     "size is neither between min:" + minSize + " and max:" + maxSize
149                             + ", nor wrap_content");
150         }
151 
152         InlineSuggestion toolTip = mInfo.getTooltip();
153         if (toolTip != null) {
154             if (mInlineTooltipUi == null) {
155                 mInlineTooltipUi = new InlineTooltipUi(context);
156             }
157         } else {
158             mInlineTooltipUi = null;
159         }
160 
161         mInlineContentCallback = getInlineContentCallback(context, callbackExecutor, callback,
162                 mInlineTooltipUi);
163         if (mContentProvider == null) {
164             callbackExecutor.execute(() -> callback.accept(/* view */ null));
165             mInlineTooltipUi = null;
166             return;
167         }
168         try {
169             mContentProvider.provideContent(size.getWidth(), size.getHeight(),
170                     new InlineContentCallbackWrapper(mInlineContentCallback));
171         } catch (RemoteException e) {
172             Slog.w(TAG, "Error creating suggestion content surface: " + e);
173             callbackExecutor.execute(() -> callback.accept(/* view */ null));
174         }
175         if (toolTip == null) return;
176 
177         final Size tooltipSize = new Size(ViewGroup.LayoutParams.WRAP_CONTENT,
178                 ViewGroup.LayoutParams.WRAP_CONTENT);
179         mInfo.getTooltip().inflate(context, tooltipSize, callbackExecutor, view -> {
180             Handler.getMain().post(() -> mInlineTooltipUi.setTooltipView(view));
181         });
182     }
183 
184     /**
185      * Returns true if the {@code actual} length is within [min, max] or is {@link
186      * ViewGroup.LayoutParams#WRAP_CONTENT}.
187      */
isValid(int actual, int min, int max)188     private static boolean isValid(int actual, int min, int max) {
189         if (actual == ViewGroup.LayoutParams.WRAP_CONTENT) {
190             return true;
191         }
192         return actual >= min && actual <= max;
193     }
194 
getInlineContentCallback(Context context, Executor callbackExecutor, Consumer<InlineContentView> callback, InlineTooltipUi inlineTooltipUi)195     private synchronized InlineContentCallbackImpl getInlineContentCallback(Context context,
196             Executor callbackExecutor, Consumer<InlineContentView> callback,
197             InlineTooltipUi inlineTooltipUi) {
198         if (mInlineContentCallback != null) {
199             throw new IllegalStateException("Already called #inflate()");
200         }
201         return new InlineContentCallbackImpl(context, mContentProvider, callbackExecutor,
202                 callback, inlineTooltipUi);
203     }
204 
205     /**
206      * A wrapper class around the {@link InlineContentCallbackImpl} to ensure it's not strongly
207      * reference by the remote system server process.
208      */
209     private static final class InlineContentCallbackWrapper extends IInlineContentCallback.Stub {
210 
211         private final WeakReference<InlineContentCallbackImpl> mCallbackImpl;
212 
InlineContentCallbackWrapper(InlineContentCallbackImpl callbackImpl)213         InlineContentCallbackWrapper(InlineContentCallbackImpl callbackImpl) {
214             mCallbackImpl = new WeakReference<>(callbackImpl);
215         }
216 
217         @Override
218         @BinderThread
onContent(SurfaceControlViewHost.SurfacePackage content, int width, int height)219         public void onContent(SurfaceControlViewHost.SurfacePackage content, int width,
220                 int height) {
221             final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
222             if (callbackImpl != null) {
223                 callbackImpl.onContent(content, width, height);
224             }
225         }
226 
227         @Override
228         @BinderThread
onClick()229         public void onClick() {
230             final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
231             if (callbackImpl != null) {
232                 callbackImpl.onClick();
233             }
234         }
235 
236         @Override
237         @BinderThread
onLongClick()238         public void onLongClick() {
239             final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
240             if (callbackImpl != null) {
241                 callbackImpl.onLongClick();
242             }
243         }
244     }
245 
246     /**
247      * Handles the communication between the inline suggestion view in current (IME) process and
248      * the remote view provided from the system server.
249      *
250      * <p>This class is thread safe, because all the outside calls are piped into a single
251      * handler thread to be processed.
252      */
253     private static final class InlineContentCallbackImpl {
254 
255         @NonNull
256         private final Handler mMainHandler = new Handler(Looper.getMainLooper());
257 
258         @NonNull
259         private final Context mContext;
260         @Nullable
261         private final IInlineContentProvider mInlineContentProvider;
262         @NonNull
263         private final Executor mCallbackExecutor;
264 
265         /**
266          * Callback from the client (IME) that will receive the inflated suggestion view. It'll
267          * only be called once when the view SurfacePackage is first sent back to the client. Any
268          * updates to the view due to attach to window and detach from window events will be
269          * handled under the hood, transparent from the client.
270          */
271         @NonNull
272         private final Consumer<InlineContentView> mCallback;
273 
274         /**
275          * Indicates whether the first content has been received or not.
276          */
277         private boolean mFirstContentReceived = false;
278 
279         /**
280          * The client (IME) side view which internally wraps a remote view. It'll be set when
281          * {@link #onContent(SurfaceControlViewHost.SurfacePackage, int, int)} is called, which
282          * should only happen once in the lifecycle of this inline suggestion instance.
283          */
284         @Nullable
285         private InlineContentView mView;
286 
287         /**
288          * The SurfacePackage pointing to the remote view. It's cached here to be sent to the next
289          * available consumer.
290          */
291         @Nullable
292         private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
293 
294         /**
295          * The callback (from the {@link InlineContentView}) which consumes the surface package.
296          * It's cached here to be called when the SurfacePackage is returned from the remote
297          * view owning process.
298          */
299         @Nullable
300         private Consumer<SurfaceControlViewHost.SurfacePackage> mSurfacePackageConsumer;
301 
302         @Nullable
303         private InlineTooltipUi mInlineTooltipUi;
304 
InlineContentCallbackImpl(@onNull Context context, @Nullable IInlineContentProvider inlineContentProvider, @NonNull @CallbackExecutor Executor callbackExecutor, @NonNull Consumer<InlineContentView> callback, @Nullable InlineTooltipUi inlineTooltipUi)305         InlineContentCallbackImpl(@NonNull Context context,
306                 @Nullable IInlineContentProvider inlineContentProvider,
307                 @NonNull @CallbackExecutor Executor callbackExecutor,
308                 @NonNull Consumer<InlineContentView> callback,
309                 @Nullable InlineTooltipUi inlineTooltipUi) {
310             mContext = context;
311             mInlineContentProvider = inlineContentProvider;
312             mCallbackExecutor = callbackExecutor;
313             mCallback = callback;
314             mInlineTooltipUi = inlineTooltipUi;
315         }
316 
317         @BinderThread
onContent(SurfaceControlViewHost.SurfacePackage content, int width, int height)318         public void onContent(SurfaceControlViewHost.SurfacePackage content, int width,
319                 int height) {
320             mMainHandler.post(() -> handleOnContent(content, width, height));
321         }
322 
323         @MainThread
handleOnContent(SurfaceControlViewHost.SurfacePackage content, int width, int height)324         private void handleOnContent(SurfaceControlViewHost.SurfacePackage content, int width,
325                 int height) {
326             if (!mFirstContentReceived) {
327                 handleOnFirstContentReceived(content, width, height);
328                 mFirstContentReceived = true;
329             } else {
330                 handleOnSurfacePackage(content);
331             }
332         }
333 
334         /**
335          * Called when the view content is returned for the first time.
336          */
337         @MainThread
handleOnFirstContentReceived(SurfaceControlViewHost.SurfacePackage content, int width, int height)338         private void handleOnFirstContentReceived(SurfaceControlViewHost.SurfacePackage content,
339                 int width, int height) {
340             mSurfacePackage = content;
341             if (mSurfacePackage == null) {
342                 mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
343             } else {
344                 mView = new InlineContentView(mContext);
345                 if (mInlineTooltipUi != null) {
346                     mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
347                         @Override
348                         public void onLayoutChange(View v, int left, int top, int right,
349                                 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
350                             if (mInlineTooltipUi != null) {
351                                 mInlineTooltipUi.update(mView);
352                             }
353                         }
354                     });
355                 }
356                 mView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
357                 mView.setChildSurfacePackageUpdater(getSurfacePackageUpdater());
358                 mCallbackExecutor.execute(() -> mCallback.accept(mView));
359             }
360         }
361 
362         /**
363          * Called when any subsequent SurfacePackage is returned from the remote view owning
364          * process.
365          */
366         @MainThread
handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage)367         private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
368             if (surfacePackage == null) {
369                 return;
370             }
371             if (mSurfacePackage != null || mSurfacePackageConsumer == null) {
372                 // The surface package is not consumed, release it immediately.
373                 surfacePackage.release();
374                 try {
375                     mInlineContentProvider.onSurfacePackageReleased();
376                 } catch (RemoteException e) {
377                     Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
378                 }
379                 return;
380             }
381             mSurfacePackage = surfacePackage;
382             if (mSurfacePackage == null) {
383                 return;
384             }
385             if (mSurfacePackageConsumer != null) {
386                 mSurfacePackageConsumer.accept(mSurfacePackage);
387                 mSurfacePackageConsumer = null;
388             }
389         }
390 
391         @MainThread
handleOnSurfacePackageReleased()392         private void handleOnSurfacePackageReleased() {
393             if (mSurfacePackage != null) {
394                 try {
395                     mInlineContentProvider.onSurfacePackageReleased();
396                 } catch (RemoteException e) {
397                     Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
398                 }
399                 mSurfacePackage = null;
400             }
401             // Clear the pending surface package consumer, if any. This can happen if the IME
402             // attaches the view to window and then quickly detaches it from the window, before
403             // the surface package requested upon attaching to window was returned.
404             mSurfacePackageConsumer = null;
405         }
406 
407         @MainThread
handleGetSurfacePackage( Consumer<SurfaceControlViewHost.SurfacePackage> consumer)408         private void handleGetSurfacePackage(
409                 Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
410             if (mSurfacePackage != null) {
411                 consumer.accept(mSurfacePackage);
412             } else {
413                 mSurfacePackageConsumer = consumer;
414                 try {
415                     mInlineContentProvider.requestSurfacePackage();
416                 } catch (RemoteException e) {
417                     Slog.w(TAG, "Error calling getSurfacePackage(): " + e);
418                     consumer.accept(null);
419                     mSurfacePackageConsumer = null;
420                 }
421             }
422         }
423 
getSurfacePackageUpdater()424         private InlineContentView.SurfacePackageUpdater getSurfacePackageUpdater() {
425             return new InlineContentView.SurfacePackageUpdater() {
426                 @Override
427                 public void onSurfacePackageReleased() {
428                     mMainHandler.post(
429                             () -> InlineContentCallbackImpl.this.handleOnSurfacePackageReleased());
430                 }
431 
432                 @Override
433                 public void getSurfacePackage(
434                         Consumer<SurfaceControlViewHost.SurfacePackage> consumer) {
435                     mMainHandler.post(
436                             () -> InlineContentCallbackImpl.this.handleGetSurfacePackage(consumer));
437                 }
438             };
439         }
440 
441         @BinderThread
onClick()442         public void onClick() {
443             mMainHandler.post(() -> {
444                 if (mView != null && mView.hasOnClickListeners()) {
445                     mView.callOnClick();
446                 }
447             });
448         }
449 
450         @BinderThread
onLongClick()451         public void onLongClick() {
452             mMainHandler.post(() -> {
453                 if (mView != null && mView.hasOnLongClickListeners()) {
454                     mView.performLongClick();
455                 }
456             });
457         }
458     }
459 
460     /**
461      * This class used to provide parcelling logic for InlineContentCallbackImpl. It's intended to
462      * make this parcelling a no-op, since it can't be parceled and we don't need to parcel it.
463      */
464     private static class InlineContentCallbackImplParceling implements
465             Parcelling<InlineContentCallbackImpl> {
466         @Override
467         public void parcel(InlineContentCallbackImpl item, Parcel dest, int parcelFlags) {
468         }
469 
470         @Override
471         public InlineContentCallbackImpl unparcel(Parcel source) {
472             return null;
473         }
474     }
475 
476     /**
477      * This class used to provide parcelling logic for InlineContentCallbackImpl. It's intended to
478      * make this parcelling a no-op, since it can't be parceled and we don't need to parcel it.
479      */
480     private static class InlineTooltipUiParceling implements
481             Parcelling<InlineTooltipUi> {
482         @Override
483         public void parcel(InlineTooltipUi item, Parcel dest, int parcelFlags) {
484         }
485 
486         @Override
487         public InlineTooltipUi unparcel(Parcel source) {
488             return null;
489         }
490     }
491 
492 
493 
494     // Code below generated by codegen v1.0.22.
495     //
496     // DO NOT MODIFY!
497     // CHECKSTYLE:OFF Generated code
498     //
499     // To regenerate run:
500     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java
501     //
502     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
503     //   Settings > Editor > Code Style > Formatter Control
504     //@formatter:off
505 
506 
507     /**
508      * Creates a new InlineSuggestion.
509      *
510      * @param inlineContentCallback
511      *   Used to keep a strong reference to the callback so it doesn't get garbage collected.
512      * @param inlineTooltipUi
513      *   Used to show up the inline suggestion tooltip.
514      * @hide
515      */
516     @DataClass.Generated.Member
517     public InlineSuggestion(
518             @NonNull InlineSuggestionInfo info,
519             @Nullable IInlineContentProvider contentProvider,
520             @Nullable InlineContentCallbackImpl inlineContentCallback,
521             @Nullable InlineTooltipUi inlineTooltipUi) {
522         this.mInfo = info;
523         com.android.internal.util.AnnotationValidations.validate(
524                 NonNull.class, null, mInfo);
525         this.mContentProvider = contentProvider;
526         this.mInlineContentCallback = inlineContentCallback;
527         this.mInlineTooltipUi = inlineTooltipUi;
528 
529         // onConstructed(); // You can define this method to get a callback
530     }
531 
532     @DataClass.Generated.Member
533     public @NonNull InlineSuggestionInfo getInfo() {
534         return mInfo;
535     }
536 
537     /**
538      * @hide
539      */
540     @DataClass.Generated.Member
541     public @Nullable IInlineContentProvider getContentProvider() {
542         return mContentProvider;
543     }
544 
545     /**
546      * Used to keep a strong reference to the callback so it doesn't get garbage collected.
547      *
548      * @hide
549      */
550     @DataClass.Generated.Member
551     public @Nullable InlineContentCallbackImpl getInlineContentCallback() {
552         return mInlineContentCallback;
553     }
554 
555     /**
556      * Used to show up the inline suggestion tooltip.
557      *
558      * @hide
559      */
560     @DataClass.Generated.Member
561     public @Nullable InlineTooltipUi getInlineTooltipUi() {
562         return mInlineTooltipUi;
563     }
564 
565     @Override
566     @DataClass.Generated.Member
567     public String toString() {
568         // You can override field toString logic by defining methods like:
569         // String fieldNameToString() { ... }
570 
571         return "InlineSuggestion { " +
572                 "info = " + mInfo + ", " +
573                 "contentProvider = " + mContentProvider + ", " +
574                 "inlineContentCallback = " + mInlineContentCallback + ", " +
575                 "inlineTooltipUi = " + mInlineTooltipUi +
576         " }";
577     }
578 
579     @Override
580     @DataClass.Generated.Member
581     public boolean equals(@Nullable Object o) {
582         // You can override field equality logic by defining either of the methods like:
583         // boolean fieldNameEquals(InlineSuggestion other) { ... }
584         // boolean fieldNameEquals(FieldType otherValue) { ... }
585 
586         if (this == o) return true;
587         if (o == null || getClass() != o.getClass()) return false;
588         @SuppressWarnings("unchecked")
589         InlineSuggestion that = (InlineSuggestion) o;
590         //noinspection PointlessBooleanExpression
591         return true
592                 && java.util.Objects.equals(mInfo, that.mInfo)
593                 && java.util.Objects.equals(mContentProvider, that.mContentProvider)
594                 && java.util.Objects.equals(mInlineContentCallback, that.mInlineContentCallback)
595                 && java.util.Objects.equals(mInlineTooltipUi, that.mInlineTooltipUi);
596     }
597 
598     @Override
599     @DataClass.Generated.Member
600     public int hashCode() {
601         // You can override field hashCode logic by defining methods like:
602         // int fieldNameHashCode() { ... }
603 
604         int _hash = 1;
605         _hash = 31 * _hash + java.util.Objects.hashCode(mInfo);
606         _hash = 31 * _hash + java.util.Objects.hashCode(mContentProvider);
607         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineContentCallback);
608         _hash = 31 * _hash + java.util.Objects.hashCode(mInlineTooltipUi);
609         return _hash;
610     }
611 
612     @DataClass.Generated.Member
613     static Parcelling<InlineContentCallbackImpl> sParcellingForInlineContentCallback =
614             Parcelling.Cache.get(
615                     InlineContentCallbackImplParceling.class);
616     static {
617         if (sParcellingForInlineContentCallback == null) {
618             sParcellingForInlineContentCallback = Parcelling.Cache.put(
619                     new InlineContentCallbackImplParceling());
620         }
621     }
622 
623     @DataClass.Generated.Member
624     static Parcelling<InlineTooltipUi> sParcellingForInlineTooltipUi =
625             Parcelling.Cache.get(
626                     InlineTooltipUiParceling.class);
627     static {
628         if (sParcellingForInlineTooltipUi == null) {
629             sParcellingForInlineTooltipUi = Parcelling.Cache.put(
630                     new InlineTooltipUiParceling());
631         }
632     }
633 
634     @Override
635     @DataClass.Generated.Member
636     public void writeToParcel(@NonNull Parcel dest, int flags) {
637         // You can override field parcelling by defining methods like:
638         // void parcelFieldName(Parcel dest, int flags) { ... }
639 
640         byte flg = 0;
641         if (mContentProvider != null) flg |= 0x2;
642         if (mInlineContentCallback != null) flg |= 0x4;
643         if (mInlineTooltipUi != null) flg |= 0x8;
644         dest.writeByte(flg);
645         dest.writeTypedObject(mInfo, flags);
646         if (mContentProvider != null) dest.writeStrongInterface(mContentProvider);
647         sParcellingForInlineContentCallback.parcel(mInlineContentCallback, dest, flags);
648         sParcellingForInlineTooltipUi.parcel(mInlineTooltipUi, dest, flags);
649     }
650 
651     @Override
652     @DataClass.Generated.Member
653     public int describeContents() { return 0; }
654 
655     /** @hide */
656     @SuppressWarnings({"unchecked", "RedundantCast"})
657     @DataClass.Generated.Member
658     /* package-private */ InlineSuggestion(@NonNull Parcel in) {
659         // You can override field unparcelling by defining methods like:
660         // static FieldType unparcelFieldName(Parcel in) { ... }
661 
662         byte flg = in.readByte();
663         InlineSuggestionInfo info = (InlineSuggestionInfo) in.readTypedObject(InlineSuggestionInfo.CREATOR);
664         IInlineContentProvider contentProvider = (flg & 0x2) == 0 ? null : IInlineContentProvider.Stub.asInterface(in.readStrongBinder());
665         InlineContentCallbackImpl inlineContentCallback = sParcellingForInlineContentCallback.unparcel(in);
666         InlineTooltipUi inlineTooltipUi = sParcellingForInlineTooltipUi.unparcel(in);
667 
668         this.mInfo = info;
669         com.android.internal.util.AnnotationValidations.validate(
670                 NonNull.class, null, mInfo);
671         this.mContentProvider = contentProvider;
672         this.mInlineContentCallback = inlineContentCallback;
673         this.mInlineTooltipUi = inlineTooltipUi;
674 
675         // onConstructed(); // You can define this method to get a callback
676     }
677 
678     @DataClass.Generated.Member
679     public static final @NonNull Parcelable.Creator<InlineSuggestion> CREATOR
680             = new Parcelable.Creator<InlineSuggestion>() {
681         @Override
682         public InlineSuggestion[] newArray(int size) {
683             return new InlineSuggestion[size];
684         }
685 
686         @Override
687         public InlineSuggestion createFromParcel(@NonNull Parcel in) {
688             return new InlineSuggestion(in);
689         }
690     };
691 
692     @DataClass.Generated(
693             time = 1615562097666L,
694             codegenVersion = "1.0.22",
695             sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
696             inputSignatures = "private static final  java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineTooltipUiParceling.class) com.android.internal.view.inline.InlineTooltipUi mInlineTooltipUi\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic  void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>)\nprivate static  boolean isValid(int,int,int)\nprivate synchronized  android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.widget.inline.InlineContentView>,com.android.internal.view.inline.InlineTooltipUi)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
697     @Deprecated
698     private void __metadata() {}
699 
700 
701     //@formatter:on
702     // End of generated code
703 
704 }
705