• 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 com.android.systemui.car.systembar;
18 
19 import android.annotation.IntDef;
20 import android.content.Context;
21 import android.util.AttributeSet;
22 import android.view.MotionEvent;
23 import android.view.View;
24 import android.widget.LinearLayout;
25 
26 import com.android.systemui.R;
27 import com.android.systemui.car.systembar.CarSystemBarController.NotificationsShadeController;
28 import com.android.systemui.statusbar.FeatureFlags;
29 import com.android.systemui.statusbar.phone.StatusBarIconController;
30 
31 import java.lang.annotation.ElementType;
32 import java.lang.annotation.Target;
33 
34 /**
35  * A custom system bar for the automotive use case.
36  * <p>
37  * The system bar in the automotive use case is more like a list of shortcuts, rendered
38  * in a linear layout.
39  */
40 public class CarSystemBarView extends LinearLayout {
41 
42     @IntDef(value = {BUTTON_TYPE_NAVIGATION, BUTTON_TYPE_KEYGUARD, BUTTON_TYPE_OCCLUSION})
43     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
44     private @interface ButtonsType {
45     }
46 
47     public static final int BUTTON_TYPE_NAVIGATION = 0;
48     public static final int BUTTON_TYPE_KEYGUARD = 1;
49     public static final int BUTTON_TYPE_OCCLUSION = 2;
50 
51     private final boolean mConsumeTouchWhenPanelOpen;
52     private final boolean mButtonsDraggable;
53 
54     private View mNavButtons;
55     private CarSystemBarButton mNotificationsButton;
56     private NotificationsShadeController mNotificationsShadeController;
57     private View mLockScreenButtons;
58     private View mOcclusionButtons;
59     // used to wire in open/close gestures for notifications
60     private OnTouchListener mStatusBarWindowTouchListener;
61 
CarSystemBarView(Context context, AttributeSet attrs)62     public CarSystemBarView(Context context, AttributeSet attrs) {
63         super(context, attrs);
64         mConsumeTouchWhenPanelOpen = getResources().getBoolean(
65                 R.bool.config_consumeSystemBarTouchWhenNotificationPanelOpen);
66         mButtonsDraggable = getResources().getBoolean(R.bool.config_systemBarButtonsDraggable);
67     }
68 
69     @Override
onFinishInflate()70     public void onFinishInflate() {
71         mNavButtons = findViewById(R.id.nav_buttons);
72         mLockScreenButtons = findViewById(R.id.lock_screen_nav_buttons);
73         mOcclusionButtons = findViewById(R.id.occlusion_buttons);
74         mNotificationsButton = findViewById(R.id.notifications);
75         if (mNotificationsButton != null) {
76             mNotificationsButton.setOnClickListener(this::onNotificationsClick);
77         }
78         // Needs to be clickable so that it will receive ACTION_MOVE events.
79         setClickable(true);
80         // Needs to not be focusable so rotary won't highlight the entire nav bar.
81         setFocusable(false);
82     }
83 
setupIconController(FeatureFlags featureFlags, StatusBarIconController iconController)84     void setupIconController(FeatureFlags featureFlags, StatusBarIconController iconController) {
85         View mStatusIcons = findViewById(R.id.statusIcons);
86         if (mStatusIcons != null) {
87             // Attach the controllers for Status icons such as wifi and bluetooth if the standard
88             // container is in the view.
89             StatusBarIconController.DarkIconManager mDarkIconManager =
90                     new StatusBarIconController.DarkIconManager(
91                             mStatusIcons.findViewById(R.id.statusIcons), featureFlags);
92             mDarkIconManager.setShouldLog(true);
93             iconController.addIconGroup(mDarkIconManager);
94         }
95     }
96 
97     // Used to forward touch events even if the touch was initiated from a child component
98     @Override
onInterceptTouchEvent(MotionEvent ev)99     public boolean onInterceptTouchEvent(MotionEvent ev) {
100         if (mStatusBarWindowTouchListener != null) {
101             if (!mButtonsDraggable) {
102                 return false;
103             }
104             boolean shouldConsumeEvent = mNotificationsShadeController == null ? false
105                     : mNotificationsShadeController.isNotificationPanelOpen();
106 
107             // Forward touch events to the status bar window so it can drag
108             // windows if required (Notification shade)
109             mStatusBarWindowTouchListener.onTouch(this, ev);
110 
111             if (mConsumeTouchWhenPanelOpen && shouldConsumeEvent) {
112                 return true;
113             }
114         }
115         return super.onInterceptTouchEvent(ev);
116     }
117 
118     /** Sets the notifications panel controller. */
setNotificationsPanelController(NotificationsShadeController controller)119     public void setNotificationsPanelController(NotificationsShadeController controller) {
120         mNotificationsShadeController = controller;
121     }
122 
123     /** Gets the notifications panel controller. */
getNotificationsPanelController()124     public NotificationsShadeController getNotificationsPanelController() {
125         return mNotificationsShadeController;
126     }
127 
128     /**
129      * Sets a touch listener that will be called from onInterceptTouchEvent and onTouchEvent
130      *
131      * @param statusBarWindowTouchListener The listener to call from touch and intercept touch
132      */
setStatusBarWindowTouchListener(OnTouchListener statusBarWindowTouchListener)133     public void setStatusBarWindowTouchListener(OnTouchListener statusBarWindowTouchListener) {
134         mStatusBarWindowTouchListener = statusBarWindowTouchListener;
135     }
136 
137     /** Gets the touch listener that will be called from onInterceptTouchEvent and onTouchEvent. */
getStatusBarWindowTouchListener()138     public OnTouchListener getStatusBarWindowTouchListener() {
139         return mStatusBarWindowTouchListener;
140     }
141 
142     @Override
onTouchEvent(MotionEvent event)143     public boolean onTouchEvent(MotionEvent event) {
144         if (mStatusBarWindowTouchListener != null) {
145             mStatusBarWindowTouchListener.onTouch(this, event);
146         }
147         return super.onTouchEvent(event);
148     }
149 
onNotificationsClick(View v)150     protected void onNotificationsClick(View v) {
151         if (mNotificationsShadeController != null) {
152             mNotificationsShadeController.togglePanel();
153         }
154     }
155 
156     /**
157      * Shows buttons of the specified {@link ButtonsType}.
158      *
159      * NOTE: Only one type of buttons can be shown at a time, so showing buttons of one type will
160      * hide all buttons of other types.
161      *
162      * @param buttonsType
163      */
showButtonsOfType(@uttonsType int buttonsType)164     public void showButtonsOfType(@ButtonsType int buttonsType) {
165         switch(buttonsType) {
166             case BUTTON_TYPE_NAVIGATION:
167                 setNavigationButtonsVisibility(View.VISIBLE);
168                 setKeyguardButtonsVisibility(View.GONE);
169                 setOcclusionButtonsVisibility(View.GONE);
170                 break;
171             case BUTTON_TYPE_KEYGUARD:
172                 setNavigationButtonsVisibility(View.GONE);
173                 setKeyguardButtonsVisibility(View.VISIBLE);
174                 setOcclusionButtonsVisibility(View.GONE);
175                 break;
176             case BUTTON_TYPE_OCCLUSION:
177                 setNavigationButtonsVisibility(View.GONE);
178                 setKeyguardButtonsVisibility(View.GONE);
179                 setOcclusionButtonsVisibility(View.VISIBLE);
180                 break;
181         }
182     }
183 
setNavigationButtonsVisibility(int visibility)184     private void setNavigationButtonsVisibility(int visibility) {
185         if (mNavButtons != null) {
186             mNavButtons.setVisibility(visibility);
187         }
188     }
189 
setKeyguardButtonsVisibility(int visibility)190     private void setKeyguardButtonsVisibility(int visibility) {
191         if (mLockScreenButtons != null) {
192             mLockScreenButtons.setVisibility(visibility);
193         }
194     }
195 
setOcclusionButtonsVisibility(int visibility)196     private void setOcclusionButtonsVisibility(int visibility) {
197         if (mOcclusionButtons != null) {
198             mOcclusionButtons.setVisibility(visibility);
199         }
200     }
201 
202     /**
203      * Toggles the notification unseen indicator on/off.
204      *
205      * @param hasUnseen true if the unseen notification count is great than 0.
206      */
toggleNotificationUnseenIndicator(Boolean hasUnseen)207     public void toggleNotificationUnseenIndicator(Boolean hasUnseen) {
208         if (mNotificationsButton == null) return;
209 
210         mNotificationsButton.setUnseen(hasUnseen);
211     }
212 }
213