• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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;
18 
19 import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
20 import static com.android.systemui.plugins.DarkIconDispatcher.isInArea;
21 import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
22 import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
23 import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
24 
25 import android.content.Context;
26 import android.content.res.ColorStateList;
27 import android.graphics.Rect;
28 import android.util.AttributeSet;
29 import android.view.Gravity;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.widget.FrameLayout;
33 import android.widget.ImageView;
34 import android.widget.LinearLayout;
35 
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.settingslib.graph.SignalDrawable;
38 import com.android.systemui.DualToneHandler;
39 import com.android.systemui.R;
40 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
41 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
42 
43 public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
44         StatusIconDisplayable {
45     private static final String TAG = "StatusBarMobileView";
46 
47     /// Used to show etc dots
48     private StatusBarIconView mDotView;
49     /// The main icon view
50     private LinearLayout mMobileGroup;
51     private String mSlot;
52     private MobileIconState mState;
53     private SignalDrawable mMobileDrawable;
54     private View mInoutContainer;
55     private ImageView mIn;
56     private ImageView mOut;
57     private ImageView mMobile, mMobileType, mMobileRoaming;
58     private View mMobileRoamingSpace;
59     private int mVisibleState = -1;
60     private DualToneHandler mDualToneHandler;
61     private boolean mForceHidden;
62     private boolean mProviderModel;
63 
64     /**
65      * Designated constructor
66      */
fromContext( Context context, String slot, boolean providerModel )67     public static StatusBarMobileView fromContext(
68             Context context,
69             String slot,
70             boolean providerModel
71     ) {
72         LayoutInflater inflater = LayoutInflater.from(context);
73         StatusBarMobileView v = (StatusBarMobileView)
74                 inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
75         v.setSlot(slot);
76         v.init(providerModel);
77         v.setVisibleState(STATE_ICON);
78         return v;
79     }
80 
StatusBarMobileView(Context context)81     public StatusBarMobileView(Context context) {
82         super(context);
83     }
84 
StatusBarMobileView(Context context, AttributeSet attrs)85     public StatusBarMobileView(Context context, AttributeSet attrs) {
86         super(context, attrs);
87     }
88 
StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr)89     public StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr) {
90         super(context, attrs, defStyleAttr);
91     }
92 
StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)93     public StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr,
94             int defStyleRes) {
95         super(context, attrs, defStyleAttr, defStyleRes);
96     }
97 
98     @Override
getDrawingRect(Rect outRect)99     public void getDrawingRect(Rect outRect) {
100         super.getDrawingRect(outRect);
101         float translationX = getTranslationX();
102         float translationY = getTranslationY();
103         outRect.left += translationX;
104         outRect.right += translationX;
105         outRect.top += translationY;
106         outRect.bottom += translationY;
107     }
108 
init(boolean providerModel)109     private void init(boolean providerModel) {
110         mProviderModel = providerModel;
111         mDualToneHandler = new DualToneHandler(getContext());
112         mMobileGroup = findViewById(R.id.mobile_group);
113         mMobile = findViewById(R.id.mobile_signal);
114         mMobileType = findViewById(R.id.mobile_type);
115         if (mProviderModel) {
116             mMobileRoaming = findViewById(R.id.mobile_roaming_large);
117         } else {
118             mMobileRoaming = findViewById(R.id.mobile_roaming);
119         }
120         mMobileRoamingSpace = findViewById(R.id.mobile_roaming_space);
121         mIn = findViewById(R.id.mobile_in);
122         mOut = findViewById(R.id.mobile_out);
123         mInoutContainer = findViewById(R.id.inout_container);
124 
125         mMobileDrawable = new SignalDrawable(getContext());
126         mMobile.setImageDrawable(mMobileDrawable);
127 
128         initDotView();
129     }
130 
initDotView()131     private void initDotView() {
132         mDotView = new StatusBarIconView(mContext, mSlot, null);
133         mDotView.setVisibleState(STATE_DOT);
134 
135         int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
136         LayoutParams lp = new LayoutParams(width, width);
137         lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
138         addView(mDotView, lp);
139     }
140 
applyMobileState(MobileIconState state)141     public void applyMobileState(MobileIconState state) {
142         boolean requestLayout = false;
143         if (state == null) {
144             requestLayout = getVisibility() != View.GONE;
145             setVisibility(View.GONE);
146             mState = null;
147         } else if (mState == null) {
148             requestLayout = true;
149             mState = state.copy();
150             initViewState();
151         } else if (!mState.equals(state)) {
152             requestLayout = updateState(state.copy());
153         }
154 
155         if (requestLayout) {
156             requestLayout();
157         }
158     }
159 
initViewState()160     private void initViewState() {
161         setContentDescription(mState.contentDescription);
162         if (!mState.visible || mForceHidden) {
163             mMobileGroup.setVisibility(View.GONE);
164         } else {
165             mMobileGroup.setVisibility(View.VISIBLE);
166         }
167         mMobileDrawable.setLevel(mState.strengthId);
168         if (mState.typeId > 0) {
169             mMobileType.setContentDescription(mState.typeContentDescription);
170             mMobileType.setImageResource(mState.typeId);
171             mMobileType.setVisibility(View.VISIBLE);
172         } else {
173             mMobileType.setVisibility(View.GONE);
174         }
175         mMobile.setVisibility(mState.showTriangle ? View.VISIBLE : View.GONE);
176         mMobileRoaming.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
177         mMobileRoamingSpace.setVisibility(mState.roaming ? View.VISIBLE : View.GONE);
178         mIn.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
179         mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
180         mInoutContainer.setVisibility((mState.activityIn || mState.activityOut)
181                 ? View.VISIBLE : View.GONE);
182     }
183 
updateState(MobileIconState state)184     private boolean updateState(MobileIconState state) {
185         boolean needsLayout = false;
186 
187         setContentDescription(state.contentDescription);
188         int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
189         if (newVisibility != mMobileGroup.getVisibility()) {
190             mMobileGroup.setVisibility(newVisibility);
191             needsLayout = true;
192         }
193         if (mState.strengthId != state.strengthId) {
194             mMobileDrawable.setLevel(state.strengthId);
195         }
196         if (mState.typeId != state.typeId) {
197             needsLayout |= state.typeId == 0 || mState.typeId == 0;
198             if (state.typeId != 0) {
199                 mMobileType.setContentDescription(state.typeContentDescription);
200                 mMobileType.setImageResource(state.typeId);
201                 mMobileType.setVisibility(View.VISIBLE);
202             } else {
203                 mMobileType.setVisibility(View.GONE);
204             }
205         }
206 
207         mMobile.setVisibility(state.showTriangle ? View.VISIBLE : View.GONE);
208         mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
209         mMobileRoamingSpace.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
210         mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
211         mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
212         mInoutContainer.setVisibility((state.activityIn || state.activityOut)
213                 ? View.VISIBLE : View.GONE);
214 
215         needsLayout |= state.roaming != mState.roaming
216                 || state.activityIn != mState.activityIn
217                 || state.activityOut != mState.activityOut
218                 || state.showTriangle != mState.showTriangle;
219 
220         mState = state;
221         return needsLayout;
222     }
223 
224     @Override
onDarkChanged(Rect area, float darkIntensity, int tint)225     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
226         float intensity = isInArea(area, this) ? darkIntensity : 0;
227         mMobileDrawable.setTintList(
228                 ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity)));
229         ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
230         mIn.setImageTintList(color);
231         mOut.setImageTintList(color);
232         mMobileType.setImageTintList(color);
233         mMobileRoaming.setImageTintList(color);
234         mDotView.setDecorColor(tint);
235         mDotView.setIconColor(tint, false);
236     }
237 
238     @Override
getSlot()239     public String getSlot() {
240         return mSlot;
241     }
242 
setSlot(String slot)243     public void setSlot(String slot) {
244         mSlot = slot;
245     }
246 
247     @Override
setStaticDrawableColor(int color)248     public void setStaticDrawableColor(int color) {
249         ColorStateList list = ColorStateList.valueOf(color);
250         mMobileDrawable.setTintList(list);
251         mIn.setImageTintList(list);
252         mOut.setImageTintList(list);
253         mMobileType.setImageTintList(list);
254         mMobileRoaming.setImageTintList(list);
255         mDotView.setDecorColor(color);
256     }
257 
258     @Override
setDecorColor(int color)259     public void setDecorColor(int color) {
260         mDotView.setDecorColor(color);
261     }
262 
263     @Override
isIconVisible()264     public boolean isIconVisible() {
265         return mState.visible && !mForceHidden;
266     }
267 
268     @Override
setVisibleState(int state, boolean animate)269     public void setVisibleState(int state, boolean animate) {
270         if (state == mVisibleState) {
271             return;
272         }
273 
274         mVisibleState = state;
275         switch (state) {
276             case STATE_ICON:
277                 mMobileGroup.setVisibility(View.VISIBLE);
278                 mDotView.setVisibility(View.GONE);
279                 break;
280             case STATE_DOT:
281                 mMobileGroup.setVisibility(View.INVISIBLE);
282                 mDotView.setVisibility(View.VISIBLE);
283                 break;
284             case STATE_HIDDEN:
285             default:
286                 mMobileGroup.setVisibility(View.INVISIBLE);
287                 mDotView.setVisibility(View.INVISIBLE);
288                 break;
289         }
290     }
291 
292     /**
293      * Forces the state to be hidden (views will be GONE) and if necessary updates the layout.
294      *
295      * Makes sure that the {@link StatusBarIconController} cannot make it visible while this flag
296      * is enabled.
297      * @param forceHidden {@code true} if the icon should be GONE in its view regardless of its
298      *                                state.
299      *               {@code false} if the icon should show as determined by its controller.
300      */
forceHidden(boolean forceHidden)301     public void forceHidden(boolean forceHidden) {
302         if (mForceHidden != forceHidden) {
303             mForceHidden = forceHidden;
304             updateState(mState);
305             requestLayout();
306         }
307     }
308 
309     @Override
getVisibleState()310     public int getVisibleState() {
311         return mVisibleState;
312     }
313 
314     @VisibleForTesting
getState()315     public MobileIconState getState() {
316         return mState;
317     }
318 
319     @Override
toString()320     public String toString() {
321         return "StatusBarMobileView(slot=" + mSlot + " state=" + mState + ")";
322     }
323 }
324