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 android.content.Context; 20 import android.content.res.ColorStateList; 21 import android.graphics.Color; 22 import android.graphics.Point; 23 import android.graphics.RectF; 24 import android.graphics.drawable.Drawable; 25 import android.util.AttributeSet; 26 import android.view.View; 27 import android.widget.FrameLayout; 28 import android.widget.ImageView; 29 30 import androidx.annotation.IntDef; 31 import androidx.annotation.NonNull; 32 import androidx.annotation.VisibleForTesting; 33 34 import com.android.internal.graphics.ColorUtils; 35 import com.android.settingslib.Utils; 36 import com.android.systemui.Dumpable; 37 import com.android.systemui.R; 38 39 import java.io.PrintWriter; 40 41 /** 42 * A view positioned under the notification shade. 43 */ 44 public class LockIconView extends FrameLayout implements Dumpable { 45 @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) 46 public @interface IconType {} 47 48 public static final int ICON_NONE = -1; 49 public static final int ICON_LOCK = 0; 50 public static final int ICON_FINGERPRINT = 1; 51 public static final int ICON_UNLOCK = 2; 52 53 private @IconType int mIconType; 54 private boolean mAod; 55 56 @NonNull private final RectF mSensorRect; 57 @NonNull private Point mLockIconCenter = new Point(0, 0); 58 private float mRadius; 59 private int mLockIconPadding; 60 61 private ImageView mLockIcon; 62 private ImageView mBgView; 63 64 private int mLockIconColor; 65 private boolean mUseBackground = false; 66 private float mDozeAmount = 0f; 67 LockIconView(Context context, AttributeSet attrs)68 public LockIconView(Context context, AttributeSet attrs) { 69 super(context, attrs); 70 mSensorRect = new RectF(); 71 } 72 73 @Override onFinishInflate()74 public void onFinishInflate() { 75 super.onFinishInflate(); 76 mLockIcon = findViewById(R.id.lock_icon); 77 mBgView = findViewById(R.id.lock_icon_bg); 78 } 79 setDozeAmount(float dozeAmount)80 void setDozeAmount(float dozeAmount) { 81 mDozeAmount = dozeAmount; 82 updateColorAndBackgroundVisibility(); 83 } 84 updateColorAndBackgroundVisibility()85 void updateColorAndBackgroundVisibility() { 86 if (mUseBackground && mLockIcon.getDrawable() != null) { 87 mLockIconColor = ColorUtils.blendARGB( 88 Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary), 89 Color.WHITE, 90 mDozeAmount); 91 mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg)); 92 mBgView.setAlpha(1f - mDozeAmount); 93 mBgView.setVisibility(View.VISIBLE); 94 } else { 95 mLockIconColor = ColorUtils.blendARGB( 96 Utils.getColorAttrDefaultColor(getContext(), R.attr.wallpaperTextColorAccent), 97 Color.WHITE, 98 mDozeAmount); 99 mBgView.setVisibility(View.GONE); 100 } 101 102 mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor)); 103 } 104 setImageDrawable(Drawable drawable)105 void setImageDrawable(Drawable drawable) { 106 mLockIcon.setImageDrawable(drawable); 107 108 if (!mUseBackground) return; 109 110 if (drawable == null) { 111 mBgView.setVisibility(View.INVISIBLE); 112 } else { 113 mBgView.setVisibility(View.VISIBLE); 114 } 115 } 116 117 /** 118 * Whether or not to render the lock icon background. Mainly used for UDPFS. 119 */ setUseBackground(boolean useBackground)120 public void setUseBackground(boolean useBackground) { 121 mUseBackground = useBackground; 122 updateColorAndBackgroundVisibility(); 123 } 124 125 /** 126 * Set the location of the lock icon. 127 */ 128 @VisibleForTesting 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 return mLockIconCenter.y - mRadius; 159 } 160 getLocationBottom()161 float getLocationBottom() { 162 return mLockIconCenter.y + mRadius; 163 } 164 165 /** 166 * Updates the icon its default state where no visual is shown. 167 */ clearIcon()168 public void clearIcon() { 169 updateIcon(ICON_NONE, false); 170 } 171 172 /** 173 * Transition the current icon to a new state 174 * @param icon type (ie: lock icon, unlock icon, fingerprint icon) 175 * @param aod whether to use the aod icon variant (some icons don't have aod variants and will 176 * therefore show no icon) 177 */ updateIcon(@conType int icon, boolean aod)178 public void updateIcon(@IconType int icon, boolean aod) { 179 mIconType = icon; 180 mAod = aod; 181 182 mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); 183 } 184 getLockIconState(@conType int icon, boolean aod)185 private static int[] getLockIconState(@IconType int icon, boolean aod) { 186 if (icon == ICON_NONE) { 187 return new int[0]; 188 } 189 190 int[] lockIconState = new int[2]; 191 switch (icon) { 192 case ICON_LOCK: 193 lockIconState[0] = android.R.attr.state_first; 194 break; 195 case ICON_FINGERPRINT: 196 lockIconState[0] = android.R.attr.state_middle; 197 break; 198 case ICON_UNLOCK: 199 lockIconState[0] = android.R.attr.state_last; 200 break; 201 } 202 203 if (aod) { 204 lockIconState[1] = android.R.attr.state_single; 205 } else { 206 lockIconState[1] = -android.R.attr.state_single; 207 } 208 209 return lockIconState; 210 } 211 typeToString(@conType int type)212 private String typeToString(@IconType int type) { 213 switch (type) { 214 case ICON_NONE: 215 return "none"; 216 case ICON_LOCK: 217 return "lock"; 218 case ICON_FINGERPRINT: 219 return "fingerprint"; 220 case ICON_UNLOCK: 221 return "unlock"; 222 } 223 224 return "invalid"; 225 } 226 227 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)228 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 229 pw.println("Lock Icon View Parameters:"); 230 pw.println(" Center in px (x, y)= (" 231 + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); 232 pw.println(" Radius in pixels: " + mRadius); 233 pw.println(" Drawable padding: " + mLockIconPadding); 234 pw.println(" mIconType=" + typeToString(mIconType)); 235 pw.println(" mAod=" + mAod); 236 pw.println("Lock Icon View actual measurements:"); 237 pw.println(" topLeft= (" + getX() + ", " + getY() + ")"); 238 pw.println(" width=" + getWidth() + " height=" + getHeight()); 239 } 240 } 241