• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.launcher3;
2 
3 import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
4 import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
5 
6 import android.annotation.TargetApi;
7 import android.app.ActivityManager;
8 import android.content.Context;
9 import android.graphics.Canvas;
10 import android.graphics.Color;
11 import android.graphics.Paint;
12 import android.graphics.Rect;
13 import android.util.AttributeSet;
14 import android.view.View;
15 import android.view.ViewDebug;
16 
17 public class LauncherRootView extends InsettableFrameLayout {
18 
19     private final Launcher mLauncher;
20 
21     private final Paint mOpaquePaint;
22 
23     @ViewDebug.ExportedProperty(category = "launcher")
24     private final Rect mConsumedInsets = new Rect();
25 
26     private View mAlignedView;
27     private WindowStateListener mWindowStateListener;
28 
LauncherRootView(Context context, AttributeSet attrs)29     public LauncherRootView(Context context, AttributeSet attrs) {
30         super(context, attrs);
31 
32         mOpaquePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
33         mOpaquePaint.setColor(Color.BLACK);
34         mOpaquePaint.setStyle(Paint.Style.FILL);
35 
36         mLauncher = Launcher.getLauncher(context);
37     }
38 
39     @Override
onFinishInflate()40     protected void onFinishInflate() {
41         if (getChildCount() > 0) {
42             // LauncherRootView contains only one child, which should be aligned
43             // based on the horizontal insets.
44             mAlignedView = getChildAt(0);
45         }
46         super.onFinishInflate();
47     }
48 
49     @TargetApi(23)
50     @Override
fitSystemWindows(Rect insets)51     protected boolean fitSystemWindows(Rect insets) {
52         mConsumedInsets.setEmpty();
53         boolean drawInsetBar = false;
54         if (mLauncher.isInMultiWindowModeCompat()
55                 && (insets.left > 0 || insets.right > 0 || insets.bottom > 0)) {
56             mConsumedInsets.left = insets.left;
57             mConsumedInsets.right = insets.right;
58             mConsumedInsets.bottom = insets.bottom;
59             insets = new Rect(0, insets.top, 0, 0);
60             drawInsetBar = true;
61         } else  if ((insets.right > 0 || insets.left > 0) &&
62                 (!Utilities.ATLEAST_MARSHMALLOW ||
63                         getContext().getSystemService(ActivityManager.class).isLowRamDevice())) {
64             mConsumedInsets.left = insets.left;
65             mConsumedInsets.right = insets.right;
66             insets = new Rect(0, insets.top, 0, insets.bottom);
67             drawInsetBar = true;
68         }
69 
70         mLauncher.getSystemUiController().updateUiState(
71                 UI_STATE_ROOT_VIEW, drawInsetBar ? FLAG_DARK_NAV : 0);
72 
73         // Update device profile before notifying th children.
74         mLauncher.getDeviceProfile().updateInsets(insets);
75         boolean resetState = !insets.equals(mInsets);
76         setInsets(insets);
77 
78         if (mAlignedView != null) {
79             // Apply margins on aligned view to handle consumed insets.
80             MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams();
81             if (lp.leftMargin != mConsumedInsets.left || lp.rightMargin != mConsumedInsets.right ||
82                     lp.bottomMargin != mConsumedInsets.bottom) {
83                 lp.leftMargin = mConsumedInsets.left;
84                 lp.rightMargin = mConsumedInsets.right;
85                 lp.topMargin = mConsumedInsets.top;
86                 lp.bottomMargin = mConsumedInsets.bottom;
87                 mAlignedView.setLayoutParams(lp);
88             }
89         }
90         if (resetState) {
91             mLauncher.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
92         }
93 
94         return true; // I'll take it from here
95     }
96 
97     @Override
setInsets(Rect insets)98     public void setInsets(Rect insets) {
99         // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
100         // modifying child layout params.
101         if (!insets.equals(mInsets)) {
102             super.setInsets(insets);
103         }
104     }
105 
dispatchInsets()106     public void dispatchInsets() {
107         mLauncher.getDeviceProfile().updateInsets(mInsets);
108         super.setInsets(mInsets);
109     }
110 
111     @Override
dispatchDraw(Canvas canvas)112     protected void dispatchDraw(Canvas canvas) {
113         super.dispatchDraw(canvas);
114 
115         // If the right inset is opaque, draw a black rectangle to ensure that is stays opaque.
116         if (mConsumedInsets.right > 0) {
117             int width = getWidth();
118             canvas.drawRect(width - mConsumedInsets.right, 0, width, getHeight(), mOpaquePaint);
119         }
120         if (mConsumedInsets.left > 0) {
121             canvas.drawRect(0, 0, mConsumedInsets.left, getHeight(), mOpaquePaint);
122         }
123         if (mConsumedInsets.bottom > 0) {
124             int height = getHeight();
125             canvas.drawRect(0, height - mConsumedInsets.bottom, getWidth(), height, mOpaquePaint);
126         }
127     }
128 
setWindowStateListener(WindowStateListener listener)129     public void setWindowStateListener(WindowStateListener listener) {
130         mWindowStateListener = listener;
131     }
132 
133     @Override
onWindowFocusChanged(boolean hasWindowFocus)134     public void onWindowFocusChanged(boolean hasWindowFocus) {
135         super.onWindowFocusChanged(hasWindowFocus);
136         if (mWindowStateListener != null) {
137             mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
138         }
139     }
140 
141     @Override
onWindowVisibilityChanged(int visibility)142     protected void onWindowVisibilityChanged(int visibility) {
143         super.onWindowVisibilityChanged(visibility);
144         if (mWindowStateListener != null) {
145             mWindowStateListener.onWindowVisibilityChanged(visibility);
146         }
147     }
148 
149     public interface WindowStateListener {
150 
onWindowFocusChanged(boolean hasFocus)151         void onWindowFocusChanged(boolean hasFocus);
152 
onWindowVisibilityChanged(int visibility)153         void onWindowVisibilityChanged(int visibility);
154     }
155 }