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