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
17b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralespackage com.android.nfc.beam;
185438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
19b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.R;
20b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.beam.FireflyRenderer;
2165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales
225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.Animator;
2369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.animation.AnimatorSet;
245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.ObjectAnimator;
255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.PropertyValuesHolder;
26f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenenimport android.animation.TimeAnimator;
270c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.ActivityManager;
280c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.StatusBarManager;
295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.content.Context;
3069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.pm.ActivityInfo;
3169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.res.Configuration;
325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Bitmap;
335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Canvas;
345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Matrix;
355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.PixelFormat;
36217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.graphics.SurfaceTexture;
3757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenenimport android.os.AsyncTask;
385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.os.Binder;
395438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.util.DisplayMetrics;
40595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenenimport android.util.Log;
419340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.ActionMode;
425438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Display;
439340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.KeyEvent;
445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.LayoutInflater;
459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.Menu;
469340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.MenuItem;
47b2112cff553c3b6658440bf06060c7a08f82df5cNick Pellyimport android.view.MotionEvent;
48c88594c35808ab286ce68d09d6725e44be3bbc96Adam Powellimport com.android.internal.policy.PhoneWindow;
4986bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbournimport android.view.SearchEvent;
505438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Surface;
5182792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopianimport android.view.SurfaceControl;
52217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.view.TextureView;
535438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.View;
545438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.ViewGroup;
559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.Window;
565438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.WindowManager;
579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.WindowManager.LayoutParams;
589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.view.accessibility.AccessibilityEvent;
590c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.view.animation.AccelerateDecelerateInterpolator;
6069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.view.animation.DecelerateInterpolator;
615438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.widget.ImageView;
62be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenenimport android.widget.TextView;
63a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenenimport android.widget.Toast;
645438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
655438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly/**
66f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * This class is responsible for handling the UI animation
67f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * around Android Beam. The animation consists of the following
68f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * animators:
69f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
70f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator: scales the screenshot down to INTERMEDIATE_SCALE
71f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mSlowSendAnimator: scales the screenshot down to 0.2f (used as a "send in progress" animation)
72f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFastSendAnimator: quickly scales the screenshot down to 0.0f (used for send success)
73f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFadeInAnimator: fades the current activity back in (used after mFastSendAnimator completes)
74f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mScaleUpAnimator: scales the screenshot back up to full screen (used for failure or receiving)
75f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mHintAnimator: Slowly turns up the alpha of the "Touch to Beam" hint
76f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
77f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Possible sequences are:
78f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
79f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mFastSendAnimator => mFadeInAnimator (send success)
80f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mScaleUpAnimator (send failure)
81f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mScaleUpAnimator (p2p link broken, or data received)
82f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
83f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Note that mFastSendAnimator and mFadeInAnimator are combined in a set, as they
84f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * are an atomic animation that cannot be interrupted.
85f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen *
86f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * All methods of this class must be called on the UI thread
875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */
8865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Moralespublic class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
8965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        TimeAnimator.TimeListener, TextureView.SurfaceTextureListener, android.view.Window.Callback {
9065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    static final String TAG = "SendUi";
91595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen
9269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float INTERMEDIATE_SCALE = 0.6f;
935438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
9469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float[] PRE_SCREENSHOT_SCALE = {1.0f, INTERMEDIATE_SCALE};
95674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int PRE_DURATION_MS = 350;
9669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
97f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    static final float[] SEND_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 0.2f};
98674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int SLOW_SEND_DURATION_MS = 8000; // Stretch out sending over 8s
99f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    static final int FAST_SEND_DURATION_MS = 350;
10069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
10169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final float[] SCALE_UP_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 1.0f};
10269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    static final int SCALE_UP_DURATION_MS = 300;
1035438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
104674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int FADE_IN_DURATION_MS = 250;
105674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int FADE_IN_START_DELAY_MS = 350;
106674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely
1070c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen    static final int SLIDE_OUT_DURATION_MS = 300;
1080c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
1091a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final float[] BLACK_LAYER_ALPHA_DOWN_RANGE = {0.9f, 0.0f};
1101a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    static final float[] BLACK_LAYER_ALPHA_UP_RANGE = {0.0f, 0.9f};
1111a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
112be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen    static final float[] TEXT_HINT_ALPHA_RANGE = {0.0f, 1.0f};
113be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen    static final int TEXT_HINT_ALPHA_DURATION_MS = 500;
114674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely    static final int TEXT_HINT_ALPHA_START_DELAY_MS = 300;
115be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
116b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public static final int FINISH_SCALE_UP = 0;
117b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public static final int FINISH_SEND_SUCCESS = 1;
1180c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
11957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int STATE_IDLE = 0;
120595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    static final int STATE_W4_SCREENSHOT = 1;
121595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    static final int STATE_W4_SCREENSHOT_PRESEND_REQUESTED = 2;
1229340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED = 3;
1239340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_SCREENSHOT_THEN_STOP = 4;
1249340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_PRESEND = 5;
1259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_TOUCH = 6;
1269340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_W4_NFC_TAP = 7;
1279340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_SENDING = 8;
1289340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    static final int STATE_COMPLETE = 9;
12957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
1305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    // all members are only used on UI thread
13165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final WindowManager mWindowManager;
13265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Context mContext;
13365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Display mDisplay;
13465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final DisplayMetrics mDisplayMetrics;
13565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Matrix mDisplayMatrix;
13665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final WindowManager.LayoutParams mWindowLayoutParams;
13765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final LayoutInflater mLayoutInflater;
13865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final StatusBarManager mStatusBarManager;
13965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final View mScreenshotLayout;
14065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ImageView mScreenshotView;
14165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ImageView mBlackLayer;
14265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextureView mTextureView;
14365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextView mTextHint;
14465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TextView mTextRetry;
14565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final Callback mCallback;
146f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
147f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // The mFrameCounter animation is purely used to count down a certain
148f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // number of (vsync'd) frames. This is needed because the first 3
149f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // times the animation internally calls eglSwapBuffers(), large buffers
150f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // are allocated by the graphics drivers. This causes the animation
151f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // to look janky. So on platforms where we can use hardware acceleration,
152f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // the animation order is:
153f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Wait for hw surface => start frame counter => start pre-animation after 3 frames
154f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // For platforms where no hw acceleration can be used, the pre-animation
155f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // is started immediately.
15665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final TimeAnimator mFrameCounterAnimator;
15765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales
15865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mPreAnimator;
15965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mSlowSendAnimator;
16065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mFastSendAnimator;
16165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mFadeInAnimator;
16265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mHintAnimator;
16365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mScaleUpAnimator;
16465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mAlphaDownAnimator;
16565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final ObjectAnimator mAlphaUpAnimator;
16665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final AnimatorSet mSuccessAnimatorSet;
167f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
168f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Besides animating the screenshot, the Beam UI also renders
169f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // fireflies on platforms where we can do hardware-acceleration.
170f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Firefly rendering is only started once the initial
171f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // "pre-animation" has scaled down the screenshot, to avoid
172f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // that animation becoming janky. Likewise, the fireflies are
173f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // stopped in their tracks as soon as we finish the animation,
174f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // to make the finishing animation smooth.
17565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final boolean mHardwareAccelerated;
17665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    final FireflyRenderer mFireflyRenderer;
1775438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
178a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    String mToastString;
1795438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    Bitmap mScreenshotBitmap;
1800c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
18157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    int mState;
182f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mRenderedFrames;
183f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
1849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    View mDecor;
1859340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
186f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    // Used for holding the surface
187f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    SurfaceTexture mSurface;
188f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mSurfaceWidth;
189f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    int mSurfaceHeight;
1905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
191b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public interface Callback {
19265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        public void onSendConfirmed();
19365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        public void onCanceled();
1945438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
1955438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
19665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    public SendUi(Context context, Callback callback) {
19765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mContext = context;
19865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mCallback = callback;
1995438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
2005438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplayMetrics = new DisplayMetrics();
2015438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplayMatrix = new Matrix();
20265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
20365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mStatusBarManager = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
2040c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
2055438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplay = mWindowManager.getDefaultDisplay();
2065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
20765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mLayoutInflater = (LayoutInflater)
20865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotLayout = mLayoutInflater.inflate(R.layout.screenshot, null);
210f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
2115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.screenshot);
2125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotLayout.setFocusable(true);
2135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
214be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mTextHint = (TextView) mScreenshotLayout.findViewById(R.id.calltoaction);
2151a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry = (TextView) mScreenshotLayout.findViewById(R.id.retrytext);
2161a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer = (ImageView) mScreenshotLayout.findViewById(R.id.blacklayer);
217217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mTextureView = (TextureView) mScreenshotLayout.findViewById(R.id.fireflies);
218217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mTextureView.setSurfaceTextureListener(this);
219217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
2200c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // We're only allowed to use hardware acceleration if
2210c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // isHighEndGfx() returns true - otherwise, we're too limited
2220c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // on resources to do it.
223525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mHardwareAccelerated = ActivityManager.isHighEndGfx();
2240c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        int hwAccelerationFlags = mHardwareAccelerated ?
225f7966d1dadff2d78f01bbdb134e8252b53343179Dianne Hackborn                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0;
2260c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
2275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mWindowLayoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
2280c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen                ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
2290c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
2305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                WindowManager.LayoutParams.FLAG_FULLSCREEN
23165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                | hwAccelerationFlags
23265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
2335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                PixelFormat.OPAQUE);
234525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mWindowLayoutParams.privateFlags |=
235525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2365438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mWindowLayoutParams.token = new Binder();
2375438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
238f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator = new TimeAnimator();
239f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.setTimeListener(this);
240f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
2415438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        PropertyValuesHolder preX = PropertyValuesHolder.ofFloat("scaleX", PRE_SCREENSHOT_SCALE);
2425438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        PropertyValuesHolder preY = PropertyValuesHolder.ofFloat("scaleY", PRE_SCREENSHOT_SCALE);
2435438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, preX, preY);
24469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mPreAnimator.setInterpolator(new DecelerateInterpolator());
2455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.setDuration(PRE_DURATION_MS);
2465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.addListener(this);
2475438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
248f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", SEND_SCREENSHOT_SCALE);
249f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", SEND_SCREENSHOT_SCALE);
25065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha",
25165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[]{1.0f, 0.0f});
2524dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen
253217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, postY);
254674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mSlowSendAnimator.setInterpolator(new DecelerateInterpolator());
255217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator.setDuration(SLOW_SEND_DURATION_MS);
25669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
257f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX,
2584dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen                postY, alphaDown);
259f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.setInterpolator(new DecelerateInterpolator());
260f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.setDuration(FAST_SEND_DURATION_MS);
261f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.addListener(this);
26269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
26365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", SCALE_UP_SCREENSHOT_SCALE);
26465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", SCALE_UP_SCREENSHOT_SCALE);
2654dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen
26665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mScaleUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, scaleUpX, scaleUpY);
267674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mScaleUpAnimator.setInterpolator(new DecelerateInterpolator());
26869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.setDuration(SCALE_UP_DURATION_MS);
26969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.addListener(this);
27069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
271674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", 1.0f);
272674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, fadeIn);
273674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
274674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setDuration(FADE_IN_DURATION_MS);
275674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.setStartDelay(FADE_IN_START_DELAY_MS);
276674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mFadeInAnimator.addListener(this);
277674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely
278be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", TEXT_HINT_ALPHA_RANGE);
279be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextHint, alphaUp);
280be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator.setInterpolator(null);
281be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mHintAnimator.setDuration(TEXT_HINT_ALPHA_DURATION_MS);
282674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely        mHintAnimator.setStartDelay(TEXT_HINT_ALPHA_START_DELAY_MS);
283be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
2841a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        alphaDown = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_DOWN_RANGE);
2851a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaDown);
2861a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.setInterpolator(new DecelerateInterpolator());
2871a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.setDuration(400);
2881a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
2891a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        alphaUp = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_UP_RANGE);
2901a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaUp);
2911a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setInterpolator(new DecelerateInterpolator());
2921a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setDuration(200);
2931a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
29469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mSuccessAnimatorSet = new AnimatorSet();
295f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSuccessAnimatorSet.playSequentially(mFastSendAnimator, mFadeInAnimator);
2965438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
2979340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        // Create a Window with a Decor view; creating a window allows us to get callbacks
2989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        // on key events (which require a decor view to be dispatched).
29965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mContext.setTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen);
300f42c2eba6ba6e6dae07ea617ab1be7f6f18f220dJorim Jaggi        Window window = new PhoneWindow(mContext);
3019340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.setCallback(this);
3029340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.requestFeature(Window.FEATURE_NO_TITLE);
3039340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mDecor = window.getDecorView();
3049340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        window.setContentView(mScreenshotLayout, mWindowLayoutParams);
3059340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
306f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (mHardwareAccelerated) {
30765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mFireflyRenderer = new FireflyRenderer(context);
308f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else {
309f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFireflyRenderer = null;
310f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        }
31157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_IDLE;
3125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
3135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
3145438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void takeScreenshot() {
31557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // There's no point in taking the screenshot if
31657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // we're still finishing the previous animation.
3179340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState >= STATE_W4_TOUCH) {
31857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            return;
31957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
320595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        mState = STATE_W4_SCREENSHOT;
32157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        new ScreenshotTask().execute();
3225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
3235438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
32469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Show pre-send animation */
3259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void showPreSend(boolean promptToNfcTap) {
326595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        switch (mState) {
327595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_IDLE:
328595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in STATE_IDLE");
329595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
330595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT:
331595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Still waiting for screenshot, store request in state
332595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // and wait for screenshot completion.
3339340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                if (promptToNfcTap) {
3349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState = STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED;
3359340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                } else {
3369340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState = STATE_W4_SCREENSHOT_PRESEND_REQUESTED;
3379340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
338595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
339595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_REQUESTED:
3409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED:
341595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in STATE_W4_SCREENSHOT_PRESEND_REQUESTED");
342595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
343595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_PRESEND:
344595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Expected path, continue below
345595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                break;
346595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            default:
347595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected showPreSend() in state " + Integer.toString(mState));
348595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
34957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
35090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Update display metrics
35190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mDisplay.getRealMetrics(mDisplayMetrics);
35290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
35365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int statusBarHeight = mContext.getResources().getDimensionPixelSize(
35490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen                                        com.android.internal.R.dimen.status_bar_height);
35590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
3561a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setVisibility(View.GONE);
3571a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setAlpha(0f);
358595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        mScreenshotLayout.setOnTouchListener(this);
3595438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mScreenshotView.setImageBitmap(mScreenshotBitmap);
3600c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mScreenshotView.setTranslationX(0f);
3610c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mScreenshotView.setAlpha(1.0f);
36290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mScreenshotView.setPadding(0, statusBarHeight, 0, 0);
36369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
36490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        mScreenshotLayout.requestFocus();
36569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
3669340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (promptToNfcTap) {
36765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mTextHint.setText(mContext.getResources().getString(R.string.ask_nfc_tap));
3689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        } else {
36965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mTextHint.setText(mContext.getResources().getString(R.string.touch));
3709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
371e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mTextHint.setAlpha(0.0f);
372e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mTextHint.setVisibility(View.VISIBLE);
373e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly        mHintAnimator.start();
374be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen
37569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // Lock the orientation.
37669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // The orientation from the configuration does not specify whether
37769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // the orientation is reverse or not (ie landscape or reverse landscape).
37869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // So we have to use SENSOR_LANDSCAPE or SENSOR_PORTRAIT to make sure
37969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // we lock in portrait / landscape and have the sensor determine
38069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // which way is up.
38165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        int orientation = mContext.getResources().getConfiguration().orientation;
38269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
38369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        switch (orientation) {
38469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            case Configuration.ORIENTATION_LANDSCAPE:
38569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
38669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
38769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
38869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            case Configuration.ORIENTATION_PORTRAIT:
38969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
39069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
39169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
39269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen            default:
39369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                mWindowLayoutParams.screenOrientation =
39469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                        ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
39569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen                break;
39669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        }
39769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
3989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mWindowManager.addView(mDecor, mWindowLayoutParams);
3990c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        // Disable statusbar pull-down
4000c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
4010c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
402a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = null;
403f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
404f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (!mHardwareAccelerated) {
405f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mPreAnimator.start();
406f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } // else, we will start the animation once we get the hardware surface
4079340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mState = promptToNfcTap ? STATE_W4_NFC_TAP : STATE_W4_TOUCH;
40869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    }
4095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
41069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Show starting send animation */
41169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    public void showStartSend() {
41257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        if (mState < STATE_SENDING) return;
413217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
4141a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.GONE);
415f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Update the starting scale - touchscreen-mashers may trigger
416f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // this before the pre-animation completes.
41790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        float currentScale = mScreenshotView.getScaleX();
41865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX",
41965ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {currentScale, 0.0f});
42065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY",
42165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {currentScale, 0.0f});
422217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
423f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSlowSendAnimator.setValues(postX, postY);
4241a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
4251a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        float currentAlpha = mBlackLayer.getAlpha();
4261a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mBlackLayer.isShown() && currentAlpha > 0.0f) {
42765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha",
42865ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 0.0f});
4291a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mAlphaDownAnimator.setValues(alphaDown);
4301a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mAlphaDownAnimator.start();
4311a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
432f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSlowSendAnimator.start();
43369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    }
43469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
435a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    public void finishAndToast(int finishMode, String toast) {
436a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = toast;
437a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
438a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        finish(finishMode);
439a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen    }
440a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen
44169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen    /** Return to initial state */
4420c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen    public void finish(int finishMode) {
443595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        switch (mState) {
444595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_IDLE:
445595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
446595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT:
447595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_REQUESTED:
4489340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED:
449595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Screenshot is still being captured on a separate thread.
450595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Update state, and stop everything when the capture is done.
451595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_W4_SCREENSHOT_THEN_STOP;
452595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
453595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_SCREENSHOT_THEN_STOP:
454595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Unexpected call to finish() in STATE_W4_SCREENSHOT_THEN_STOP");
455595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
456595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            case STATE_W4_PRESEND:
457595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We didn't build up any animation state yet, but
458595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // did store the bitmap. Clear out the bitmap, reset
459595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // state and bail.
460595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mScreenshotBitmap = null;
461595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_IDLE;
462595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                return;
463595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            default:
464595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We've started animations and attached a view; tear stuff down below.
465595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                break;
466595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen        }
467f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
468f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Stop rendering the fireflies
469f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (mFireflyRenderer != null) {
470f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFireflyRenderer.stop();
47169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        }
472f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
473be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen        mTextHint.setVisibility(View.GONE);
4741a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.GONE);
475f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
476f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        float currentScale = mScreenshotView.getScaleX();
477f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        float currentAlpha = mScreenshotView.getAlpha();
478f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
479f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (finishMode == FINISH_SCALE_UP) {
4801a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mBlackLayer.setVisibility(View.GONE);
481674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX",
48265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 1.0f});
483674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY",
48465ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 1.0f});
485674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely            PropertyValuesHolder scaleUpAlpha = PropertyValuesHolder.ofFloat("alpha",
48665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 1.0f});
487f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mScaleUpAnimator.setValues(scaleUpX, scaleUpY, scaleUpAlpha);
488f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
4890c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen            mScaleUpAnimator.start();
490f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (finishMode == FINISH_SEND_SUCCESS){
491f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Modify the fast send parameters to match the current scale
492f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX",
49365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 0.0f});
494f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY",
49565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentScale, 0.0f});
496f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha",
49765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {currentAlpha, 0.0f});
498f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFastSendAnimator.setValues(postX, postY, alpha);
499f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
500f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Reset the fadeIn parameters to start from alpha 1
501f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha",
50265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                    new float[] {0.0f, 1.0f});
503f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFadeInAnimator.setValues(fadeIn);
504f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
505f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSlowSendAnimator.cancel();
506f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSuccessAnimatorSet.start();
5070c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        }
50857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_COMPLETE;
5095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
511595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen    void dismiss() {
5129340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState < STATE_W4_TOUCH) return;
51357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // Immediately set to IDLE, to prevent .cancel() calls
5144e0ab3174beafb4915388d8c11286a48e362ed7cMartijn Coenen        // below from immediately calling into dismiss() again.
51557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        // (They can do so on the same thread).
51657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_IDLE;
517f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSurface = null;
518f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.cancel();
5195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mPreAnimator.cancel();
520217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        mSlowSendAnimator.cancel();
521f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFastSendAnimator.cancel();
52269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mSuccessAnimatorSet.cancel();
52369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScaleUpAnimator.cancel();
5241a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.cancel();
5251a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaDownAnimator.cancel();
5269340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        mWindowManager.removeView(mDecor);
5270c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
52857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mScreenshotBitmap = null;
529a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        if (mToastString != null) {
53065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            Toast.makeText(mContext, mToastString, Toast.LENGTH_LONG).show();
531a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        }
532a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen        mToastString = null;
5335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
5355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    /**
5365438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     * @return the current display rotation in degrees
5375438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     */
5385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    static float getDegreesForRotation(int value) {
5395438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        switch (value) {
5405438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_90:
5415438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 90f;
5425438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_180:
5435438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 180f;
5445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        case Surface.ROTATION_270:
5455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return 270f;
5465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
5475438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        return 0f;
5485438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
5495438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
55057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    final class ScreenshotTask extends AsyncTask<Void, Void, Bitmap> {
55157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        @Override
55257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        protected Bitmap doInBackground(Void... params) {
55357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            return createScreenshot();
55457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
55557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
55657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        @Override
55757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        protected void onPostExecute(Bitmap result) {
558595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            if (mState == STATE_W4_SCREENSHOT) {
559595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // Screenshot done, wait for request to start preSend anim
560ddefd2afcd6b09c3a48db4b2f69377dbc3a8a282Martijn Coenen                mScreenshotBitmap = result;
561595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_W4_PRESEND;
562595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            } else if (mState == STATE_W4_SCREENSHOT_THEN_STOP) {
563595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                // We were asked to finish, move to idle state and exit
564595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                mState = STATE_IDLE;
5659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else if (mState == STATE_W4_SCREENSHOT_PRESEND_REQUESTED ||
5669340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED) {
567595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                if (result != null) {
568595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mScreenshotBitmap = result;
5699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    boolean requestTap = (mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED);
570595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mState = STATE_W4_PRESEND;
5719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    showPreSend(requestTap);
572595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                } else {
573595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    // Failed to take screenshot; reset state to idle
574595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    // and don't do anything
575595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    Log.e(TAG, "Failed to create screenshot");
576595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                    mState = STATE_IDLE;
577595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                }
578595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen            } else {
579595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen                Log.e(TAG, "Invalid state on screenshot completion: " + Integer.toString(mState));
58057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen            }
58157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        }
58265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales    };
58357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
5845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    /**
5855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     * Returns a screenshot of the current display contents.
5865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly     */
5875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    Bitmap createScreenshot() {
5885438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // We need to orient the screenshot correctly (and the Surface api seems to
5895438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // take screenshots only in the natural orientation of the device :!)
5905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        mDisplay.getRealMetrics(mDisplayMetrics);
59165ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        boolean hasNavBar =  mContext.getResources().getBoolean(
592e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                com.android.internal.R.bool.config_showNavigationBar);
5930c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen
5945443a8f5b786bfc03633ea5821d95dffc856e3e8Martijn Coenen        float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
5955438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        float degrees = getDegreesForRotation(mDisplay.getRotation());
59665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int statusBarHeight = mContext.getResources().getDimensionPixelSize(
59790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen                                        com.android.internal.R.dimen.status_bar_height);
598e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen
59990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Navbar has different sizes, depending on orientation
60065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize(
601e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                                        com.android.internal.R.dimen.navigation_bar_height) : 0;
60265ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize(
603525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                        com.android.internal.R.dimen.navigation_bar_height_landscape) : 0;
604525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
60565ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize(
606e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen                                        com.android.internal.R.dimen.navigation_bar_width) : 0;
60790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
6085438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        boolean requiresRotation = (degrees > 0);
6095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (requiresRotation) {
6105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            // Get the dimensions of the device in its native orientation
6115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.reset();
6125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.preRotate(-degrees);
6135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            mDisplayMatrix.mapPoints(dims);
6145438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dims[0] = Math.abs(dims[0]);
6155438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dims[1] = Math.abs(dims[1]);
6165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6175438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
61882792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopian        Bitmap bitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
6195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        // Bail if we couldn't take the screenshot
6205438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (bitmap == null) {
6215438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            return null;
6225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6235438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        if (requiresRotation) {
6255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            // Rotate the screenshot to the current orientation
6265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
6275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly                    mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
6285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            Canvas c = new Canvas(ss);
6295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
6305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.rotate(360f - degrees);
6315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.translate(-dims[0] / 2, -dims[1] / 2);
6325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            c.drawBitmap(bitmap, 0, 0, null);
6335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6345438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            bitmap = ss;
6355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6365438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
63790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // TODO this is somewhat device-specific; need generic solution.
63890e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Crop off the status bar and the nav bar
63990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Portrait: 0, statusBarHeight, width, height - status - nav
64090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        // Landscape: 0, statusBarHeight, width - navBar, height - status
64190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newLeft = 0;
64290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newTop = statusBarHeight;
64390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newWidth = bitmap.getWidth();
64490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        int newHeight = bitmap.getHeight();
645525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        float smallestWidth = (float)Math.min(newWidth, newHeight);
646525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f);
64790e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        if (bitmap.getWidth() < bitmap.getHeight()) {
64890e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen            // Portrait mode: status bar is at the top, navbar bottom, width unchanged
64990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen            newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight;
65090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        } else {
651525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Landscape mode: status bar is at the top
652525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Navbar: bottom on >599dp width devices, otherwise to the side
653525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (smallestWidthDp > 599) {
654525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape;
655525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else {
656525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newHeight = bitmap.getHeight() - statusBarHeight;
657525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                newWidth = bitmap.getWidth() - navBarWidth;
658525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
65990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        }
66090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen        bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight);
66190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen
6625438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        return bitmap;
6635438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
6645438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6655438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6665438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationStart(Animator animation) {  }
6675438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6685438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6695438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationEnd(Animator animation) {
6700c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen        if (animation == mScaleUpAnimator || animation == mSuccessAnimatorSet ||
671f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            animation == mFadeInAnimator) {
672f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // These all indicate the end of the animation
6735438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly            dismiss();
674f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (animation == mFastSendAnimator) {
675f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // After sending is done and we've faded out, reset the scale to 1
6764dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            // so we can fade it back in.
6774dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            mScreenshotView.setScaleX(1.0f);
6784dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen            mScreenshotView.setScaleY(1.0f);
679f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else if (animation == mPreAnimator) {
6809340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            if (mHardwareAccelerated && (mState == STATE_W4_TOUCH || mState == STATE_W4_NFC_TAP)) {
681f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen                mFireflyRenderer.start(mSurface, mSurfaceWidth, mSurfaceHeight);
682f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            }
6835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly        }
6845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    }
6855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationCancel(Animator animation) {  }
6885438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly
6895438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    @Override
6905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly    public void onAnimationRepeat(Animator animation) {  }
691b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly
692b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    @Override
693f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
694f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // This gets called on animation vsync
695f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        if (++mRenderedFrames < 4) {
696f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // For the first 3 frames, call invalidate(); this calls eglSwapBuffers
697f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // on the surface, which will allocate large buffers the first three calls
698f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // as Android uses triple buffering.
699f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mScreenshotLayout.invalidate();
700f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        } else {
701f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            // Buffers should be allocated, start the real animation
702f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFrameCounterAnimator.cancel();
703f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mPreAnimator.start();
704f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        }
705f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    }
706f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
707f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    @Override
708b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    public boolean onTouch(View v, MotionEvent event) {
7099340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        if (mState != STATE_W4_TOUCH) {
710b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly            return false;
711b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly        }
71257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        mState = STATE_SENDING;
71369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        // Ignore future touches
71469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen        mScreenshotView.setOnTouchListener(null);
71569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen
716f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        // Cancel any ongoing animations
717f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mFrameCounterAnimator.cancel();
718f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mPreAnimator.cancel();
719f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
72065ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mCallback.onSendConfirmed();
721b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly        return true;
722b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly    }
723217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
724217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
725217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
72657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        if (mHardwareAccelerated && mState < STATE_COMPLETE) {
727f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mRenderedFrames = 0;
728f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
729f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mFrameCounterAnimator.start();
730f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurface = surface;
731f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurfaceWidth = width;
732f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen            mSurfaceHeight = height;
733217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        }
734217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
735217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
736217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
737217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
738217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        // Since we've disabled orientation changes, we can safely ignore this
739217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
740217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
741217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
742217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
743f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen        mSurface = null;
744f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
745217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen        return true;
746217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    }
747217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen
748217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen    @Override
749f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen    public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
750f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen
7511a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    public void showSendHint() {
7521a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mAlphaDownAnimator.isRunning()) {
7531a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen           mAlphaDownAnimator.cancel();
7541a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
7551a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        if (mSlowSendAnimator.isRunning()) {
7561a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen            mSlowSendAnimator.cancel();
7571a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        }
7581a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setScaleX(mScreenshotView.getScaleX());
7591a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setScaleY(mScreenshotView.getScaleY());
7601a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mBlackLayer.setVisibility(View.VISIBLE);
7611a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextHint.setVisibility(View.GONE);
7621a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
76365ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales        mTextRetry.setText(mContext.getResources().getString(R.string.beam_try_again));
7641a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mTextRetry.setVisibility(View.VISIBLE);
7651a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen
7661a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha",
76765ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales                new float[] {mBlackLayer.getAlpha(), 0.9f});
7681a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.setValues(alphaUp);
7691a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen        mAlphaUpAnimator.start();
7701a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen    }
7719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchKeyEvent(KeyEvent event) {
77427382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        int keyCode = event.getKeyCode();
77527382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        if (keyCode == KeyEvent.KEYCODE_BACK) {
77665ba8d0d2adb1d1994a0c40d11e28d9ca85f50d9Andres Morales            mCallback.onCanceled();
77727382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return true;
77827382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
77927382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen                keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
78027382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            // Treat as if it's a touch event
78127382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return onTouch(mScreenshotView, null);
78227382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        } else {
78327382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen            return false;
78427382be352460d4d73fffcebe364e71a4a6e4e75Martijn Coenen        }
7859340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7869340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7879340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7889340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
7899340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
7909340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7919340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7929340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7939340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchTouchEvent(MotionEvent event) {
7949340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return mScreenshotLayout.dispatchTouchEvent(event);
7959340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
7969340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
7979340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
7989340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchTrackballEvent(MotionEvent event) {
7999340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8009340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8019340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8029340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8039340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchGenericMotionEvent(MotionEvent event) {
8049340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8059340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8069340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8079340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8089340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
8099340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8109340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8119340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8129340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8139340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public View onCreatePanelView(int featureId) {
8149340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return null;
8159340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8169340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8179340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8189340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onCreatePanelMenu(int featureId, Menu menu) {
8199340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8209340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8219340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8229340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8239340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onPreparePanel(int featureId, View view, Menu menu) {
8249340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8259340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8269340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8279340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8289340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onMenuOpened(int featureId, Menu menu) {
8299340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8309340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8319340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8329340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8339340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onMenuItemSelected(int featureId, MenuItem item) {
8349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8359340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8369340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8379340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8389340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onWindowAttributesChanged(LayoutParams attrs) {
8399340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8409340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8419340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8429340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onContentChanged() {
8439340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8449340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8459340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8469340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onWindowFocusChanged(boolean hasFocus) {
8479340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8489340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8499340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8509340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onAttachedToWindow() {
8519340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8529340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8539340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8549340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onDetachedFromWindow() {
8569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8599340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onPanelClosed(int featureId, Menu menu) {
8609340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8619340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8629340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8639340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
86486bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbourn    public boolean onSearchRequested(SearchEvent searchEvent) {
86586bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbourn        return onSearchRequested();
86686bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbourn    }
86786bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbourn
86886bd05f00c88427e988aa57c0fbbddcb7bd278c6Tim Kilbourn    @Override
8699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public boolean onSearchRequested() {
8709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return false;
8719340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8729340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8739340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8749340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public ActionMode onWindowStartingActionMode(
8759340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            android.view.ActionMode.Callback callback) {
8769340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        return null;
8779340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8789340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
879e5231ecfada2ade90483dc48ff188fc2082f616bClara Bayarri    public ActionMode onWindowStartingActionMode(
880e5231ecfada2ade90483dc48ff188fc2082f616bClara Bayarri            android.view.ActionMode.Callback callback, int type) {
881e5231ecfada2ade90483dc48ff188fc2082f616bClara Bayarri        return null;
882e5231ecfada2ade90483dc48ff188fc2082f616bClara Bayarri    }
883e5231ecfada2ade90483dc48ff188fc2082f616bClara Bayarri
8849340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8859340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onActionModeStarted(ActionMode mode) {
8869340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8879340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8889340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    @Override
8899340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    public void onActionModeFinished(ActionMode mode) {
8909340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen    }
8915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly}
892