• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.view;
18 
19 import static android.view.InsetsController.DEBUG;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.content.res.CompatibilityInfo;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.RemoteException;
28 import android.util.Log;
29 import android.view.inputmethod.ImeTracker;
30 import android.view.inputmethod.InputMethodManager;
31 
32 import java.util.List;
33 
34 /**
35  * Implements {@link InsetsController.Host} for {@link ViewRootImpl}s.
36  * @hide
37  */
38 public class ViewRootInsetsControllerHost implements InsetsController.Host {
39 
40     private final String TAG = "VRInsetsControllerHost";
41 
42     private final ViewRootImpl mViewRoot;
43     private SyncRtSurfaceTransactionApplier mApplier;
44 
ViewRootInsetsControllerHost(ViewRootImpl viewRoot)45     public ViewRootInsetsControllerHost(ViewRootImpl viewRoot) {
46         mViewRoot = viewRoot;
47     }
48 
49     @Override
getHandler()50     public Handler getHandler() {
51         return mViewRoot.mHandler;
52     }
53 
54     @Override
notifyInsetsChanged()55     public void notifyInsetsChanged() {
56         mViewRoot.notifyInsetsChanged();
57     }
58 
59     @Override
addOnPreDrawRunnable(Runnable r)60     public void addOnPreDrawRunnable(Runnable r) {
61         if (mViewRoot.mView == null) {
62             return;
63         }
64         mViewRoot.mView.getViewTreeObserver().addOnPreDrawListener(
65                 new ViewTreeObserver.OnPreDrawListener() {
66                     @Override
67                     public boolean onPreDraw() {
68                         mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this);
69                         r.run();
70                         return true;
71                     }
72                 });
73         mViewRoot.mView.invalidate();
74     }
75 
76     @Override
dispatchWindowInsetsAnimationPrepare(@onNull WindowInsetsAnimation animation)77     public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) {
78         if (mViewRoot.mView == null) {
79             return;
80         }
81         mViewRoot.mView.dispatchWindowInsetsAnimationPrepare(animation);
82     }
83 
84     @Override
dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds)85     public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart(
86             @NonNull WindowInsetsAnimation animation,
87             @NonNull WindowInsetsAnimation.Bounds bounds) {
88         if (mViewRoot.mView == null) {
89             return null;
90         }
91         if (DEBUG) Log.d(TAG, "windowInsetsAnimation started");
92         return mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds);
93     }
94 
95     @Override
dispatchWindowInsetsAnimationProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)96     public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets,
97             @NonNull List<WindowInsetsAnimation> runningAnimations) {
98         if (mViewRoot.mView == null) {
99             // The view has already detached from window.
100             return null;
101         }
102         if (DEBUG) {
103             for (WindowInsetsAnimation anim : runningAnimations) {
104                 Log.d(TAG, "windowInsetsAnimation progress: "
105                         + anim.getInterpolatedFraction());
106             }
107         }
108         return mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, runningAnimations);
109     }
110 
111     @Override
dispatchWindowInsetsAnimationEnd(@onNull WindowInsetsAnimation animation)112     public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) {
113         if (DEBUG) Log.d(TAG, "windowInsetsAnimation ended");
114         if (mViewRoot.mView == null) {
115             // The view has already detached from window.
116             return;
117         }
118         mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation);
119     }
120 
121     @Override
applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params)122     public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
123         if (mViewRoot.mView == null) {
124             throw new IllegalStateException("View of the ViewRootImpl is not initiated.");
125         }
126         if (mApplier == null) {
127             mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
128         }
129         if (mViewRoot.mView.isHardwareAccelerated() && isVisibleToUser()) {
130             mApplier.scheduleApply(params);
131         } else {
132             // Synchronization requires hardware acceleration for now.
133             // If the window isn't visible, drawing is paused and the applier won't run.
134             // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every
135             //  frame instead.
136             final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
137             mApplier.applyParams(t, params);
138             t.apply();
139         }
140     }
141 
142     @Override
postInsetsAnimationCallback(Runnable r)143     public void postInsetsAnimationCallback(Runnable r) {
144         mViewRoot.mChoreographer.postCallback(Choreographer.CALLBACK_INSETS_ANIMATION, r,
145                 null /* token */);
146     }
147 
148     @Override
updateCompatSysUiVisibility(int visibleTypes, int requestedVisibleTypes, int controllableTypes)149     public void updateCompatSysUiVisibility(int visibleTypes, int requestedVisibleTypes,
150             int controllableTypes) {
151         mViewRoot.updateCompatSysUiVisibility(visibleTypes, requestedVisibleTypes,
152                 controllableTypes);
153     }
154 
155     @Override
updateRequestedVisibleTypes(@indowInsets.Type.InsetsType int types, @Nullable ImeTracker.Token statsToken)156     public void updateRequestedVisibleTypes(@WindowInsets.Type.InsetsType int types,
157             @Nullable ImeTracker.Token statsToken) {
158         try {
159             if (mViewRoot.mAdded) {
160                 ImeTracker.forLogging().onProgress(statsToken,
161                         ImeTracker.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES);
162                 mViewRoot.mWindowSession.updateRequestedVisibleTypes(mViewRoot.mWindow, types,
163                         statsToken);
164             } else {
165                 ImeTracker.forLogging().onFailed(statsToken,
166                         ImeTracker.PHASE_CLIENT_UPDATE_REQUESTED_VISIBLE_TYPES);
167             }
168         } catch (RemoteException e) {
169             Log.e(TAG, "Failed to call insetsModified", e);
170         }
171     }
172 
173     @Override
updateAnimatingTypes(@indowInsets.Type.InsetsType int animatingTypes, @Nullable ImeTracker.Token statsToken)174     public void updateAnimatingTypes(@WindowInsets.Type.InsetsType int animatingTypes,
175             @Nullable ImeTracker.Token statsToken) {
176         if (mViewRoot != null) {
177             ImeTracker.forLogging().onProgress(statsToken,
178                     ImeTracker.PHASE_CLIENT_UPDATE_ANIMATING_TYPES);
179             mViewRoot.updateAnimatingTypes(animatingTypes, statsToken);
180         } else {
181             ImeTracker.forLogging().onFailed(statsToken,
182                     ImeTracker.PHASE_CLIENT_UPDATE_ANIMATING_TYPES);
183         }
184     }
185 
186     @Override
hasAnimationCallbacks()187     public boolean hasAnimationCallbacks() {
188         if (mViewRoot.mView == null) {
189             return false;
190         }
191         return mViewRoot.mView.hasWindowInsetsAnimationCallback();
192     }
193 
194     @Override
setSystemBarsAppearance(int appearance, int mask)195     public void setSystemBarsAppearance(int appearance, int mask) {
196         final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags;
197         final int newAppearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
198         if (insetsFlags.appearance != newAppearance) {
199             insetsFlags.appearance = newAppearance;
200             mViewRoot.mWindowAttributesChanged = true;
201             mViewRoot.scheduleTraversals();
202         }
203     }
204 
205     @Override
getSystemBarsAppearance()206     public int getSystemBarsAppearance() {
207         return mViewRoot.mWindowAttributes.insetsFlags.appearance;
208     }
209 
210     @Override
setSystemBarsBehavior(int behavior)211     public void setSystemBarsBehavior(int behavior) {
212         if (mViewRoot.mWindowAttributes.insetsFlags.behavior != behavior) {
213             mViewRoot.mWindowAttributes.insetsFlags.behavior = behavior;
214             mViewRoot.mWindowAttributesChanged = true;
215             mViewRoot.scheduleTraversals();
216         }
217     }
218 
219     @Override
getSystemBarsBehavior()220     public int getSystemBarsBehavior() {
221         return mViewRoot.mWindowAttributes.insetsFlags.behavior;
222     }
223 
224     @Override
releaseSurfaceControlFromRt(SurfaceControl surfaceControl)225     public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) {
226 
227          // At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
228          // setControl) we need to release the old leash. But we may have already scheduled
229          // a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid
230          // synchronization issues we also release from the RenderThread so this release
231          // happens after any existing items on the work queue.
232 
233         if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) {
234             mViewRoot.registerRtFrameCallback(frame -> {
235                 surfaceControl.release();
236             });
237             // Make sure a frame gets scheduled.
238             mViewRoot.mView.invalidate();
239         } else {
240             surfaceControl.release();
241         }
242     }
243 
244     @Override
getInputMethodManager()245     public InputMethodManager getInputMethodManager() {
246         return mViewRoot.mContext.getSystemService(InputMethodManager.class);
247     }
248 
249     @Override
getRootViewTitle()250     public String getRootViewTitle() {
251         if (mViewRoot == null) {
252             return null;
253         }
254         return mViewRoot.getTitle().toString();
255     }
256 
257     @Override
getRootViewContext()258     public Context getRootViewContext() {
259         return mViewRoot != null ? mViewRoot.mContext : null;
260     }
261 
262     @Override
dipToPx(int dips)263     public int dipToPx(int dips) {
264         if (mViewRoot != null) {
265             return mViewRoot.dipToPx(dips);
266         }
267         return 0;
268     }
269 
270     @Override
getWindowToken()271     public IBinder getWindowToken() {
272         if (mViewRoot == null) {
273             return null;
274         }
275         final View view = mViewRoot.getView();
276         if (view == null) {
277             return null;
278         }
279         return view.getWindowToken();
280     }
281 
282     @Override
getTranslator()283     public CompatibilityInfo.Translator getTranslator() {
284         if (mViewRoot != null) {
285             return mViewRoot.mTranslator;
286         }
287         return null;
288     }
289 
290     @Override
isHandlingPointerEvent()291     public boolean isHandlingPointerEvent() {
292         return mViewRoot != null && mViewRoot.isHandlingPointerEvent();
293     }
294 
isVisibleToUser()295     private boolean isVisibleToUser() {
296         return mViewRoot.getHostVisibility() == View.VISIBLE;
297     }
298 }
299