blob: 19bc2ecc34b7deb9a5715de7b784e2be4872bc92 [file] [log] [blame]
Kevin Chyn42653e82018-01-19 14:15:46 -08001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.fingerprint;
18
Kevin Chyn42653e82018-01-19 14:15:46 -080019import android.app.ActivityManager;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.pm.ActivityInfo;
23import android.graphics.PixelFormat;
24import android.graphics.drawable.Drawable;
25import android.hardware.fingerprint.FingerprintDialog;
26import android.os.Binder;
27import android.os.Bundle;
28import android.os.Handler;
29import android.os.IBinder;
Kevin Chyn42653e82018-01-19 14:15:46 -080030import android.view.KeyEvent;
31import android.view.LayoutInflater;
32import android.view.MotionEvent;
33import android.view.View;
34import android.view.ViewGroup;
Kevin Chyn42653e82018-01-19 14:15:46 -080035import android.view.WindowManager;
Kevin Chyn42653e82018-01-19 14:15:46 -080036import android.view.animation.Interpolator;
37import android.widget.Button;
38import android.widget.ImageView;
39import android.widget.LinearLayout;
40import android.widget.TextView;
41
Kevin Chyne8f3e1b2018-01-23 17:33:58 -080042import com.android.systemui.Interpolators;
Kevin Chyn42653e82018-01-19 14:15:46 -080043import com.android.systemui.R;
44import com.android.systemui.shared.system.ActivityManagerWrapper;
45import com.android.systemui.shared.system.PackageManagerWrapper;
46
47/**
48 * This class loads the view for the system-provided dialog. The view consists of:
49 * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
50 * and positive/negative buttons.
51 */
52public class FingerprintDialogView extends LinearLayout {
53
54 private static final String TAG = "FingerprintDialogView";
55
Kevin Chyn42653e82018-01-19 14:15:46 -080056 private static final int ANIMATION_DURATION = 250; // ms
57
58 private final IBinder mWindowToken = new Binder();
Kevin Chyn42653e82018-01-19 14:15:46 -080059 private final ActivityManagerWrapper mActivityManagerWrapper;
60 private final PackageManagerWrapper mPackageManageWrapper;
61 private final Interpolator mLinearOutSlowIn;
62 private final Interpolator mFastOutLinearIn;
Kevin Chyne8f3e1b2018-01-23 17:33:58 -080063 private final float mAnimationTranslationOffset;
Kevin Chyn42653e82018-01-19 14:15:46 -080064
65 private ViewGroup mLayout;
66 private final TextView mErrorText;
67 private Handler mHandler;
68 private Bundle mBundle;
Kevin Chyn42653e82018-01-19 14:15:46 -080069 private final LinearLayout mDialog;
70
71 public FingerprintDialogView(Context context, Handler handler) {
72 super(context);
73 mHandler = handler;
Kevin Chyn42653e82018-01-19 14:15:46 -080074 mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
75 mPackageManageWrapper = PackageManagerWrapper.getInstance();
Kevin Chyne8f3e1b2018-01-23 17:33:58 -080076 mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
77 mFastOutLinearIn = Interpolators.FAST_OUT_LINEAR_IN;
78 mAnimationTranslationOffset = getResources()
79 .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
Kevin Chyn42653e82018-01-19 14:15:46 -080080
81 // Create the dialog
82 LayoutInflater factory = LayoutInflater.from(getContext());
83 mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
84 addView(mLayout);
85
86 mDialog = mLayout.findViewById(R.id.dialog);
Kevin Chyn42653e82018-01-19 14:15:46 -080087
88 mErrorText = mLayout.findViewById(R.id.error);
89
90 mLayout.setOnKeyListener(new View.OnKeyListener() {
91 boolean downPressed = false;
92 @Override
93 public boolean onKey(View v, int keyCode, KeyEvent event) {
94 if (keyCode != KeyEvent.KEYCODE_BACK) {
95 return false;
96 }
97 if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
98 downPressed = true;
99 } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
100 downPressed = false;
101 } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
102 downPressed = false;
103 mHandler.obtainMessage(FingerprintDialogImpl.MSG_USER_CANCELED).sendToTarget();
104 }
105 return true;
106 }
107 });
108
109 final View space = mLayout.findViewById(R.id.space);
110 final Button negative = mLayout.findViewById(R.id.button2);
111 final Button positive = mLayout.findViewById(R.id.button1);
112
113 space.setClickable(true);
114 space.setOnTouchListener((View view, MotionEvent event) -> {
115 mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG, true /* userCanceled*/)
116 .sendToTarget();
117 return true;
118 });
119
120 negative.setOnClickListener((View v) -> {
121 mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_NEGATIVE).sendToTarget();
122 });
123
124 positive.setOnClickListener((View v) -> {
125 mHandler.obtainMessage(FingerprintDialogImpl.MSG_BUTTON_POSITIVE).sendToTarget();
126 });
127
128 mLayout.setFocusableInTouchMode(true);
129 mLayout.requestFocus();
130 }
131
132 @Override
133 public void onAttachedToWindow() {
134 super.onAttachedToWindow();
135
136 final TextView title = mLayout.findViewById(R.id.title);
137 final TextView subtitle = mLayout.findViewById(R.id.subtitle);
138 final TextView description = mLayout.findViewById(R.id.description);
139 final Button negative = mLayout.findViewById(R.id.button2);
140 final ImageView image = mLayout.findViewById(R.id.icon);
141 final Button positive = mLayout.findViewById(R.id.button1);
142 final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
143
144 title.setText(mBundle.getCharSequence(FingerprintDialog.KEY_TITLE));
145 title.setSelected(true);
146 subtitle.setText(mBundle.getCharSequence(FingerprintDialog.KEY_SUBTITLE));
147 description.setText(mBundle.getCharSequence(FingerprintDialog.KEY_DESCRIPTION));
148 negative.setText(mBundle.getCharSequence(FingerprintDialog.KEY_NEGATIVE_TEXT));
149 image.setImageDrawable(getAppIcon());
150
151 final CharSequence positiveText =
152 mBundle.getCharSequence(FingerprintDialog.KEY_POSITIVE_TEXT);
153 positive.setText(positiveText); // needs to be set for marquee to work
154 if (positiveText != null) {
155 positive.setVisibility(View.VISIBLE);
156 } else {
157 positive.setVisibility(View.GONE);
158 }
159
160 // Dim the background and slide the dialog up
Kevin Chyne8f3e1b2018-01-23 17:33:58 -0800161 mDialog.setTranslationY(mAnimationTranslationOffset);
Kevin Chyn42653e82018-01-19 14:15:46 -0800162 mLayout.setAlpha(0f);
163 postOnAnimation(new Runnable() {
164 @Override
165 public void run() {
166 mLayout.animate()
167 .alpha(1f)
168 .setDuration(ANIMATION_DURATION)
169 .setInterpolator(mLinearOutSlowIn)
170 .withLayer()
171 .start();
172 mDialog.animate()
173 .translationY(0)
174 .setDuration(ANIMATION_DURATION)
175 .setInterpolator(mLinearOutSlowIn)
176 .withLayer()
177 .start();
178 }
179 });
180 }
181
182 public void setBundle(Bundle bundle) {
183 mBundle = bundle;
184 }
185
186 protected void clearMessage() {
187 mErrorText.setVisibility(View.INVISIBLE);
188 }
189
190 private void showMessage(String message) {
191 mHandler.removeMessages(FingerprintDialogImpl.MSG_CLEAR_MESSAGE);
192 mErrorText.setText(message);
193 mErrorText.setVisibility(View.VISIBLE);
194 mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
195 FingerprintDialog.HIDE_DIALOG_DELAY);
196 }
197
198 public void showHelpMessage(String message) {
199 showMessage(message);
200 }
201
202 public void showErrorMessage(String error) {
203 showMessage(error);
204 mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
205 false /* userCanceled */), FingerprintDialog.HIDE_DIALOG_DELAY);
206 }
207
208 private Drawable getAppIcon() {
209 final ActivityManager.RunningTaskInfo taskInfo = mActivityManagerWrapper.getRunningTask();
210 final ComponentName cn = taskInfo.topActivity;
211 final int userId = mActivityManagerWrapper.getCurrentUserId();
212 final ActivityInfo activityInfo = mPackageManageWrapper.getActivityInfo(cn, userId);
213 return mActivityManagerWrapper.getBadgedActivityIcon(activityInfo, userId);
214 }
215
216 public WindowManager.LayoutParams getLayoutParams() {
217 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
218 ViewGroup.LayoutParams.MATCH_PARENT,
219 ViewGroup.LayoutParams.MATCH_PARENT,
220 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
221 WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
222 PixelFormat.TRANSLUCENT);
223 lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
224 lp.setTitle("FingerprintDialogView");
225 lp.token = mWindowToken;
226 return lp;
227 }
228}