| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.keyguard; |
| |
| import android.content.Context; |
| import android.content.res.ColorStateList; |
| import android.graphics.Color; |
| import android.graphics.PointF; |
| import android.graphics.RectF; |
| import android.graphics.drawable.Drawable; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.widget.FrameLayout; |
| import android.widget.ImageView; |
| |
| import androidx.annotation.IntDef; |
| import androidx.annotation.NonNull; |
| import androidx.annotation.VisibleForTesting; |
| |
| import com.android.internal.graphics.ColorUtils; |
| import com.android.settingslib.Utils; |
| import com.android.systemui.Dumpable; |
| import com.android.systemui.R; |
| |
| import java.io.PrintWriter; |
| |
| /** |
| * A view positioned under the notification shade. |
| */ |
| public class LockIconView extends FrameLayout implements Dumpable { |
| @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) |
| public @interface IconType {} |
| |
| public static final int ICON_NONE = -1; |
| public static final int ICON_LOCK = 0; |
| public static final int ICON_FINGERPRINT = 1; |
| public static final int ICON_UNLOCK = 2; |
| |
| private @IconType int mIconType; |
| private boolean mAod; |
| |
| @NonNull private final RectF mSensorRect; |
| @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); |
| private float mRadius; |
| private int mLockIconPadding; |
| |
| private ImageView mLockIcon; |
| private ImageView mBgView; |
| |
| private int mLockIconColor; |
| private boolean mUseBackground = false; |
| private float mDozeAmount = 0f; |
| |
| public LockIconView(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| mSensorRect = new RectF(); |
| } |
| |
| @Override |
| public void onFinishInflate() { |
| super.onFinishInflate(); |
| mLockIcon = findViewById(R.id.lock_icon); |
| mBgView = findViewById(R.id.lock_icon_bg); |
| } |
| |
| void setDozeAmount(float dozeAmount) { |
| mDozeAmount = dozeAmount; |
| updateColorAndBackgroundVisibility(); |
| } |
| |
| void updateColorAndBackgroundVisibility() { |
| if (mUseBackground && mLockIcon.getDrawable() != null) { |
| mLockIconColor = ColorUtils.blendARGB( |
| Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary), |
| Color.WHITE, |
| mDozeAmount); |
| mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg)); |
| mBgView.setAlpha(1f - mDozeAmount); |
| mBgView.setVisibility(View.VISIBLE); |
| } else { |
| mLockIconColor = ColorUtils.blendARGB( |
| Utils.getColorAttrDefaultColor(getContext(), R.attr.wallpaperTextColorAccent), |
| Color.WHITE, |
| mDozeAmount); |
| mBgView.setVisibility(View.GONE); |
| } |
| |
| mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor)); |
| } |
| |
| void setImageDrawable(Drawable drawable) { |
| mLockIcon.setImageDrawable(drawable); |
| |
| if (!mUseBackground) return; |
| |
| if (drawable == null) { |
| mBgView.setVisibility(View.INVISIBLE); |
| } else { |
| mBgView.setVisibility(View.VISIBLE); |
| } |
| } |
| |
| /** |
| * Whether or not to render the lock icon background. Mainly used for UDPFS. |
| */ |
| public void setUseBackground(boolean useBackground) { |
| mUseBackground = useBackground; |
| updateColorAndBackgroundVisibility(); |
| } |
| |
| /** |
| * Set the location of the lock icon. |
| */ |
| @VisibleForTesting |
| public void setCenterLocation(@NonNull PointF center, float radius, int drawablePadding) { |
| mLockIconCenter = center; |
| mRadius = radius; |
| mLockIconPadding = drawablePadding; |
| |
| mLockIcon.setPadding(mLockIconPadding, mLockIconPadding, mLockIconPadding, |
| mLockIconPadding); |
| |
| // mSensorProps coordinates assume portrait mode which is OK b/c the keyguard is always in |
| // portrait. |
| mSensorRect.set(mLockIconCenter.x - mRadius, |
| mLockIconCenter.y - mRadius, |
| mLockIconCenter.x + mRadius, |
| mLockIconCenter.y + mRadius); |
| |
| final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); |
| lp.width = (int) (mSensorRect.right - mSensorRect.left); |
| lp.height = (int) (mSensorRect.bottom - mSensorRect.top); |
| lp.topMargin = (int) mSensorRect.top; |
| lp.setMarginStart((int) mSensorRect.left); |
| setLayoutParams(lp); |
| } |
| |
| @Override |
| public boolean hasOverlappingRendering() { |
| return false; |
| } |
| |
| float getLocationTop() { |
| return mLockIconCenter.y - mRadius; |
| } |
| |
| /** |
| * Updates the icon its default state where no visual is shown. |
| */ |
| public void clearIcon() { |
| updateIcon(ICON_NONE, false); |
| } |
| |
| /** |
| * Transition the current icon to a new state |
| * @param icon type (ie: lock icon, unlock icon, fingerprint icon) |
| * @param aod whether to use the aod icon variant (some icons don't have aod variants and will |
| * therefore show no icon) |
| */ |
| public void updateIcon(@IconType int icon, boolean aod) { |
| mIconType = icon; |
| mAod = aod; |
| |
| mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); |
| } |
| |
| private static int[] getLockIconState(@IconType int icon, boolean aod) { |
| if (icon == ICON_NONE) { |
| return new int[0]; |
| } |
| |
| int[] lockIconState = new int[2]; |
| switch (icon) { |
| case ICON_LOCK: |
| lockIconState[0] = android.R.attr.state_first; |
| break; |
| case ICON_FINGERPRINT: |
| lockIconState[0] = android.R.attr.state_middle; |
| break; |
| case ICON_UNLOCK: |
| lockIconState[0] = android.R.attr.state_last; |
| break; |
| } |
| |
| if (aod) { |
| lockIconState[1] = android.R.attr.state_single; |
| } else { |
| lockIconState[1] = -android.R.attr.state_single; |
| } |
| |
| return lockIconState; |
| } |
| |
| private String typeToString(@IconType int type) { |
| switch (type) { |
| case ICON_NONE: |
| return "none"; |
| case ICON_LOCK: |
| return "lock"; |
| case ICON_FINGERPRINT: |
| return "fingerprint"; |
| case ICON_UNLOCK: |
| return "unlock"; |
| } |
| |
| return "invalid"; |
| } |
| |
| @Override |
| public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { |
| pw.println("Lock Icon View Parameters:"); |
| pw.println(" Center in px (x, y)= (" |
| + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); |
| pw.println(" Radius in pixels: " + mRadius); |
| pw.println(" Drawable padding: " + mLockIconPadding); |
| pw.println(" mIconType=" + typeToString(mIconType)); |
| pw.println(" mAod=" + mAod); |
| pw.println("Lock Icon View actual measurements:"); |
| pw.println(" topLeft= (" + getX() + ", " + getY() + ")"); |
| pw.println(" width=" + getWidth() + " height=" + getHeight()); |
| } |
| } |