15438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly/*
25438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * Copyright (C) 2011 The Android Open Source Project
35438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly *
45438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
55438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * you may not use this file except in compliance with the License.
65438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * You may obtain a copy of the License at
75438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly *
85438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
95438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly *
105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * Unless required by applicable law or agreed to in writing, software
115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * See the License for the specific language governing permissions and
145438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * limitations under the License.
155438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */
165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
175438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellypackage com.android.nfc;
185438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
1965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Moralesimport com.android.internal.policy.PolicyManager;
2065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales
215438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.Animator;
2269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.animation.AnimatorSet;
235438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.ObjectAnimator;
245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.PropertyValuesHolder;
25f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenenimport android.animation.TimeAnimator;
260c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.ActivityManager;
270c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.StatusBarManager;
285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.content.Context;
2969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.pm.ActivityInfo;
3069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.res.Configuration;
315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Bitmap;
325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Canvas;
335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Matrix;
345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.PixelFormat;
35217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.graphics.SurfaceTexture;
3657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenenimport android.os.AsyncTask;
375438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.os.Binder;
385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.util.DisplayMetrics;
39595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenenimport android.util.Log;
409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.ActionMode;
415438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Display;
429340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.KeyEvent;
435438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.LayoutInflater;
449340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.Menu;
459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.MenuItem;
46b2112cff553c3b6658440bf06060c7a08f82df5cNick Pellyimport android.view.MotionEvent;
475438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Surface;
4882792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopianimport android.view.SurfaceControl;
49217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.view.TextureView;
505438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.View;
515438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.ViewGroup;
529340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.Window;
535438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.WindowManager;
549340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.WindowManager.LayoutParams;
559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.accessibility.AccessibilityEvent;
560c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.view.animation.AccelerateDecelerateInterpolator;
5769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.view.animation.DecelerateInterpolator;
585438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.widget.ImageView;
59be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenenimport android.widget.TextView;
60a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenenimport android.widget.Toast;
615438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
625438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly/**
63f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * This class is responsible for handling the UI animation
64f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * around Android Beam. The animation consists of the following
65f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * animators:
66f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
67f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator: scales the screenshot down to INTERMEDIATE_SCALE
68f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mSlowSendAnimator: scales the screenshot down to 0.2f (used as a "send in progress" animation)
69f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFastSendAnimator: quickly scales the screenshot down to 0.0f (used for send success)
70f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFadeInAnimator: fades the current activity back in (used after mFastSendAnimator completes)
71f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mScaleUpAnimator: scales the screenshot back up to full screen (used for failure or receiving)
72f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mHintAnimator: Slowly turns up the alpha of the "Touch to Beam" hint
73f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
74f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Possible sequences are:
75f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
76f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mFastSendAnimator => mFadeInAnimator (send success)
77f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mScaleUpAnimator (send failure)
78f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mScaleUpAnimator (p2p link broken, or data received)
79f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
80f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Note that mFastSendAnimator and mFadeInAnimator are combined in a set, as they
81f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * are an atomic animation that cannot be interrupted.
82f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
83f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * All methods of this class must be called on the UI thread
845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */
8565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Moralespublic class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
8665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        TimeAnimator.TimeListener, TextureView.SurfaceTextureListener, android.view.Window.Callback {
8765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    static final String TAG = "SendUi";
88595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen
8969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float INTERMEDIATE_SCALE = 0.6f;
905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
9169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float[] PRE_SCREENSHOT_SCALE = {1.0f, INTERMEDIATE_SCALE};
92674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int PRE_DURATION_MS = 350;
9369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
94f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    static final float[] SEND_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 0.2f};
95674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int SLOW_SEND_DURATION_MS = 8000; // Stretch out sending over 8s
96f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    static final int FAST_SEND_DURATION_MS = 350;
9769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
9869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float[] SCALE_UP_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 1.0f};
9969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final int SCALE_UP_DURATION_MS = 300;
1005438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
101674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int FADE_IN_DURATION_MS = 250;
102674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int FADE_IN_START_DELAY_MS = 350;
103674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely
1040c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen    static final int SLIDE_OUT_DURATION_MS = 300;
1050c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
1061a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final float[] BLACK_LAYER_ALPHA_DOWN_RANGE = {0.9f, 0.0f};
1071a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final float[] BLACK_LAYER_ALPHA_UP_RANGE = {0.0f, 0.9f};
1081a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
109be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen    static final float[] TEXT_HINT_ALPHA_RANGE = {0.0f, 1.0f};
110be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen    static final int TEXT_HINT_ALPHA_DURATION_MS = 500;
111674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int TEXT_HINT_ALPHA_START_DELAY_MS = 300;
112be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
1130c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen    static final int FINISH_SCALE_UP = 0;
114f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    static final int FINISH_SEND_SUCCESS = 1;
1150c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
11657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int STATE_IDLE = 0;
117595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    static final int STATE_W4_SCREENSHOT = 1;
118595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    static final int STATE_W4_SCREENSHOT_PRESEND_REQUESTED = 2;
1199340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED = 3;
1209340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_SCREENSHOT_THEN_STOP = 4;
1219340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_PRESEND = 5;
1229340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_TOUCH = 6;
1239340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_NFC_TAP = 7;
1249340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_SENDING = 8;
1259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_COMPLETE = 9;
12657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
1275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    // all members are only used on UI thread
12865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final WindowManager mWindowManager;
12965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Context mContext;
13065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Display mDisplay;
13165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final DisplayMetrics mDisplayMetrics;
13265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Matrix mDisplayMatrix;
13365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final WindowManager.LayoutParams mWindowLayoutParams;
13465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final LayoutInflater mLayoutInflater;
13565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final StatusBarManager mStatusBarManager;
13665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final View mScreenshotLayout;
13765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ImageView mScreenshotView;
13865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ImageView mBlackLayer;
13965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextureView mTextureView;
14065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextView mTextHint;
14165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextView mTextRetry;
14265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Callback mCallback;
143f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
144f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // The mFrameCounter animation is purely used to count down a certain
145f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // number of (vsync'd) frames. This is needed because the first 3
146f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // times the animation internally calls eglSwapBuffers(), large buffers
147f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // are allocated by the graphics drivers. This causes the animation
148f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // to look janky. So on platforms where we can use hardware acceleration,
149f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // the animation order is:
150f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Wait for hw surface => start frame counter => start pre-animation after 3 frames
151f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // For platforms where no hw acceleration can be used, the pre-animation
152f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // is started immediately.
15365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TimeAnimator mFrameCounterAnimator;
15465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales
15565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mPreAnimator;
15665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mSlowSendAnimator;
15765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mFastSendAnimator;
15865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mFadeInAnimator;
15965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mHintAnimator;
16065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mScaleUpAnimator;
16165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mAlphaDownAnimator;
16265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mAlphaUpAnimator;
16365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final AnimatorSet mSuccessAnimatorSet;
164f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
165f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Besides animating the screenshot, the Beam UI also renders
166f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // fireflies on platforms where we can do hardware-acceleration.
167f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Firefly rendering is only started once the initial
168f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // "pre-animation" has scaled down the screenshot, to avoid
169f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // that animation becoming janky. Likewise, the fireflies are
170f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // stopped in their tracks as soon as we finish the animation,
171f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // to make the finishing animation smooth.
17265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final boolean mHardwareAccelerated;
17365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final FireflyRenderer mFireflyRenderer;
1745438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
175a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    String mToastString;
1765438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    Bitmap mScreenshotBitmap;
1770c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
17857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    int mState;
179f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mRenderedFrames;
180f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
1819340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    View mDecor;
1829340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
183f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Used for holding the surface
184f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    SurfaceTexture mSurface;
185f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mSurfaceWidth;
186f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mSurfaceHeight;
1875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
18865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    interface Callback {
18965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        public void onSendConfirmed();
19065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        public void onCanceled();
1915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
1925438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
19365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    public SendUi(Context context, Callback callback) {
19465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mContext = context;
19565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mCallback = callback;
1965438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
1975438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplayMetrics = new DisplayMetrics();
1985438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplayMatrix = new Matrix();
19965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
20065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mStatusBarManager = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
2010c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
2025438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplay = mWindowManager.getDefaultDisplay();
2035438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
20465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mLayoutInflater = (LayoutInflater)
20565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotLayout = mLayoutInflater.inflate(R.layout.screenshot, null);
207f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
2085438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.screenshot);
2095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotLayout.setFocusable(true);
2105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
211be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mTextHint = (TextView) mScreenshotLayout.findViewById(R.id.calltoaction);
2121a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry = (TextView) mScreenshotLayout.findViewById(R.id.retrytext);
2131a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer = (ImageView) mScreenshotLayout.findViewById(R.id.blacklayer);
214217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mTextureView = (TextureView) mScreenshotLayout.findViewById(R.id.fireflies);
215217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mTextureView.setSurfaceTextureListener(this);
216217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
2170c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // We're only allowed to use hardware acceleration if
2180c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // isHighEndGfx() returns true - otherwise, we're too limited
2190c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // on resources to do it.
220525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mHardwareAccelerated = ActivityManager.isHighEndGfx();
2210c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        int hwAccelerationFlags = mHardwareAccelerated ?
222f7966d1dadff2d78f01bbdb134e8252b53343179Dianne Hackborn                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0;
2230c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
2245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mWindowLayoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
2250c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen                ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
2260c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
2275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                WindowManager.LayoutParams.FLAG_FULLSCREEN
22865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                | hwAccelerationFlags
22965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
2305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                PixelFormat.OPAQUE);
231525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mWindowLayoutParams.privateFlags |=
232525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mWindowLayoutParams.token = new Binder();
2345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
235f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator = new TimeAnimator();
236f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.setTimeListener(this);
237f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
2385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        PropertyValuesHolder preX = PropertyValuesHolder.ofFloat("scaleX", PRE_SCREENSHOT_SCALE);
2395438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        PropertyValuesHolder preY = PropertyValuesHolder.ofFloat("scaleY", PRE_SCREENSHOT_SCALE);
2405438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, preX, preY);
24169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mPreAnimator.setInterpolator(new DecelerateInterpolator());
2425438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.setDuration(PRE_DURATION_MS);
2435438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.addListener(this);
2445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
245f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", SEND_SCREENSHOT_SCALE);
246f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", SEND_SCREENSHOT_SCALE);
24765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha",
24865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[]{1.0f, 0.0f});
2494dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen
250217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, postY);
251674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mSlowSendAnimator.setInterpolator(new DecelerateInterpolator());
252217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator.setDuration(SLOW_SEND_DURATION_MS);
25369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
254f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX,
2554dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen                postY, alphaDown);
256f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.setInterpolator(new DecelerateInterpolator());
257f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.setDuration(FAST_SEND_DURATION_MS);
258f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.addListener(this);
25969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
26065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", SCALE_UP_SCREENSHOT_SCALE);
26165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", SCALE_UP_SCREENSHOT_SCALE);
2624dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen
26365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mScaleUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, scaleUpX, scaleUpY);
264674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mScaleUpAnimator.setInterpolator(new DecelerateInterpolator());
26569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.setDuration(SCALE_UP_DURATION_MS);
26669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.addListener(this);
26769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
268674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", 1.0f);
269674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, fadeIn);
270674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
271674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setDuration(FADE_IN_DURATION_MS);
272674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setStartDelay(FADE_IN_START_DELAY_MS);
273674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.addListener(this);
274674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely
275be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", TEXT_HINT_ALPHA_RANGE);
276be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextHint, alphaUp);
277be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator.setInterpolator(null);
278be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator.setDuration(TEXT_HINT_ALPHA_DURATION_MS);
279674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mHintAnimator.setStartDelay(TEXT_HINT_ALPHA_START_DELAY_MS);
280be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
2811a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        alphaDown = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_DOWN_RANGE);
2821a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaDown);
2831a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.setInterpolator(new DecelerateInterpolator());
2841a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.setDuration(400);
2851a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
2861a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        alphaUp = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_UP_RANGE);
2871a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaUp);
2881a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setInterpolator(new DecelerateInterpolator());
2891a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setDuration(200);
2901a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
29169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mSuccessAnimatorSet = new AnimatorSet();
292f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSuccessAnimatorSet.playSequentially(mFastSendAnimator, mFadeInAnimator);
2935438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
2949340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        // Create a Window with a Decor view; creating a window allows us to get callbacks
2959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        // on key events (which require a decor view to be dispatched).
29665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mContext.setTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen);
29765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        Window window = PolicyManager.makeNewWindow(mContext);
2989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.setCallback(this);
2999340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.requestFeature(Window.FEATURE_NO_TITLE);
3009340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mDecor = window.getDecorView();
3019340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.setContentView(mScreenshotLayout, mWindowLayoutParams);
3029340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
303f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (mHardwareAccelerated) {
30465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mFireflyRenderer = new FireflyRenderer(context);
305f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else {
306f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFireflyRenderer = null;
307f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        }
30857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_IDLE;
3095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
3105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
3115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void takeScreenshot() {
31257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // There's no point in taking the screenshot if
31357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // we're still finishing the previous animation.
3149340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState >= STATE_W4_TOUCH) {
31557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            return;
31657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
317595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        mState = STATE_W4_SCREENSHOT;
31857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        new ScreenshotTask().execute();
3195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
3205438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
32169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Show pre-send animation */
3229340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void showPreSend(boolean promptToNfcTap) {
323595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        switch (mState) {
324595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_IDLE:
325595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in STATE_IDLE");
326595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
327595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT:
328595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Still waiting for screenshot, store request in state
329595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // and wait for screenshot completion.
3309340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                if (promptToNfcTap) {
3319340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState = STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED;
3329340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                } else {
3339340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState = STATE_W4_SCREENSHOT_PRESEND_REQUESTED;
3349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
335595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
336595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_REQUESTED:
3379340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED:
338595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in STATE_W4_SCREENSHOT_PRESEND_REQUESTED");
339595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
340595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_PRESEND:
341595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Expected path, continue below
342595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                break;
343595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            default:
344595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in state " + Integer.toString(mState));
345595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
34657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
34790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Update display metrics
34890e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mDisplay.getRealMetrics(mDisplayMetrics);
34990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
35065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int statusBarHeight = mContext.getResources().getDimensionPixelSize(
35190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen                                        com.android.internal.R.dimen.status_bar_height);
35290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
3531a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setVisibility(View.GONE);
3541a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setAlpha(0f);
355595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        mScreenshotLayout.setOnTouchListener(this);
3565438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotView.setImageBitmap(mScreenshotBitmap);
3570c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mScreenshotView.setTranslationX(0f);
3580c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mScreenshotView.setAlpha(1.0f);
35990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mScreenshotView.setPadding(0, statusBarHeight, 0, 0);
36069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
36190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mScreenshotLayout.requestFocus();
36269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
3639340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (promptToNfcTap) {
36465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mTextHint.setText(mContext.getResources().getString(R.string.ask_nfc_tap));
3659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        } else {
36665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mTextHint.setText(mContext.getResources().getString(R.string.touch));
3679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
368e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mTextHint.setAlpha(0.0f);
369e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mTextHint.setVisibility(View.VISIBLE);
370e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mHintAnimator.start();
371be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
37269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // Lock the orientation.
37369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // The orientation from the configuration does not specify whether
37469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // the orientation is reverse or not (ie landscape or reverse landscape).
37569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // So we have to use SENSOR_LANDSCAPE or SENSOR_PORTRAIT to make sure
37669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // we lock in portrait / landscape and have the sensor determine
37769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // which way is up.
37865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        int orientation = mContext.getResources().getConfiguration().orientation;
37969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
38069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        switch (orientation) {
38169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            case Configuration.ORIENTATION_LANDSCAPE:
38269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
38369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
38469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
38569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            case Configuration.ORIENTATION_PORTRAIT:
38669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
38769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
38869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
38969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            default:
39069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
39169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
39269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
39369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        }
39469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
3959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mWindowManager.addView(mDecor, mWindowLayoutParams);
3960c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // Disable statusbar pull-down
3970c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
3980c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
399a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = null;
400f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
401f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (!mHardwareAccelerated) {
402f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mPreAnimator.start();
403f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } // else, we will start the animation once we get the hardware surface
4049340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mState = promptToNfcTap ? STATE_W4_NFC_TAP : STATE_W4_TOUCH;
40569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    }
4065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
40769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Show starting send animation */
40869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    public void showStartSend() {
40957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        if (mState < STATE_SENDING) return;
410217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
4111a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.GONE);
412f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Update the starting scale - touchscreen-mashers may trigger
413f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // this before the pre-animation completes.
41490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        float currentScale = mScreenshotView.getScaleX();
41565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX",
41665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {currentScale, 0.0f});
41765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY",
41865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {currentScale, 0.0f});
419217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
420f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSlowSendAnimator.setValues(postX, postY);
4211a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
4221a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        float currentAlpha = mBlackLayer.getAlpha();
4231a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mBlackLayer.isShown() && currentAlpha > 0.0f) {
42465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha",
42565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 0.0f});
4261a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mAlphaDownAnimator.setValues(alphaDown);
4271a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mAlphaDownAnimator.start();
4281a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
429f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSlowSendAnimator.start();
43069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    }
43169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
432a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    public void finishAndToast(int finishMode, String toast) {
433a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = toast;
434a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
435a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        finish(finishMode);
436a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    }
437a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
43869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Return to initial state */
4390c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen    public void finish(int finishMode) {
440595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        switch (mState) {
441595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_IDLE:
442595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
443595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT:
444595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_REQUESTED:
4459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED:
446595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Screenshot is still being captured on a separate thread.
447595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Update state, and stop everything when the capture is done.
448595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_W4_SCREENSHOT_THEN_STOP;
449595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
450595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_THEN_STOP:
451595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected call to finish() in STATE_W4_SCREENSHOT_THEN_STOP");
452595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
453595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_PRESEND:
454595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We didn't build up any animation state yet, but
455595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // did store the bitmap. Clear out the bitmap, reset
456595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // state and bail.
457595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mScreenshotBitmap = null;
458595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_IDLE;
459595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
460595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            default:
461595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We've started animations and attached a view; tear stuff down below.
462595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                break;
463595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        }
464f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
465f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Stop rendering the fireflies
466f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (mFireflyRenderer != null) {
467f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFireflyRenderer.stop();
46869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        }
469f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
470be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mTextHint.setVisibility(View.GONE);
4711a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.GONE);
472f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
473f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        float currentScale = mScreenshotView.getScaleX();
474f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        float currentAlpha = mScreenshotView.getAlpha();
475f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
476f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (finishMode == FINISH_SCALE_UP) {
4771a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mBlackLayer.setVisibility(View.GONE);
478674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX",
47965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 1.0f});
480674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY",
48165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 1.0f});
482674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpAlpha = PropertyValuesHolder.ofFloat("alpha",
48365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 1.0f});
484f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mScaleUpAnimator.setValues(scaleUpX, scaleUpY, scaleUpAlpha);
485f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
4860c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen            mScaleUpAnimator.start();
487f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (finishMode == FINISH_SEND_SUCCESS){
488f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Modify the fast send parameters to match the current scale
489f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX",
49065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 0.0f});
491f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY",
49265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 0.0f});
493f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha",
49465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 0.0f});
495f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFastSendAnimator.setValues(postX, postY, alpha);
496f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
497f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Reset the fadeIn parameters to start from alpha 1
498f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha",
49965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {0.0f, 1.0f});
500f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFadeInAnimator.setValues(fadeIn);
501f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
502f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSlowSendAnimator.cancel();
503f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSuccessAnimatorSet.start();
5040c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        }
50557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_COMPLETE;
5065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5075438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
508595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    void dismiss() {
5099340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState < STATE_W4_TOUCH) return;
51057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // Immediately set to IDLE, to prevent .cancel() calls
5114e0ab3174beafb4915388d8c11286a48e362ed7cMartijn Coenen        // below from immediately calling into dismiss() again.
51257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // (They can do so on the same thread).
51357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_IDLE;
514f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSurface = null;
515f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.cancel();
5165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.cancel();
517217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator.cancel();
518f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.cancel();
51969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mSuccessAnimatorSet.cancel();
52069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.cancel();
5211a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.cancel();
5221a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.cancel();
5239340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mWindowManager.removeView(mDecor);
5240c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
52557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mScreenshotBitmap = null;
526a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        if (mToastString != null) {
52765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            Toast.makeText(mContext, mToastString, Toast.LENGTH_LONG).show();
528a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        }
529a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = null;
5305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
5325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    /**
5335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     * @return the current display rotation in degrees
5345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     */
5355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    static float getDegreesForRotation(int value) {
5365438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        switch (value) {
5375438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_90:
5385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 90f;
5395438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_180:
5405438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 180f;
5415438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_270:
5425438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 270f;
5435438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
5445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        return 0f;
5455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
54757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    final class ScreenshotTask extends AsyncTask<Void, Void, Bitmap> {
54857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        @Override
54957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        protected Bitmap doInBackground(Void... params) {
55057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            return createScreenshot();
55157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
55257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
55357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        @Override
55457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        protected void onPostExecute(Bitmap result) {
555595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            if (mState == STATE_W4_SCREENSHOT) {
556595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Screenshot done, wait for request to start preSend anim
557595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_W4_PRESEND;
558595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            } else if (mState == STATE_W4_SCREENSHOT_THEN_STOP) {
559595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We were asked to finish, move to idle state and exit
560595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_IDLE;
5619340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else if (mState == STATE_W4_SCREENSHOT_PRESEND_REQUESTED ||
5629340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED) {
563595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                if (result != null) {
564595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mScreenshotBitmap = result;
5659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    boolean requestTap = (mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED);
566595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mState = STATE_W4_PRESEND;
5679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    showPreSend(requestTap);
568595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                } else {
569595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    // Failed to take screenshot; reset state to idle
570595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    // and don't do anything
571595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    Log.e(TAG, "Failed to create screenshot");
572595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mState = STATE_IDLE;
573595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                }
574595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            } else {
575595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Invalid state on screenshot completion: " + Integer.toString(mState));
57657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            }
57757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
57865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    };
57957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
5805438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    /**
5815438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     * Returns a screenshot of the current display contents.
5825438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     */
5835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    Bitmap createScreenshot() {
5845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // We need to orient the screenshot correctly (and the Surface api seems to
5855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // take screenshots only in the natural orientation of the device :!)
5865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplay.getRealMetrics(mDisplayMetrics);
58765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        boolean hasNavBar =  mContext.getResources().getBoolean(
588e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                com.android.internal.R.bool.config_showNavigationBar);
5890c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
5905443a8f5b786bfc03633ea5821d95dffc856e3e8Martijn Coenen        float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
5915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        float degrees = getDegreesForRotation(mDisplay.getRotation());
59265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int statusBarHeight = mContext.getResources().getDimensionPixelSize(
59390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen                                        com.android.internal.R.dimen.status_bar_height);
594e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen
59590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Navbar has different sizes, depending on orientation
59665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize(
597e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                                        com.android.internal.R.dimen.navigation_bar_height) : 0;
59865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize(
599525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                        com.android.internal.R.dimen.navigation_bar_height_landscape) : 0;
600525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
60165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize(
602e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                                        com.android.internal.R.dimen.navigation_bar_width) : 0;
60390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
6045438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        boolean requiresRotation = (degrees > 0);
6055438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (requiresRotation) {
6065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            // Get the dimensions of the device in its native orientation
6075438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.reset();
6085438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.preRotate(-degrees);
6095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.mapPoints(dims);
6105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dims[0] = Math.abs(dims[0]);
6115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dims[1] = Math.abs(dims[1]);
6125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
61482792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopian        Bitmap bitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
6155438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // Bail if we couldn't take the screenshot
6165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (bitmap == null) {
6175438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return null;
6185438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6205438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (requiresRotation) {
6215438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            // Rotate the screenshot to the current orientation
6225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
6235438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                    mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
6245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            Canvas c = new Canvas(ss);
6255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
6265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.rotate(360f - degrees);
6275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.translate(-dims[0] / 2, -dims[1] / 2);
6285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.drawBitmap(bitmap, 0, 0, null);
6295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            bitmap = ss;
6315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
63390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // TODO this is somewhat device-specific; need generic solution.
63490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Crop off the status bar and the nav bar
63590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Portrait: 0, statusBarHeight, width, height - status - nav
63690e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Landscape: 0, statusBarHeight, width - navBar, height - status
63790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newLeft = 0;
63890e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newTop = statusBarHeight;
63990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newWidth = bitmap.getWidth();
64090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newHeight = bitmap.getHeight();
641525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        float smallestWidth = (float)Math.min(newWidth, newHeight);
642525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f);
64390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        if (bitmap.getWidth() < bitmap.getHeight()) {
64490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen            // Portrait mode: status bar is at the top, navbar bottom, width unchanged
64590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen            newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight;
64690e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        } else {
647525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Landscape mode: status bar is at the top
648525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Navbar: bottom on >599dp width devices, otherwise to the side
649525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (smallestWidthDp > 599) {
650525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape;
651525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else {
652525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newHeight = bitmap.getHeight() - statusBarHeight;
653525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newWidth = bitmap.getWidth() - navBarWidth;
654525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
65590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        }
65690e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight);
65790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
6585438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        return bitmap;
6595438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
6605438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6615438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6625438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationStart(Animator animation) {  }
6635438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6645438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6655438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationEnd(Animator animation) {
6660c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        if (animation == mScaleUpAnimator || animation == mSuccessAnimatorSet ||
667f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            animation == mFadeInAnimator) {
668f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // These all indicate the end of the animation
6695438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dismiss();
670f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (animation == mFastSendAnimator) {
671f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // After sending is done and we've faded out, reset the scale to 1
6724dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            // so we can fade it back in.
6734dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            mScreenshotView.setScaleX(1.0f);
6744dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            mScreenshotView.setScaleY(1.0f);
675f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (animation == mPreAnimator) {
6769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mHardwareAccelerated && (mState == STATE_W4_TOUCH || mState == STATE_W4_NFC_TAP)) {
677f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen                mFireflyRenderer.start(mSurface, mSurfaceWidth, mSurfaceHeight);
678f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            }
6795438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6805438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
6815438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6825438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationCancel(Animator animation) {  }
6845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationRepeat(Animator animation) {  }
687b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly
688b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    @Override
689f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
690f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // This gets called on animation vsync
691f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (++mRenderedFrames < 4) {
692f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // For the first 3 frames, call invalidate(); this calls eglSwapBuffers
693f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // on the surface, which will allocate large buffers the first three calls
694f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // as Android uses triple buffering.
695f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mScreenshotLayout.invalidate();
696f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else {
697f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Buffers should be allocated, start the real animation
698f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFrameCounterAnimator.cancel();
699f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mPreAnimator.start();
700f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        }
701f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    }
702f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
703f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    @Override
704b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    public boolean onTouch(View v, MotionEvent event) {
7059340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState != STATE_W4_TOUCH) {
706b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly            return false;
707b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly        }
70857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_SENDING;
70969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // Ignore future touches
71069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScreenshotView.setOnTouchListener(null);
71169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
712f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Cancel any ongoing animations
713f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.cancel();
714f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mPreAnimator.cancel();
715f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
71665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mCallback.onSendConfirmed();
717b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly        return true;
718b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    }
719217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
720217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
721217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
72257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        if (mHardwareAccelerated && mState < STATE_COMPLETE) {
723f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mRenderedFrames = 0;
724f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
725f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFrameCounterAnimator.start();
726f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurface = surface;
727f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurfaceWidth = width;
728f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurfaceHeight = height;
729217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        }
730217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
731217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
732217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
733217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
734217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        // Since we've disabled orientation changes, we can safely ignore this
735217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
736217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
737217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
738217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
739f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSurface = null;
740f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
741217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        return true;
742217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
743217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
744217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
745f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
746f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
7471a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    public void showSendHint() {
7481a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mAlphaDownAnimator.isRunning()) {
7491a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen           mAlphaDownAnimator.cancel();
7501a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
7511a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mSlowSendAnimator.isRunning()) {
7521a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mSlowSendAnimator.cancel();
7531a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
7541a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setScaleX(mScreenshotView.getScaleX());
7551a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setScaleY(mScreenshotView.getScaleY());
7561a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setVisibility(View.VISIBLE);
7571a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextHint.setVisibility(View.GONE);
7581a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
75965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mTextRetry.setText(mContext.getResources().getString(R.string.beam_try_again));
7601a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.VISIBLE);
7611a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
7621a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha",
76365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {mBlackLayer.getAlpha(), 0.9f});
7641a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setValues(alphaUp);
7651a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.start();
7661a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    }
7679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchKeyEvent(KeyEvent event) {
77027382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        int keyCode = event.getKeyCode();
77127382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        if (keyCode == KeyEvent.KEYCODE_BACK) {
77265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mCallback.onCanceled();
77327382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return true;
77427382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
77527382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen                keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
77627382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            // Treat as if it's a touch event
77727382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return onTouch(mScreenshotView, null);
77827382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        } else {
77927382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return false;
78027382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        }
7819340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7829340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7839340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
7859340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
7869340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7879340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7889340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7899340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchTouchEvent(MotionEvent event) {
7909340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return mScreenshotLayout.dispatchTouchEvent(event);
7919340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7929340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7939340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7949340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchTrackballEvent(MotionEvent event) {
7959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
7969340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7979340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7999340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchGenericMotionEvent(MotionEvent event) {
8009340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8019340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8029340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8039340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8049340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
8059340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8069340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8079340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8089340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8099340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public View onCreatePanelView(int featureId) {
8109340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return null;
8119340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8129340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8139340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8149340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onCreatePanelMenu(int featureId, Menu menu) {
8159340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8169340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8179340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8189340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8199340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onPreparePanel(int featureId, View view, Menu menu) {
8209340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8219340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8229340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8239340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8249340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onMenuOpened(int featureId, Menu menu) {
8259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8269340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8279340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8289340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8299340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onMenuItemSelected(int featureId, MenuItem item) {
8309340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8319340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8329340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8339340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onWindowAttributesChanged(LayoutParams attrs) {
8359340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8369340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8379340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8389340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onContentChanged() {
8399340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8419340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8429340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onWindowFocusChanged(boolean hasFocus) {
8439340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8449340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8469340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onAttachedToWindow() {
8479340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8489340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8499340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8509340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8519340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onDetachedFromWindow() {
8529340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8539340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8549340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onPanelClosed(int featureId, Menu menu) {
8569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8599340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8609340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onSearchRequested() {
8619340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8629340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8639340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8649340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public ActionMode onWindowStartingActionMode(
8669340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            android.view.ActionMode.Callback callback) {
8679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return null;
8689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onActionModeStarted(ActionMode mode) {
8729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8759340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onActionModeFinished(ActionMode mode) {
8769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8775438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly}
878