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.PointF; 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.FileDescriptor; 40 import java.io.PrintWriter; 41 42 /** 43 * A view positioned under the notification shade. 44 */ 45 public class LockIconView extends FrameLayout implements Dumpable { 46 @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) 47 public @interface IconType {} 48 49 public static final int ICON_NONE = -1; 50 public static final int ICON_LOCK = 0; 51 public static final int ICON_FINGERPRINT = 1; 52 public static final int ICON_UNLOCK = 2; 53 54 private @IconType int mIconType; 55 private boolean mAod; 56 57 @NonNull private final RectF mSensorRect; 58 @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); 59 private int mRadius; 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 PointF center, int radius)129 public void setCenterLocation(@NonNull PointF center, int radius) { 130 mLockIconCenter = center; 131 mRadius = radius; 132 133 // mSensorProps coordinates assume portrait mode which is OK b/c the keyguard is always in 134 // portrait. 135 mSensorRect.set(mLockIconCenter.x - mRadius, 136 mLockIconCenter.y - mRadius, 137 mLockIconCenter.x + mRadius, 138 mLockIconCenter.y + mRadius); 139 140 final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); 141 lp.width = (int) (mSensorRect.right - mSensorRect.left); 142 lp.height = (int) (mSensorRect.bottom - mSensorRect.top); 143 lp.topMargin = (int) mSensorRect.top; 144 lp.setMarginStart((int) mSensorRect.left); 145 setLayoutParams(lp); 146 } 147 148 @Override hasOverlappingRendering()149 public boolean hasOverlappingRendering() { 150 return false; 151 } 152 getLocationTop()153 float getLocationTop() { 154 return mLockIconCenter.y - mRadius; 155 } 156 157 /** 158 * Updates the icon its default state where no visual is shown. 159 */ clearIcon()160 public void clearIcon() { 161 updateIcon(ICON_NONE, false); 162 } 163 164 /** 165 * Transition the current icon to a new state 166 * @param icon type (ie: lock icon, unlock icon, fingerprint icon) 167 * @param aod whether to use the aod icon variant (some icons don't have aod variants and will 168 * therefore show no icon) 169 */ updateIcon(@conType int icon, boolean aod)170 public void updateIcon(@IconType int icon, boolean aod) { 171 mIconType = icon; 172 mAod = aod; 173 174 mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); 175 } 176 getLockIconState(@conType int icon, boolean aod)177 private static int[] getLockIconState(@IconType int icon, boolean aod) { 178 if (icon == ICON_NONE) { 179 return new int[0]; 180 } 181 182 int[] lockIconState = new int[2]; 183 switch (icon) { 184 case ICON_LOCK: 185 lockIconState[0] = android.R.attr.state_first; 186 break; 187 case ICON_FINGERPRINT: 188 lockIconState[0] = android.R.attr.state_middle; 189 break; 190 case ICON_UNLOCK: 191 lockIconState[0] = android.R.attr.state_last; 192 break; 193 } 194 195 if (aod) { 196 lockIconState[1] = android.R.attr.state_single; 197 } else { 198 lockIconState[1] = -android.R.attr.state_single; 199 } 200 201 return lockIconState; 202 } 203 typeToString(@conType int type)204 private String typeToString(@IconType int type) { 205 switch (type) { 206 case ICON_NONE: 207 return "none"; 208 case ICON_LOCK: 209 return "lock"; 210 case ICON_FINGERPRINT: 211 return "fingerprint"; 212 case ICON_UNLOCK: 213 return "unlock"; 214 } 215 216 return "invalid"; 217 } 218 219 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)220 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { 221 pw.println("Lock Icon View Parameters:"); 222 pw.println(" Center in px (x, y)= (" 223 + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); 224 pw.println(" Radius in pixels: " + mRadius); 225 pw.println(" mIconType=" + typeToString(mIconType)); 226 pw.println(" mAod=" + mAod); 227 pw.println("Lock Icon View actual measurements:"); 228 pw.println(" topLeft= (" + getX() + ", " + getY() + ")"); 229 pw.println(" width=" + getWidth() + " height=" + getHeight()); 230 } 231 } 232