• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.systemui.statusbar.phone;
18 
19 import static com.android.systemui.DejankUtils.whitelistIpcs;
20 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
21 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
22 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
23 
24 import android.animation.ValueAnimator;
25 import android.annotation.ColorInt;
26 import android.content.Context;
27 import android.content.res.Configuration;
28 import android.content.res.Resources;
29 import android.graphics.Color;
30 import android.graphics.Rect;
31 import android.graphics.drawable.Drawable;
32 import android.os.UserManager;
33 import android.util.AttributeSet;
34 import android.util.Pair;
35 import android.util.TypedValue;
36 import android.view.DisplayCutout;
37 import android.view.Gravity;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.ViewTreeObserver;
41 import android.view.WindowInsets;
42 import android.widget.ImageView;
43 import android.widget.LinearLayout;
44 import android.widget.RelativeLayout;
45 import android.widget.TextView;
46 
47 import com.android.settingslib.Utils;
48 import com.android.systemui.BatteryMeterView;
49 import com.android.systemui.Dependency;
50 import com.android.systemui.R;
51 import com.android.systemui.animation.Interpolators;
52 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
53 import com.android.systemui.statusbar.FeatureFlags;
54 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
55 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
56 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
57 import com.android.systemui.statusbar.policy.BatteryController;
58 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
59 import com.android.systemui.statusbar.policy.ConfigurationController;
60 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
61 import com.android.systemui.statusbar.policy.UserInfoController;
62 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
63 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
64 
65 import java.io.FileDescriptor;
66 import java.io.PrintWriter;
67 import java.util.ArrayList;
68 import java.util.List;
69 
70 /**
71  * The header group on Keyguard.
72  */
73 public class KeyguardStatusBarView extends RelativeLayout implements
74         BatteryStateChangeCallback,
75         OnUserInfoChangedListener,
76         ConfigurationListener,
77         SystemStatusAnimationCallback {
78 
79     private static final int LAYOUT_NONE = 0;
80     private static final int LAYOUT_CUTOUT = 1;
81     private static final int LAYOUT_NO_CUTOUT = 2;
82 
83     private final Rect mEmptyRect = new Rect(0, 0, 0, 0);
84 
85     private boolean mShowPercentAvailable;
86     private boolean mBatteryCharging;
87     private boolean mBatteryListening;
88 
89     private TextView mCarrierLabel;
90     private ImageView mMultiUserAvatar;
91     private BatteryMeterView mBatteryView;
92     private StatusIconContainer mStatusIconContainer;
93 
94     private BatteryController mBatteryController;
95     private boolean mKeyguardUserSwitcherEnabled;
96     private final UserManager mUserManager;
97 
98     private int mSystemIconsSwitcherHiddenExpandedMargin;
99     private int mSystemIconsBaseMargin;
100     private View mSystemIconsContainer;
101     private TintedIconManager mIconManager;
102     private List<String> mBlockedIcons = new ArrayList<>();
103 
104     private View mCutoutSpace;
105     private ViewGroup mStatusIconArea;
106     private int mLayoutState = LAYOUT_NONE;
107 
108     private SystemStatusAnimationScheduler mAnimationScheduler;
109     private FeatureFlags mFeatureFlags;
110 
111     /**
112      * Draw this many pixels into the left/right side of the cutout to optimally use the space
113      */
114     private int mCutoutSideNudge = 0;
115 
116     private DisplayCutout mDisplayCutout;
117     private int mRoundedCornerPadding = 0;
118     // right and left padding applied to this view to account for cutouts and rounded corners
119     private Pair<Integer, Integer> mPadding = new Pair(0, 0);
120 
121     /**
122      * The clipping on the top
123      */
124     private int mTopClipping;
125     private final Rect mClipRect = new Rect(0, 0, 0, 0);
126 
KeyguardStatusBarView(Context context, AttributeSet attrs)127     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
128         super(context, attrs);
129         mUserManager = UserManager.get(getContext());
130     }
131 
132     @Override
onFinishInflate()133     protected void onFinishInflate() {
134         super.onFinishInflate();
135         mSystemIconsContainer = findViewById(R.id.system_icons_container);
136         mMultiUserAvatar = findViewById(R.id.multi_user_avatar);
137         mCarrierLabel = findViewById(R.id.keyguard_carrier_text);
138         mBatteryView = mSystemIconsContainer.findViewById(R.id.battery);
139         mCutoutSpace = findViewById(R.id.cutout_space_view);
140         mStatusIconArea = findViewById(R.id.status_icon_area);
141         mStatusIconContainer = findViewById(R.id.statusIcons);
142 
143         loadDimens();
144         loadBlockList();
145         mBatteryController = Dependency.get(BatteryController.class);
146         mAnimationScheduler = Dependency.get(SystemStatusAnimationScheduler.class);
147         mFeatureFlags = Dependency.get(FeatureFlags.class);
148     }
149 
150     @Override
onConfigurationChanged(Configuration newConfig)151     protected void onConfigurationChanged(Configuration newConfig) {
152         super.onConfigurationChanged(newConfig);
153 
154         MarginLayoutParams lp = (MarginLayoutParams) mMultiUserAvatar.getLayoutParams();
155         lp.width = lp.height = getResources().getDimensionPixelSize(
156                 R.dimen.multi_user_avatar_keyguard_size);
157         mMultiUserAvatar.setLayoutParams(lp);
158 
159         // System icons
160         lp = (MarginLayoutParams) mSystemIconsContainer.getLayoutParams();
161         lp.setMarginStart(getResources().getDimensionPixelSize(
162                 R.dimen.system_icons_super_container_margin_start));
163         mSystemIconsContainer.setLayoutParams(lp);
164         mSystemIconsContainer.setPaddingRelative(mSystemIconsContainer.getPaddingStart(),
165                 mSystemIconsContainer.getPaddingTop(),
166                 getResources().getDimensionPixelSize(R.dimen.system_icons_keyguard_padding_end),
167                 mSystemIconsContainer.getPaddingBottom());
168 
169         // Respect font size setting.
170         mCarrierLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
171                 getResources().getDimensionPixelSize(
172                         com.android.internal.R.dimen.text_size_small_material));
173         lp = (MarginLayoutParams) mCarrierLabel.getLayoutParams();
174 
175         int marginStart = calculateMargin(
176                 getResources().getDimensionPixelSize(R.dimen.keyguard_carrier_text_margin),
177                 mPadding.first);
178         lp.setMarginStart(marginStart);
179 
180         mCarrierLabel.setLayoutParams(lp);
181         updateKeyguardStatusBarHeight();
182     }
183 
updateKeyguardStatusBarHeight()184     private void updateKeyguardStatusBarHeight() {
185         final int waterfallTop =
186                 mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
187         MarginLayoutParams lp =  (MarginLayoutParams) getLayoutParams();
188         lp.height =  getResources().getDimensionPixelSize(
189                 R.dimen.status_bar_header_height_keyguard) + waterfallTop;
190         setLayoutParams(lp);
191     }
192 
loadDimens()193     private void loadDimens() {
194         Resources res = getResources();
195         mSystemIconsSwitcherHiddenExpandedMargin = res.getDimensionPixelSize(
196                 R.dimen.system_icons_switcher_hidden_expanded_margin);
197         mSystemIconsBaseMargin = res.getDimensionPixelSize(
198                 R.dimen.system_icons_super_container_avatarless_margin_end);
199         mCutoutSideNudge = getResources().getDimensionPixelSize(
200                 R.dimen.display_cutout_margin_consumption);
201         mShowPercentAvailable = getContext().getResources().getBoolean(
202                 com.android.internal.R.bool.config_battery_percentage_setting_available);
203         mRoundedCornerPadding = res.getDimensionPixelSize(
204                 R.dimen.rounded_corner_content_padding);
205     }
206 
207     // Set hidden status bar items
loadBlockList()208     private void loadBlockList() {
209         Resources r = getResources();
210         mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_volume));
211         mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_alarm_clock));
212         mBlockedIcons.add(r.getString(com.android.internal.R.string.status_bar_call_strength));
213     }
214 
updateVisibilities()215     private void updateVisibilities() {
216         if (mMultiUserAvatar.getParent() != mStatusIconArea
217                 && !mKeyguardUserSwitcherEnabled) {
218             if (mMultiUserAvatar.getParent() != null) {
219                 getOverlay().remove(mMultiUserAvatar);
220             }
221             mStatusIconArea.addView(mMultiUserAvatar, 0);
222         } else if (mMultiUserAvatar.getParent() == mStatusIconArea
223                 && mKeyguardUserSwitcherEnabled) {
224             mStatusIconArea.removeView(mMultiUserAvatar);
225         }
226         if (!mKeyguardUserSwitcherEnabled) {
227             // If we have no keyguard switcher, the screen width is under 600dp. In this case,
228             // we only show the multi-user switch if it's enabled through UserManager as well as
229             // by the user.
230             // TODO(b/138661450) Move IPC calls to background
231             boolean isMultiUserEnabled = whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled(
232                     mContext.getResources().getBoolean(
233                             R.bool.qs_show_user_switcher_for_single_user)));
234             if (isMultiUserEnabled) {
235                 mMultiUserAvatar.setVisibility(View.VISIBLE);
236             } else {
237                 mMultiUserAvatar.setVisibility(View.GONE);
238             }
239         }
240         mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable);
241     }
242 
updateSystemIconsLayoutParams()243     private void updateSystemIconsLayoutParams() {
244         LinearLayout.LayoutParams lp =
245                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
246         // If the avatar icon is gone, we need to have some end margin to display the system icons
247         // correctly.
248         int baseMarginEnd = mMultiUserAvatar.getVisibility() == View.GONE
249                 ? mSystemIconsBaseMargin
250                 : 0;
251         int marginEnd =
252                 mKeyguardUserSwitcherEnabled ? mSystemIconsSwitcherHiddenExpandedMargin
253                         : baseMarginEnd;
254         marginEnd = calculateMargin(marginEnd, mPadding.second);
255         if (marginEnd != lp.getMarginEnd()) {
256             lp.setMarginEnd(marginEnd);
257             mSystemIconsContainer.setLayoutParams(lp);
258         }
259     }
260 
261     @Override
onApplyWindowInsets(WindowInsets insets)262     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
263         mLayoutState = LAYOUT_NONE;
264         if (updateLayoutConsideringCutout()) {
265             requestLayout();
266         }
267         return super.onApplyWindowInsets(insets);
268     }
269 
updateLayoutConsideringCutout()270     private boolean updateLayoutConsideringCutout() {
271         mDisplayCutout = getRootWindowInsets().getDisplayCutout();
272         updateKeyguardStatusBarHeight();
273 
274         Pair<Integer, Integer> cornerCutoutMargins =
275                 StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay());
276         updatePadding(cornerCutoutMargins);
277         if (mDisplayCutout == null || cornerCutoutMargins != null) {
278             return updateLayoutParamsNoCutout();
279         } else {
280             return updateLayoutParamsForCutout();
281         }
282     }
283 
updatePadding(Pair<Integer, Integer> cornerCutoutMargins)284     private void updatePadding(Pair<Integer, Integer> cornerCutoutMargins) {
285         final int waterfallTop =
286                 mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
287         mPadding =
288                 StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
289                         mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
290         setPadding(mPadding.first, waterfallTop, mPadding.second, 0);
291     }
292 
updateLayoutParamsNoCutout()293     private boolean updateLayoutParamsNoCutout() {
294         if (mLayoutState == LAYOUT_NO_CUTOUT) {
295             return false;
296         }
297         mLayoutState = LAYOUT_NO_CUTOUT;
298 
299         if (mCutoutSpace != null) {
300             mCutoutSpace.setVisibility(View.GONE);
301         }
302 
303         RelativeLayout.LayoutParams lp = (LayoutParams) mCarrierLabel.getLayoutParams();
304         lp.addRule(RelativeLayout.START_OF, R.id.status_icon_area);
305 
306         lp = (LayoutParams) mStatusIconArea.getLayoutParams();
307         lp.removeRule(RelativeLayout.RIGHT_OF);
308         lp.width = LayoutParams.WRAP_CONTENT;
309 
310         LinearLayout.LayoutParams llp =
311                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
312         llp.setMarginStart(getResources().getDimensionPixelSize(
313                 R.dimen.system_icons_super_container_margin_start));
314         return true;
315     }
316 
updateLayoutParamsForCutout()317     private boolean updateLayoutParamsForCutout() {
318         if (mLayoutState == LAYOUT_CUTOUT) {
319             return false;
320         }
321         mLayoutState = LAYOUT_CUTOUT;
322 
323         if (mCutoutSpace == null) {
324             updateLayoutParamsNoCutout();
325         }
326 
327         Rect bounds = new Rect();
328         boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
329 
330         mCutoutSpace.setVisibility(View.VISIBLE);
331         RelativeLayout.LayoutParams lp = (LayoutParams) mCutoutSpace.getLayoutParams();
332         bounds.left = bounds.left + mCutoutSideNudge;
333         bounds.right = bounds.right - mCutoutSideNudge;
334         lp.width = bounds.width();
335         lp.height = bounds.height();
336         lp.addRule(RelativeLayout.CENTER_IN_PARENT);
337 
338         lp = (LayoutParams) mCarrierLabel.getLayoutParams();
339         lp.addRule(RelativeLayout.START_OF, R.id.cutout_space_view);
340 
341         lp = (LayoutParams) mStatusIconArea.getLayoutParams();
342         lp.addRule(RelativeLayout.RIGHT_OF, R.id.cutout_space_view);
343         lp.width = LayoutParams.MATCH_PARENT;
344 
345         LinearLayout.LayoutParams llp =
346                 (LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
347         llp.setMarginStart(0);
348         return true;
349     }
350 
setListening(boolean listening)351     public void setListening(boolean listening) {
352         if (listening == mBatteryListening) {
353             return;
354         }
355         mBatteryListening = listening;
356         if (mBatteryListening) {
357             mBatteryController.addCallback(this);
358         } else {
359             mBatteryController.removeCallback(this);
360         }
361     }
362 
363     @Override
onAttachedToWindow()364     protected void onAttachedToWindow() {
365         super.onAttachedToWindow();
366         UserInfoController userInfoController = Dependency.get(UserInfoController.class);
367         userInfoController.addCallback(this);
368         userInfoController.reloadUserInfo();
369         Dependency.get(ConfigurationController.class).addCallback(this);
370         mIconManager = new TintedIconManager(findViewById(R.id.statusIcons), mFeatureFlags);
371         mIconManager.setBlockList(mBlockedIcons);
372         Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
373         mAnimationScheduler.addCallback(this);
374         onThemeChanged();
375     }
376 
377     @Override
onDetachedFromWindow()378     protected void onDetachedFromWindow() {
379         super.onDetachedFromWindow();
380         Dependency.get(UserInfoController.class).removeCallback(this);
381         Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
382         Dependency.get(ConfigurationController.class).removeCallback(this);
383         mAnimationScheduler.removeCallback(this);
384     }
385 
386     @Override
onUserInfoChanged(String name, Drawable picture, String userAccount)387     public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
388         mMultiUserAvatar.setImageDrawable(picture);
389     }
390 
391     @Override
onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging)392     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
393         if (mBatteryCharging != charging) {
394             mBatteryCharging = charging;
395             updateVisibilities();
396         }
397     }
398 
399     @Override
onPowerSaveChanged(boolean isPowerSave)400     public void onPowerSaveChanged(boolean isPowerSave) {
401         // could not care less
402     }
403 
setKeyguardUserSwitcherEnabled(boolean enabled)404     public void setKeyguardUserSwitcherEnabled(boolean enabled) {
405         mKeyguardUserSwitcherEnabled = enabled;
406     }
407 
animateNextLayoutChange()408     private void animateNextLayoutChange() {
409         final int systemIconsCurrentX = mSystemIconsContainer.getLeft();
410         final boolean userAvatarVisible = mMultiUserAvatar.getParent() == mStatusIconArea;
411         getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
412             @Override
413             public boolean onPreDraw() {
414                 getViewTreeObserver().removeOnPreDrawListener(this);
415                 boolean userAvatarHiding = userAvatarVisible
416                         && mMultiUserAvatar.getParent() != mStatusIconArea;
417                 mSystemIconsContainer.setX(systemIconsCurrentX);
418                 mSystemIconsContainer.animate()
419                         .translationX(0)
420                         .setDuration(400)
421                         .setStartDelay(userAvatarHiding ? 300 : 0)
422                         .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
423                         .start();
424                 if (userAvatarHiding) {
425                     getOverlay().add(mMultiUserAvatar);
426                     mMultiUserAvatar.animate()
427                             .alpha(0f)
428                             .setDuration(300)
429                             .setStartDelay(0)
430                             .setInterpolator(Interpolators.ALPHA_OUT)
431                             .withEndAction(() -> {
432                                 mMultiUserAvatar.setAlpha(1f);
433                                 getOverlay().remove(mMultiUserAvatar);
434                             })
435                             .start();
436 
437                 } else {
438                     mMultiUserAvatar.setAlpha(0f);
439                     mMultiUserAvatar.animate()
440                             .alpha(1f)
441                             .setDuration(300)
442                             .setStartDelay(200)
443                             .setInterpolator(Interpolators.ALPHA_IN);
444                 }
445                 return true;
446             }
447         });
448 
449     }
450 
451     @Override
setVisibility(int visibility)452     public void setVisibility(int visibility) {
453         super.setVisibility(visibility);
454         if (visibility != View.VISIBLE) {
455             mSystemIconsContainer.animate().cancel();
456             mSystemIconsContainer.setTranslationX(0);
457             mMultiUserAvatar.animate().cancel();
458             mMultiUserAvatar.setAlpha(1f);
459         } else {
460             updateVisibilities();
461             updateSystemIconsLayoutParams();
462         }
463     }
464 
465     @Override
hasOverlappingRendering()466     public boolean hasOverlappingRendering() {
467         return false;
468     }
469 
onThemeChanged()470     public void onThemeChanged() {
471         mBatteryView.setColorsFromContext(mContext);
472         updateIconsAndTextColors();
473         // Reload user avatar
474         ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
475                 .onDensityOrFontScaleChanged();
476     }
477 
478     @Override
onDensityOrFontScaleChanged()479     public void onDensityOrFontScaleChanged() {
480         loadDimens();
481     }
482 
483     @Override
onOverlayChanged()484     public void onOverlayChanged() {
485         mCarrierLabel.setTextAppearance(
486                 Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
487         onThemeChanged();
488         mBatteryView.updatePercentView();
489     }
490 
updateIconsAndTextColors()491     private void updateIconsAndTextColors() {
492         @ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
493                 R.attr.wallpaperTextColor);
494         @ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
495                 Color.luminance(textColor) < 0.5 ? R.color.dark_mode_icon_color_single_tone :
496                 R.color.light_mode_icon_color_single_tone);
497         float intensity = textColor == Color.WHITE ? 0 : 1;
498         mCarrierLabel.setTextColor(iconColor);
499         if (mIconManager != null) {
500             mIconManager.setTint(iconColor);
501         }
502 
503         applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
504         applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
505     }
506 
applyDarkness(int id, Rect tintArea, float intensity, int color)507     private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
508         View v = findViewById(id);
509         if (v instanceof DarkReceiver) {
510             ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
511         }
512     }
513 
514     /**
515      * Calculates the margin that isn't already accounted for in the view's padding.
516      */
calculateMargin(int margin, int padding)517     private int calculateMargin(int margin, int padding) {
518         if (padding >= margin) {
519             return 0;
520         } else {
521             return margin - padding;
522         }
523     }
524 
dump(FileDescriptor fd, PrintWriter pw, String[] args)525     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
526         pw.println("KeyguardStatusBarView:");
527         pw.println("  mBatteryCharging: " + mBatteryCharging);
528         pw.println("  mBatteryListening: " + mBatteryListening);
529         pw.println("  mLayoutState: " + mLayoutState);
530         pw.println("  mKeyguardUserSwitcherEnabled: " + mKeyguardUserSwitcherEnabled);
531         if (mBatteryView != null) {
532             mBatteryView.dump(fd, pw, args);
533         }
534     }
535 
536     /** SystemStatusAnimationCallback */
537     @Override
onSystemChromeAnimationStart()538     public void onSystemChromeAnimationStart() {
539         if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT) {
540             mSystemIconsContainer.setVisibility(View.VISIBLE);
541             mSystemIconsContainer.setAlpha(0f);
542         }
543     }
544 
545     @Override
onSystemChromeAnimationEnd()546     public void onSystemChromeAnimationEnd() {
547         // Make sure the system icons are out of the way
548         if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
549             mSystemIconsContainer.setVisibility(View.INVISIBLE);
550             mSystemIconsContainer.setAlpha(0f);
551         } else {
552             mSystemIconsContainer.setAlpha(1f);
553             mSystemIconsContainer.setVisibility(View.VISIBLE);
554         }
555     }
556 
557     @Override
onSystemChromeAnimationUpdate(ValueAnimator anim)558     public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
559         mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
560     }
561 
562     @Override
onLayout(boolean changed, int l, int t, int r, int b)563     protected void onLayout(boolean changed, int l, int t, int r, int b) {
564         super.onLayout(changed, l, t, r, b);
565         updateClipping();
566     }
567 
568     /**
569      * Set the clipping on the top of the view.
570      */
setTopClipping(int topClipping)571     public void setTopClipping(int topClipping) {
572         if (topClipping != mTopClipping) {
573             mTopClipping = topClipping;
574             updateClipping();
575         }
576     }
577 
updateClipping()578     private void updateClipping() {
579         mClipRect.set(0, mTopClipping, getWidth(), getHeight());
580         setClipBounds(mClipRect);
581     }
582 }
583