Allow animation movie for "find the sensor" flow

This adds an optional overlay to specify a per-device
movie to illustrate enrolling a fingerprint. To enable,
create a new layout overlay for
fingerprint_enroll_find_sensor_graphic.xml using
FingerprintLocationAnimationVideoView

Fixes bug 22954305

Change-Id: I59294f71617ecf7a9bf09603fc0b068cc5aa8ff9
This commit is contained in:
Jim Miller
2015-11-19 20:37:31 -08:00
parent 9cbf325589
commit c1f72f9169
6 changed files with 200 additions and 35 deletions

View File

@@ -22,48 +22,50 @@
android:layout_height="match_parent" android:layout_height="match_parent"
style="?attr/fingerprint_layout_theme"> style="?attr/fingerprint_layout_theme">
<LinearLayout <FrameLayout
style="@style/SuwContentFrame"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:clipToPadding="false" android:clipToPadding="false"
android:clipChildren="false"> android:clipChildren="false">
<TextView
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/suw_description_margin_top"
android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
<View
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"/>
<include <include
layout="@layout/fingerprint_enroll_find_sensor_graphic" layout="@layout/fingerprint_enroll_find_sensor_graphic"
android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
android:layout_height="@dimen/fingerprint_find_sensor_graphic_size"
android:layout_gravity="center_horizontal"/>
<View
android:layout_height="0dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_weight="1"/> android:layout_height="match_parent"
android:layout_gravity="center_horizontal|bottom"/>
<Button <LinearLayout
style="@style/Button.FingerprintButton" style="@style/SuwContentFrame"
android:id="@+id/next_button" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="match_parent"
android:layout_height="wrap_content" android:orientation="vertical"
android:layout_marginBottom="4dp" android:clipToPadding="false"
android:layout_marginEnd="-12dp" android:clipChildren="false">
android:layout_gravity="end"
android:gravity="end|center_vertical"
android:text="@string/fingerprint_enroll_button_next" />
</LinearLayout> <TextView
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/suw_description_margin_top"
android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
<View
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1"/>
<Button
style="@style/Button.FingerprintButton"
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="-12dp"
android:layout_gravity="end"
android:gravity="end|center_vertical"
android:text="@string/fingerprint_enroll_button_next" />
</LinearLayout>
</FrameLayout>
</com.android.setupwizardlib.SetupWizardLayout> </com.android.setupwizardlib.SetupWizardLayout>

View File

@@ -33,7 +33,7 @@ public class FingerprintEnrollFindSensor extends FingerprintEnrollBase {
private static final int ENROLLING = 2; private static final int ENROLLING = 2;
public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock"; public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
private FingerprintLocationAnimationView mAnimation; private FingerprintFindSensorAnimation mAnimation;
private boolean mLaunchedConfirmLock; private boolean mLaunchedConfirmLock;
@Override @Override
@@ -46,7 +46,7 @@ public class FingerprintEnrollFindSensor extends FingerprintEnrollBase {
if (mToken == null && !mLaunchedConfirmLock) { if (mToken == null && !mLaunchedConfirmLock) {
launchConfirmLock(); launchConfirmLock();
} }
mAnimation = (FingerprintLocationAnimationView) findViewById( mAnimation = (FingerprintFindSensorAnimation) findViewById(
R.id.fingerprint_sensor_location_animation); R.id.fingerprint_sensor_location_animation);
} }

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2015 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.settings.fingerprint;
/**
* An abstraction for a view that contains an animation that shows the user
* where the fingerprint sensor is on the device.
*/
public interface FingerprintFindSensorAnimation {
/**
* Start the animation
*/
void startAnimation();
/**
* Stop the animation
*/
void stopAnimation();
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2015 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.settings.fingerprint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnInfoListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import com.android.settings.R;
/**
* A view containing a VideoView for showing the user how to enroll a fingerprint
*/
public class FingerprintLocationAnimationVideoView extends TextureView
implements FingerprintFindSensorAnimation {
protected float mAspect = 1.0f; // initial guess until we know
protected MediaPlayer mMediaPlayer;
public FingerprintLocationAnimationVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Width is driven by measurespec, height is derrived from aspect ratio
int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
int height = Math.round(mAspect * originalWidth);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
setSurfaceTextureListener(new SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
int height) {
setVisibility(View.INVISIBLE);
Uri videoUri = resourceEntryToUri(mContext, R.raw.fingerprint_location_animation);
mMediaPlayer = MediaPlayer.create(mContext, videoUri);
mMediaPlayer.setSurface(new Surface(surfaceTexture));
mMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.setLooping(true);
}
});
mMediaPlayer.setOnInfoListener(new OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mediaPlayer, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// Keep the view hidden until video starts
setVisibility(View.VISIBLE);
}
return false;
}
});
mAspect = (float) mMediaPlayer.getVideoHeight() / mMediaPlayer.getVideoWidth();
requestLayout();
startAnimation();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
});
}
private static Uri resourceEntryToUri (Context context, int id) {
Resources res = context.getResources();
return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
res.getResourcePackageName(id) + '/' +
res.getResourceTypeName(id) + '/' +
res.getResourceEntryName(id));
}
@Override
public void startAnimation() {
if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
}
}
@Override
public void stopAnimation() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
}
}

View File

@@ -34,7 +34,8 @@ import com.android.settings.R;
/** /**
* View which plays an animation to indicate where the sensor is on the device. * View which plays an animation to indicate where the sensor is on the device.
*/ */
public class FingerprintLocationAnimationView extends View { public class FingerprintLocationAnimationView extends View implements
FingerprintFindSensorAnimation {
private static final float MAX_PULSE_ALPHA = 0.15f; private static final float MAX_PULSE_ALPHA = 0.15f;
private static final long DELAY_BETWEEN_PHASE = 1000; private static final long DELAY_BETWEEN_PHASE = 1000;
@@ -95,10 +96,12 @@ public class FingerprintLocationAnimationView extends View {
return getHeight() * mFractionCenterY; return getHeight() * mFractionCenterY;
} }
@Override
public void startAnimation() { public void startAnimation() {
startPhase(); startPhase();
} }
@Override
public void stopAnimation() { public void stopAnimation() {
removeCallbacks(mStartPhaseRunnable); removeCallbacks(mStartPhaseRunnable);
if (mRadiusAnimator != null) { if (mRadiusAnimator != null) {