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.keyguard; 18 19 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 20 21 import android.content.Context; 22 import android.content.res.ColorStateList; 23 import android.graphics.Color; 24 import android.graphics.Point; 25 import android.graphics.Rect; 26 import android.graphics.RectF; 27 import android.graphics.drawable.Drawable; 28 import android.util.AttributeSet; 29 import android.view.Gravity; 30 import android.view.View; 31 import android.widget.FrameLayout; 32 import android.widget.ImageView; 33 34 import androidx.annotation.IntDef; 35 import androidx.annotation.NonNull; 36 37 import com.android.internal.graphics.ColorUtils; 38 import com.android.settingslib.Utils; 39 import com.android.systemui.Dumpable; 40 import com.android.systemui.R; 41 42 import java.io.PrintWriter; 43 44 /** 45 * A view positioned under the notification shade. 46 */ 47 public class LockIconView extends FrameLayout implements Dumpable { 48 @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) 49 public @interface IconType {} 50 51 public static final int ICON_NONE = -1; 52 public static final int ICON_LOCK = 0; 53 public static final int ICON_FINGERPRINT = 1; 54 public static final int ICON_UNLOCK = 2; 55 56 private @IconType int mIconType; 57 private boolean mAod; 58 59 @NonNull private final RectF mSensorRect; 60 @NonNull private Point mLockIconCenter = new Point(0, 0); 61 private float mRadius; 62 private int mLockIconPadding; 63 64 private ImageView mLockIcon; 65 private ImageView mBgView; 66 67 private int mLockIconColor; 68 private boolean mUseBackground = false; 69 private float mDozeAmount = 0f; 70 LockIconView(Context context, AttributeSet attrs)71 public LockIconView(Context context, AttributeSet attrs) { 72 super(context, attrs); 73 mSensorRect = new RectF(); 74 75 addBgImageView(context, attrs); 76 addLockIconImageView(context, attrs); 77 } 78 setDozeAmount(float dozeAmount)79 void setDozeAmount(float dozeAmount) { 80 mDozeAmount = dozeAmount; 81 updateColorAndBackgroundVisibility(); 82 } 83 updateColorAndBackgroundVisibility()84 void updateColorAndBackgroundVisibility() { 85 if (mUseBackground && mLockIcon.getDrawable() != null) { 86 mLockIconColor = ColorUtils.blendARGB( 87 Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary), 88 Color.WHITE, 89 mDozeAmount); 90 int backgroundColor = Utils.getColorAttrDefaultColor(getContext(), 91 com.android.internal.R.attr.colorSurface); 92 mBgView.setImageTintList(ColorStateList.valueOf(backgroundColor)); 93 mBgView.setAlpha(1f - mDozeAmount); 94 mBgView.setVisibility(View.VISIBLE); 95 } else { 96 mLockIconColor = ColorUtils.blendARGB( 97 Utils.getColorAttrDefaultColor(getContext(), R.attr.wallpaperTextColorAccent), 98 Color.WHITE, 99 mDozeAmount); 100 mBgView.setVisibility(View.GONE); 101 } 102 103 mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor)); 104 } 105 setImageDrawable(Drawable drawable)106 void setImageDrawable(Drawable drawable) { 107 mLockIcon.setImageDrawable(drawable); 108 109 if (!mUseBackground) return; 110 111 if (drawable == null) { 112 mBgView.setVisibility(View.INVISIBLE); 113 } else { 114 mBgView.setVisibility(View.VISIBLE); 115 } 116 } 117 118 /** 119 * Whether or not to render the lock icon background. Mainly used for UDPFS. 120 */ setUseBackground(boolean useBackground)121 public void setUseBackground(boolean useBackground) { 122 mUseBackground = useBackground; 123 updateColorAndBackgroundVisibility(); 124 } 125 126 /** 127 * Set the location of the lock icon. 128 */ setCenterLocation(@onNull Point center, float radius, int drawablePadding)129 public void setCenterLocation(@NonNull Point center, float radius, int drawablePadding) { 130 mLockIconCenter = center; 131 mRadius = radius; 132 mLockIconPadding = drawablePadding; 133 134 mLockIcon.setPadding(mLockIconPadding, mLockIconPadding, mLockIconPadding, 135 mLockIconPadding); 136 137 // mSensorProps coordinates assume portrait mode which is OK b/c the keyguard is always in 138 // portrait. 139 mSensorRect.set(mLockIconCenter.x - mRadius, 140 mLockIconCenter.y - mRadius, 141 mLockIconCenter.x + mRadius, 142 mLockIconCenter.y + mRadius); 143 144 final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); 145 lp.width = (int) (mSensorRect.right - mSensorRect.left); 146 lp.height = (int) (mSensorRect.bottom - mSensorRect.top); 147 lp.topMargin = (int) mSensorRect.top; 148 lp.setMarginStart((int) mSensorRect.left); 149 setLayoutParams(lp); 150 } 151 152 @Override hasOverlappingRendering()153 public boolean hasOverlappingRendering() { 154 return false; 155 } 156 getLocationTop()157 float getLocationTop() { 158 Rect r = new Rect(); 159 mLockIcon.getGlobalVisibleRect(r); 160 return r.top; 161 } 162 getLocationBottom()163 float getLocationBottom() { 164 Rect r = new Rect(); 165 mLockIcon.getGlobalVisibleRect(r); 166 return r.bottom; 167 168 } 169 170 /** 171 * Updates the icon its default state where no visual is shown. 172 */ clearIcon()173 public void clearIcon() { 174 updateIcon(ICON_NONE, false); 175 } 176 177 /** 178 * Transition the current icon to a new state 179 * @param icon type (ie: lock icon, unlock icon, fingerprint icon) 180 * @param aod whether to use the aod icon variant (some icons don't have aod variants and will 181 * therefore show no icon) 182 */ updateIcon(@conType int icon, boolean aod)183 public void updateIcon(@IconType int icon, boolean aod) { 184 mIconType = icon; 185 mAod = aod; 186 187 mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); 188 } 189 getLockIcon()190 public ImageView getLockIcon() { 191 return mLockIcon; 192 } 193 addLockIconImageView(Context context, AttributeSet attrs)194 private void addLockIconImageView(Context context, AttributeSet attrs) { 195 mLockIcon = new ImageView(context, attrs); 196 mLockIcon.setId(R.id.lock_icon); 197 mLockIcon.setScaleType(ImageView.ScaleType.CENTER_CROP); 198 addView(mLockIcon); 199 LayoutParams lp = (LayoutParams) mLockIcon.getLayoutParams(); 200 lp.height = MATCH_PARENT; 201 lp.width = MATCH_PARENT; 202 lp.gravity = Gravity.CENTER; 203 mLockIcon.setLayoutParams(lp); 204 } 205 addBgImageView(Context context, AttributeSet attrs)206 private void addBgImageView(Context context, AttributeSet attrs) { 207 mBgView = new ImageView(context, attrs); 208 mBgView.setId(R.id.lock_icon_bg); 209 mBgView.setImageDrawable(context.getDrawable(R.drawable.fingerprint_bg)); 210 mBgView.setVisibility(View.INVISIBLE); 211 addView(mBgView); 212 LayoutParams lp = (LayoutParams) mBgView.getLayoutParams(); 213 lp.height = MATCH_PARENT; 214 lp.width = MATCH_PARENT; 215 mBgView.setLayoutParams(lp); 216 } 217 getLockIconState(@conType int icon, boolean aod)218 private static int[] getLockIconState(@IconType int icon, boolean aod) { 219 if (icon == ICON_NONE) { 220 return new int[0]; 221 } 222 223 int[] lockIconState = new int[2]; 224 switch (icon) { 225 case ICON_LOCK: 226 lockIconState[0] = android.R.attr.state_first; 227 break; 228 case ICON_FINGERPRINT: 229 lockIconState[0] = android.R.attr.state_middle; 230 break; 231 case ICON_UNLOCK: 232 lockIconState[0] = android.R.attr.state_last; 233 break; 234 } 235 236 if (aod) { 237 lockIconState[1] = android.R.attr.state_single; 238 } else { 239 lockIconState[1] = -android.R.attr.state_single; 240 } 241 242 return lockIconState; 243 } 244 typeToString(@conType int type)245 private String typeToString(@IconType int type) { 246 switch (type) { 247 case ICON_NONE: 248 return "none"; 249 case ICON_LOCK: 250 return "lock"; 251 case ICON_FINGERPRINT: 252 return "fingerprint"; 253 case ICON_UNLOCK: 254 return "unlock"; 255 } 256 257 return "invalid"; 258 } 259 260 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)261 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 262 pw.println("Lock Icon View Parameters:"); 263 pw.println(" Center in px (x, y)= (" 264 + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); 265 pw.println(" Radius in pixels: " + mRadius); 266 pw.println(" Drawable padding: " + mLockIconPadding); 267 pw.println(" mIconType=" + typeToString(mIconType)); 268 pw.println(" mAod=" + mAod); 269 pw.println("Lock Icon View actual measurements:"); 270 pw.println(" topLeft= (" + getX() + ", " + getY() + ")"); 271 pw.println(" width=" + getWidth() + " height=" + getHeight()); 272 } 273 } 274