Add Fingerprint Dialog to SysUI

Bug: 67497360

Test: Modify settings to use new API
Change-Id: I93ef475852c15e4a1a2a54bdd23ae4b8a0b8b7d7
This commit is contained in:
Kevin Chyn
2018-01-19 14:15:46 -08:00
parent aae4a15a22
commit 42653e8d50
7 changed files with 702 additions and 2 deletions

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2018 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
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/fingerprint_dialog_bg_color" />
<corners android:radius="1dp"
android:topLeftRadius="16dp"
android:topRightRadius="16dp"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"/>
</shape>

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2018 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
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="60dp"
android:height="60dp"
android:viewportWidth="60"
android:viewportHeight="60">
<path
android:fillColor="#1A73E8"
android:fillType="evenOdd"
android:strokeWidth="1"
android:pathData="M 30 0 C 46.5685424949 0 60 13.4314575051 60 30 C 60 46.5685424949 46.5685424949 60 30 60 C 13.4314575051 60 0 46.5685424949 0 30 C 0 13.4314575051 13.4314575051 0 30 0 Z" />
<group
android:translateX="17.727273"
android:translateY="16.363636">
<path
android:fillColor="#FFFFFF"
android:strokeWidth="1"
android:pathData="M20.3065726,3.44516129 C20.1974817,3.44516129 20.0883908,3.41788856
19.9929362,3.36334311 C17.3747544,2.01334311 15.111118,1.44061584
12.3974817,1.44061584 C9.69748166,1.44061584 7.1338453,2.08152493
4.80202711,3.36334311 C4.47475439,3.54061584 4.06566348,3.41788856
3.87475439,3.09061584 C3.69748166,2.76334311 3.82020893,2.34061584
4.14748166,2.16334311 C6.6838453,0.786070381 9.46566348,0.0769794721
12.3974817,0.0769794721 C15.3020271,0.0769794721 17.8383908,0.717888563
20.6202089,2.14970674 C20.961118,2.32697947 21.0838453,2.73607038
20.9065726,3.06334311 C20.7838453,3.30879765 20.5520271,3.44516129
20.3065726,3.44516129 L20.3065726,3.44516129 Z M0.792936205,10.6042522
C0.656572568,10.6042522 0.520208932,10.5633431 0.397481659,10.4815249
C0.0838452956,10.2633431 0.0156634774,9.84061584 0.233845296,9.52697947
C1.5838453,7.61788856 3.30202711,6.11788856 5.34748166,5.06788856
C9.62929984,2.85879765 15.111118,2.84516129 19.4065726,5.0542522
C21.4520271,6.1042522 23.1702089,7.59061584 24.5202089,9.48607038
C24.7383908,9.78607038 24.6702089,10.222434 24.3565726,10.4406158
C24.0429362,10.6587977 23.6202089,10.5906158 23.4020271,10.2769795
C22.1747544,8.55879765 20.6202089,7.20879765 18.7792998,6.26788856
C14.8656635,4.26334311 9.86111802,4.26334311 5.96111802,6.28152493
C4.10657257,7.23607038 2.55202711,8.59970674 1.32475439,10.3178886
C1.21566348,10.5087977 1.01111802,10.6042522 0.792936205,10.6042522
L0.792936205,10.6042522 Z M9.31566348,27.0633431 C9.13839075,27.0633431
8.96111802,26.9951613 8.83839075,26.8587977 C7.65202711,25.672434
7.01111802,24.9087977 6.09748166,23.2587977 C5.15657257,21.5815249
4.66566348,19.5360704 4.66566348,17.3406158 C4.66566348,13.2906158
8.12929984,9.99061584 12.3838453,9.99061584 C16.6383908,9.99061584
20.1020271,13.2906158 20.1020271,17.3406158 C20.1020271,17.722434
19.8020271,18.022434 19.4202089,18.022434 C19.0383908,18.022434
18.7383908,17.722434 18.7383908,17.3406158 C18.7383908,14.0406158
15.8883908,11.3542522 12.3838453,11.3542522 C8.87929984,11.3542522
6.02929984,14.0406158 6.02929984,17.3406158 C6.02929984,19.3042522
6.46566348,21.1178886 7.29748166,22.5906158 C8.17020893,24.1587977
8.77020893,24.8269795 9.82020893,25.8906158 C10.0792998,26.1633431
10.0792998,26.5860704 9.82020893,26.8587977 C9.67020893,26.9951613
9.4929362,27.0633431 9.31566348,27.0633431 Z M19.0929362,24.5406158
C17.4702089,24.5406158 16.0383908,24.1315249 14.8656635,23.3269795
C12.8338453,21.9497067 11.6202089,19.7133431 11.6202089,17.3406158
C11.6202089,16.9587977 11.9202089,16.6587977 12.3020271,16.6587977
C12.6838453,16.6587977 12.9838453,16.9587977 12.9838453,17.3406158
C12.9838453,19.2633431 13.9656635,21.0769795 15.6292998,22.1951613
C16.5974817,22.8497067 17.7292998,23.1633431 19.0929362,23.1633431
C19.4202089,23.1633431 19.9656635,23.122434 20.511118,23.0269795
C20.8792998,22.9587977 21.2338453,23.2042522 21.3020271,23.5860704
C21.3702089,23.9542522 21.1247544,24.3087977 20.7429362,24.3769795
C19.9656635,24.5269795 19.2838453,24.5406158 19.0929362,24.5406158
L19.0929362,24.5406158 Z M16.3520271,27.3497067 C16.2974817,27.3497067
16.2292998,27.3360704 16.1747544,27.322434 C14.0065726,26.722434
12.5883908,25.9178886 11.1020271,24.4587977 C9.1929362,22.5633431
8.1429362,20.0406158 8.1429362,17.3406158 C8.1429362,15.1315249
10.0247544,13.3315249 12.3429362,13.3315249 C14.661118,13.3315249
16.5429362,15.1315249 16.5429362,17.3406158 C16.5429362,18.7997067
17.811118,19.9860704 19.3792998,19.9860704 C20.9474817,19.9860704
22.2156635,18.7997067 22.2156635,17.3406158 C22.2156635,12.1997067
17.7838453,8.02697947 12.3292998,8.02697947 C8.45657257,8.02697947
4.91111802,10.1815249 3.31566348,13.522434 C2.7838453,14.6269795
2.51111802,15.922434 2.51111802,17.3406158 C2.51111802,18.4042522
2.60657257,20.0815249 3.42475439,22.2633431 C3.56111802,22.6178886
3.3838453,23.0133431 3.02929984,23.1360704 C2.67475439,23.272434
2.27929984,23.0815249 2.15657257,22.7406158 C1.48839075,20.9542522
1.16111802,19.1815249 1.16111802,17.3406158 C1.16111802,15.7042522
1.47475439,14.2178886 2.08839075,12.922434 C3.90202711,9.11788856
7.92475439,6.64970674 12.3292998,6.64970674 C18.5338453,6.64970674
23.5792998,11.4360704 23.5792998,17.3269795 C23.5792998,19.5360704
21.6974817,21.3360704 19.3792998,21.3360704 C17.061118,21.3360704
15.1792998,19.5360704 15.1792998,17.3269795 C15.1792998,15.8678886
13.911118,14.6815249 12.3429362,14.6815249 C10.7747544,14.6815249
9.50657257,15.8678886 9.50657257,17.3269795 C9.50657257,19.6587977
10.4065726,21.8406158 12.0565726,23.4769795 C13.3520271,24.7587977
14.5929362,25.4678886 16.5156635,25.9997067 C16.8838453,26.0951613
17.0883908,26.4769795 16.9929362,26.8315249 C16.9247544,27.1451613
16.6383908,27.3497067 16.3520271,27.3497067 L16.3520271,27.3497067 Z" />
</group>
</vector>

View File

@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2018 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
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:background="@color/fingerprint_dialog_dim_color"
android:orientation="vertical">
<!-- This is not a Space since Spaces cannot be clicked -->
<View
android:id="@+id/space"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
<LinearLayout
android:id="@+id/dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="2dp"
android:background="@drawable/fingerprint_dialog_bg">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:elevation="2dp">
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/fingerprint_dialog_icon_size"
android:layout_height="@dimen/fingerprint_dialog_icon_size"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:scaleType="centerInside" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/icon"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:textSize="20sp"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:textColor="@color/fingerprint_dialog_text_color"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/icon"
android:layout_below="@+id/title"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:textSize="12sp"
android:maxLines="2"
android:textColor="@color/fingerprint_dialog_text_color"/>
</RelativeLayout>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:paddingTop="16dp"
android:paddingBottom="20dp"
android:textSize="16sp"
android:maxLines="4"
android:textColor="@color/fingerprint_dialog_text_color"/>
<ImageView
android:id="@+id/fingerprint_icon"
android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
android:layout_gravity="center_horizontal"
android:scaleType="centerInside"
android:src="@drawable/fingerprint_icon"/>
<TextView
android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd = "16dp"
android:layout_marginStart="16dp"
android:paddingTop="16dp"
android:paddingBottom="60dp"
android:textSize="12sp"
android:visibility="invisible"
android:gravity="center_horizontal"
android:textColor="@color/fingerprint_error_message_color"/>
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical" >
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingStart="2dip"
android:paddingEnd="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
<!-- Positive Button -->
<Button android:id="@+id/button1"
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content"/>
<!-- Negative Button -->
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
android:layout_weight="0.25"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -156,6 +156,14 @@
<color name="zen_introduction">#ffffffff</color>
<color name="smart_reply_button_text">#ff4285f4</color><!-- blue 500 -->
<color name="smart_reply_button_background">#fff7f7f7</color>
<!-- Fingerprint dialog colors -->
<color name="fingerprint_dialog_bg_color">#f4ffffff</color> <!-- 96% white -->
<color name="fingerprint_dialog_text_color">#ff424242</color> <!-- gray 800-->
<color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
<color name="fingerprint_error_message_color">#ff5722</color>
</resources>

View File

@@ -889,4 +889,7 @@
<dimen name="smart_reply_button_spacing">8dp</dimen>
<dimen name="smart_reply_button_padding_vertical">4dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="fingerprint_dialog_icon_size">44dp</dimen>
<dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
</resources>

View File

@@ -16,17 +16,75 @@
package com.android.systemui.fingerprint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintDialog;
import android.hardware.fingerprint.IFingerprintDialogReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManager;
import com.android.internal.os.SomeArgs;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.CommandQueue;
public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Callbacks {
private static final String TAG = "FingerprintDialogImpl";
private static final boolean DEBUG = false;
private static final boolean DEBUG = true;
protected static final int MSG_SHOW_DIALOG = 1;
protected static final int MSG_FINGERPRINT_AUTHENTICATED = 2;
protected static final int MSG_FINGERPRINT_HELP = 3;
protected static final int MSG_FINGERPRINT_ERROR = 4;
protected static final int MSG_HIDE_DIALOG = 5;
protected static final int MSG_BUTTON_NEGATIVE = 6;
protected static final int MSG_USER_CANCELED = 7;
protected static final int MSG_BUTTON_POSITIVE = 8;
protected static final int MSG_CLEAR_MESSAGE = 9;
private FingerprintDialogView mDialogView;
private WindowManager mWindowManager;
private IFingerprintDialogReceiver mReceiver;
private boolean mDialogShowing;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_SHOW_DIALOG:
handleShowDialog((SomeArgs) msg.obj);
break;
case MSG_FINGERPRINT_AUTHENTICATED:
handleFingerprintAuthenticated();
break;
case MSG_FINGERPRINT_HELP:
handleFingerprintHelp((String) msg.obj);
break;
case MSG_FINGERPRINT_ERROR:
handleFingerprintError((String) msg.obj);
break;
case MSG_HIDE_DIALOG:
handleHideDialog((Boolean) msg.obj);
break;
case MSG_BUTTON_NEGATIVE:
handleButtonNegative();
break;
case MSG_USER_CANCELED:
handleUserCanceled();
break;
case MSG_BUTTON_POSITIVE:
handleButtonPositive();
break;
case MSG_CLEAR_MESSAGE:
handleClearMessage();
break;
}
}
};
@Override
public void start() {
@@ -34,30 +92,129 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
return;
}
getComponent(CommandQueue.class).addCallbacks(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mDialogView = new FingerprintDialogView(mContext, mHandler);
}
@Override
public void showFingerprintDialog(Bundle bundle, IFingerprintDialogReceiver receiver) {
if (DEBUG) Log.d(TAG, "show fingerprint dialog");
if (DEBUG) Log.d(TAG, "showFingerprintDialog");
// Remove these messages as they are part of the previous client
mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
mHandler.removeMessages(MSG_FINGERPRINT_HELP);
mHandler.removeMessages(MSG_FINGERPRINT_AUTHENTICATED);
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
args.arg2 = receiver;
mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
}
@Override
public void onFingerprintAuthenticated() {
if (DEBUG) Log.d(TAG, "onFingerprintAuthenticated");
mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED).sendToTarget();
}
@Override
public void onFingerprintHelp(String message) {
if (DEBUG) Log.d(TAG, "onFingerprintHelp: " + message);
mHandler.obtainMessage(MSG_FINGERPRINT_HELP, message).sendToTarget();
}
@Override
public void onFingerprintError(String error) {
if (DEBUG) Log.d(TAG, "onFingerprintError: " + error);
mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, error).sendToTarget();
}
@Override
public void hideFingerprintDialog() {
if (DEBUG) Log.d(TAG, "hideFingerprintDialog");
mHandler.obtainMessage(MSG_HIDE_DIALOG, false /* userCanceled */).sendToTarget();
}
private void handleShowDialog(SomeArgs args) {
if (DEBUG) Log.d(TAG, "handleShowDialog");
if (mDialogShowing) {
Log.w(TAG, "Dialog already showing");
return;
}
mReceiver = (IFingerprintDialogReceiver) args.arg2;
mDialogView.setBundle((Bundle)args.arg1);
mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
mDialogShowing = true;
}
private void handleFingerprintAuthenticated() {
if (DEBUG) Log.d(TAG, "handleFingerprintAuthenticated");
handleHideDialog(false /* userCanceled */);
}
private void handleFingerprintHelp(String message) {
if (DEBUG) Log.d(TAG, "handleFingerprintHelp: " + message);
mDialogView.showHelpMessage(message);
}
private void handleFingerprintError(String error) {
if (DEBUG) Log.d(TAG, "handleFingerprintError: " + error);
if (!mDialogShowing) {
if (DEBUG) Log.d(TAG, "Dialog already dismissed");
return;
}
mDialogView.showErrorMessage(error);
}
private void handleHideDialog(boolean userCanceled) {
if (DEBUG) Log.d(TAG, "handleHideDialog");
if (!mDialogShowing) {
// This can happen if there's a race and we get called from both
// onAuthenticated and onError, etc.
Log.w(TAG, "Dialog already dismissed, userCanceled: " + userCanceled);
return;
}
if (userCanceled) {
try {
mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_USER_CANCEL);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException when hiding dialog", e);
}
}
mReceiver = null;
mWindowManager.removeView(mDialogView);
mDialogShowing = false;
}
private void handleButtonNegative() {
if (mReceiver == null) {
Log.e(TAG, "Receiver is null");
return;
}
try {
mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_NEGATIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling negative button", e);
}
handleHideDialog(false /* userCanceled */);
}
private void handleButtonPositive() {
if (mReceiver == null) {
Log.e(TAG, "Receiver is null");
return;
}
try {
mReceiver.onDialogDismissed(FingerprintDialog.DISMISSED_REASON_POSITIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling positive button", e);
}
handleHideDialog(false /* userCanceled */);
}
private void handleClearMessage() {
mDialogView.clearMessage();
}
private void handleUserCanceled() {
handleHideDialog(true /* userCanceled */);
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) 2018 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.systemui.fingerprint;
import android.animation.Animator;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintDialog;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
/**
* This class loads the view for the system-provided dialog. The view consists of:
* Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
* and positive/negative buttons.
*/
public class FingerprintDialogView extends LinearLayout {
private static final String TAG = "FingerprintDialogView";
private static final int ANIMATION_VERTICAL_OFFSET_DP = 96;
private static final int ANIMATION_DURATION = 250; // ms
private final IBinder mWindowToken = new Binder();
private final WindowManager mWindowManager;
private final ActivityManagerWrapper mActivityManagerWrapper;
private final PackageManagerWrapper mPackageManageWrapper;
private final Interpolator mLinearOutSlowIn;
private final Interpolator mFastOutLinearIn;
private ViewGroup mLayout;
private final TextView mErrorText;
private Handler mHandler;
private Bundle mBundle;
private final float mDensity;
private final LinearLayout mDialog;
public FingerprintDialogView(Context context, Handler handler) {
super(context);
mHandler = handler;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
mPackageManageWrapper = PackageManagerWrapper.getInstance();
mLinearOutSlowIn = AnimationUtils
.loadInterpolator(getContext(), android.R.interpolator.linear_out_slow_in);
mFastOutLinearIn = AnimationUtils
.loadInterpolator(getContext(), android.R.interpolator.fast_out_linear_in);
// Create the dialog
LayoutInflater factory = LayoutInflater.from(getContext());
mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
addView(mLayout);
mDialog = mLayout.findViewById(R.id.dialog);
DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
mErrorText = mLayout.findViewById(R.id.error);
mLayout.setOnKeyListener(new View.OnKeyListener() {
boolean downPressed = false;
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode != KeyEvent.KEYCODE_BACK) {
return false;
}
if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
downPressed = true;
} else if (event.getAction() == KeyEvent.ACTION_DOWN) {
downPressed = false;
} else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
downPressed = false;
mHandler.obtainMessage(FingerprintDialogImpl.MSG_USER_CANCELED).sendToTarget();
}
return true;
}
});
final View space = mLayout.findViewById(R.id.space);
final Button negative = mLayout.findViewById(R.id.button2);
final Button positive = mLayout.findViewById(R.id.button1);
space.setClickable(true);
space.setOnTouchListener((View view, MotionEvent event) -> {
mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled*/)
.sendToTarget();
return true;
});
negative.setOnClickListener((View v) -> {
mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_NEGATIVE).sendToTarget();
});
positive.setOnClickListener((View v) -> {
mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_POSITIVE).sendToTarget();
});
mLayout.setFocusableInTouchMode(true);
mLayout.requestFocus();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
final TextView title = mLayout.findViewById(R.id.title);
final TextView subtitle = mLayout.findViewById(R.id.subtitle);
final TextView description = mLayout.findViewById(R.id.description);
final Button negative = mLayout.findViewById(R.id.button2);
final ImageView image = mLayout.findViewById(R.id.icon);
final Button positive = mLayout.findViewById(R.id.button1);
final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
title.setText(mBundle.getCharSequence(FingerprintDialog.KEY_TITLE));
title.setSelected(true);
subtitle.setText(mBundle.getCharSequence(FingerprintDialog.KEY_SUBTITLE));
description.setText(mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION));
negative.setText(mBundle.getCharSequence(FingerprintDialog.KEY_NEGATIVE_TEXT));
image.setImageDrawable(getAppIcon());
final CharSequence positiveText =
mBundle.getCharSequence(FingerprintDialog.KEY_POSITIVE_TEXT);
positive.setText(positiveText); // needs to be set for marquee to work
if (positiveText != null) {
positive.setVisibility(View.VISIBLE);
} else {
positive.setVisibility(View.GONE);
}
// Dim the background and slide the dialog up
mDialog.setTranslationY(ANIMATION_VERTICAL_OFFSET_DP * mDensity);
mLayout.setAlpha(0f);
postOnAnimation(new Runnable() {
@Override
public void run() {
mLayout.animate()
.alpha(1f)
.setDuration(ANIMATION_DURATION)
.setInterpolator(mLinearOutSlowIn)
.withLayer()
.start();
mDialog.animate()
.translationY(0)
.setDuration(ANIMATION_DURATION)
.setInterpolator(mLinearOutSlowIn)
.withLayer()
.start();
}
});
}
public void setBundle(Bundle bundle) {
mBundle = bundle;
}
protected void clearMessage() {
mErrorText.setVisibility(View.INVISIBLE);
}
private void showMessage(String message) {
mHandler.removeMessages(FingerprintDialogImpl.MSG_CLEAR_MESSAGE);
mErrorText.setText(message);
mErrorText.setVisibility(View.VISIBLE);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
FingerprintDialog.HIDE_DIALOG_DELAY);
}
public void showHelpMessage(String message) {
showMessage(message);
}
public void showErrorMessage(String error) {
showMessage(error);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
false /* userCanceled */), FingerprintDialog.HIDE_DIALOG_DELAY);
}
private Drawable getAppIcon() {
final ActivityManager.RunningTaskInfo taskInfo = mActivityManagerWrapper.getRunningTask();
final ComponentName cn = taskInfo.topActivity;
final int userId = mActivityManagerWrapper.getCurrentUserId();
final ActivityInfo activityInfo = mPackageManageWrapper.getActivityInfo(cn, userId);
return mActivityManagerWrapper.getBadgedActivityIcon(activityInfo, userId);
}
public WindowManager.LayoutParams getLayoutParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("FingerprintDialogView");
lp.token = mWindowToken;
return lp;
}
}