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 if (!isInArea(area, this)) { 212 return; 213 } 214 mMobileDrawable.setTintList( 215 ColorStateList.valueOf(mDualToneHandler.getSingleColor(darkIntensity))); 216 ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint)); 217 mIn.setImageTintList(color); 218 mOut.setImageTintList(color); 219 mMobileType.setImageTintList(color); 220 mMobileRoaming.setImageTintList(color); 221 mDotView.setDecorColor(tint); 222 mDotView.setIconColor(tint, false); 223 } 224 225 @Override getSlot()226 public String getSlot() { 227 return mSlot; 228 } 229 setSlot(String slot)230 public void setSlot(String slot) { 231 mSlot = slot; 232 } 233 234 @Override setStaticDrawableColor(int color)235 public void setStaticDrawableColor(int color) { 236 ColorStateList list = ColorStateList.valueOf(color); 237 float intensity = color == Color.WHITE ? 0 : 1; 238 // We want the ability to change the theme from the one set by SignalDrawable in certain 239 // surfaces. In this way, we can pass a theme to the view. 240 mMobileDrawable.setTintList( 241 ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity))); 242 mIn.setImageTintList(list); 243 mOut.setImageTintList(list); 244 mMobileType.setImageTintList(list); 245 mMobileRoaming.setImageTintList(list); 246 mDotView.setDecorColor(color); 247 } 248 249 @Override setDecorColor(int color)250 public void setDecorColor(int color) { 251 mDotView.setDecorColor(color); 252 } 253 254 @Override isIconVisible()255 public boolean isIconVisible() { 256 return mState.visible; 257 } 258 259 @Override setVisibleState(int state, boolean animate)260 public void setVisibleState(int state, boolean animate) { 261 if (state == mVisibleState) { 262 return; 263 } 264 265 mVisibleState = state; 266 switch (state) { 267 case STATE_ICON: 268 mMobileGroup.setVisibility(View.VISIBLE); 269 mDotView.setVisibility(View.GONE); 270 break; 271 case STATE_DOT: 272 mMobileGroup.setVisibility(View.INVISIBLE); 273 mDotView.setVisibility(View.VISIBLE); 274 break; 275 case STATE_HIDDEN: 276 default: 277 mMobileGroup.setVisibility(View.INVISIBLE); 278 mDotView.setVisibility(View.INVISIBLE); 279 break; 280 } 281 } 282 283 @Override getVisibleState()284 public int getVisibleState() { 285 return mVisibleState; 286 } 287 288 @VisibleForTesting getState()289 public MobileIconState getState() { 290 return mState; 291 } 292 293 @Override toString()294 public String toString() { 295 return "StatusBarMobileView(slot=" + mSlot + " state=" + mState + ")"; 296 } 297 } 298