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