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 195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.Animator; 2069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.animation.AnimatorSet; 215438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.ObjectAnimator; 225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.animation.PropertyValuesHolder; 23f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenenimport android.animation.TimeAnimator; 240c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.ActivityManager; 250c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.app.StatusBarManager; 265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.content.Context; 2769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.pm.ActivityInfo; 2869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.content.res.Configuration; 295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Bitmap; 305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Canvas; 315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.Matrix; 325438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.graphics.PixelFormat; 33217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.graphics.SurfaceTexture; 3457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenenimport android.os.AsyncTask; 355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.os.Binder; 365438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.util.DisplayMetrics; 37595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenenimport android.util.Log; 385438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Display; 395438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.LayoutInflater; 40b2112cff553c3b6658440bf06060c7a08f82df5cNick Pellyimport android.view.MotionEvent; 415438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.Surface; 4282792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopianimport android.view.SurfaceControl; 43217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenimport android.view.TextureView; 445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.View; 455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.ViewGroup; 465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.view.WindowManager; 470c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenenimport android.view.animation.AccelerateDecelerateInterpolator; 4869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenenimport android.view.animation.DecelerateInterpolator; 495438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pellyimport android.widget.ImageView; 50be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenenimport android.widget.TextView; 51a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenenimport android.widget.Toast; 525438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 535438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly/** 54f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * This class is responsible for handling the UI animation 55f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * around Android Beam. The animation consists of the following 56f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * animators: 57f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * 58f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator: scales the screenshot down to INTERMEDIATE_SCALE 59f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mSlowSendAnimator: scales the screenshot down to 0.2f (used as a "send in progress" animation) 60f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFastSendAnimator: quickly scales the screenshot down to 0.0f (used for send success) 61f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mFadeInAnimator: fades the current activity back in (used after mFastSendAnimator completes) 62f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mScaleUpAnimator: scales the screenshot back up to full screen (used for failure or receiving) 63f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mHintAnimator: Slowly turns up the alpha of the "Touch to Beam" hint 64f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * 65f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Possible sequences are: 66f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * 67f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mFastSendAnimator => mFadeInAnimator (send success) 68f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mSlowSendAnimator => mScaleUpAnimator (send failure) 69f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * mPreAnimator => mScaleUpAnimator (p2p link broken, or data received) 70f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * 71f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * Note that mFastSendAnimator and mFadeInAnimator are combined in a set, as they 72f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * are an atomic animation that cannot be interrupted. 73f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * 74f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen * All methods of this class must be called on the UI thread 755438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */ 76217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenenpublic class SendUi implements Animator.AnimatorListener, View.OnTouchListener, 77f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen TimeAnimator.TimeListener, TextureView.SurfaceTextureListener { 78595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final String TAG = "SendUi"; 79595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen 8069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen static final float INTERMEDIATE_SCALE = 0.6f; 815438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 8269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen static final float[] PRE_SCREENSHOT_SCALE = {1.0f, INTERMEDIATE_SCALE}; 83674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely static final int PRE_DURATION_MS = 350; 8469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 85f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen static final float[] SEND_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 0.2f}; 86674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely static final int SLOW_SEND_DURATION_MS = 8000; // Stretch out sending over 8s 87f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen static final int FAST_SEND_DURATION_MS = 350; 8869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 8969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen static final float[] SCALE_UP_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 1.0f}; 9069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen static final int SCALE_UP_DURATION_MS = 300; 915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 92674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely static final int FADE_IN_DURATION_MS = 250; 93674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely static final int FADE_IN_START_DELAY_MS = 350; 94674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely 950c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen static final int SLIDE_OUT_DURATION_MS = 300; 960c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 971a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen static final float[] BLACK_LAYER_ALPHA_DOWN_RANGE = {0.9f, 0.0f}; 981a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen static final float[] BLACK_LAYER_ALPHA_UP_RANGE = {0.0f, 0.9f}; 991a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 100be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen static final float[] TEXT_HINT_ALPHA_RANGE = {0.0f, 1.0f}; 101be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen static final int TEXT_HINT_ALPHA_DURATION_MS = 500; 102674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely static final int TEXT_HINT_ALPHA_START_DELAY_MS = 300; 103be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen 1040c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen static final int FINISH_SCALE_UP = 0; 105f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen static final int FINISH_SEND_SUCCESS = 1; 1060c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 10757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen static final int STATE_IDLE = 0; 108595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_W4_SCREENSHOT = 1; 109595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_W4_SCREENSHOT_PRESEND_REQUESTED = 2; 110595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_W4_SCREENSHOT_THEN_STOP = 3; 111595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_W4_PRESEND = 4; 112595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_W4_CONFIRM = 5; 113595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_SENDING = 6; 114595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen static final int STATE_COMPLETE = 7; 11557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen 1165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // all members are only used on UI thread 1175438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final WindowManager mWindowManager; 1185438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final Context mContext; 1195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final Display mDisplay; 1205438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final DisplayMetrics mDisplayMetrics; 1215438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final Matrix mDisplayMatrix; 1225438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final WindowManager.LayoutParams mWindowLayoutParams; 1235438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final LayoutInflater mLayoutInflater; 1240c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen final StatusBarManager mStatusBarManager; 1255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final View mScreenshotLayout; 1265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final ImageView mScreenshotView; 1271a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen final ImageView mBlackLayer; 128217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen final TextureView mTextureView; 129be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen final TextView mTextHint; 1301a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen final TextView mTextRetry; 1315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final Callback mCallback; 132f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 133f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // The mFrameCounter animation is purely used to count down a certain 134f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // number of (vsync'd) frames. This is needed because the first 3 135f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // times the animation internally calls eglSwapBuffers(), large buffers 136f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // are allocated by the graphics drivers. This causes the animation 137f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // to look janky. So on platforms where we can use hardware acceleration, 138f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // the animation order is: 139f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Wait for hw surface => start frame counter => start pre-animation after 3 frames 140f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // For platforms where no hw acceleration can be used, the pre-animation 141f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // is started immediately. 142f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen final TimeAnimator mFrameCounterAnimator; 143f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 1445438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly final ObjectAnimator mPreAnimator; 145217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen final ObjectAnimator mSlowSendAnimator; 146f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen final ObjectAnimator mFastSendAnimator; 147674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely final ObjectAnimator mFadeInAnimator; 148be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen final ObjectAnimator mHintAnimator; 149f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen final ObjectAnimator mScaleUpAnimator; 1501a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen final ObjectAnimator mAlphaDownAnimator; 1511a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen final ObjectAnimator mAlphaUpAnimator; 15269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen final AnimatorSet mSuccessAnimatorSet; 153f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 154f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Besides animating the screenshot, the Beam UI also renders 155f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // fireflies on platforms where we can do hardware-acceleration. 156f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Firefly rendering is only started once the initial 157f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // "pre-animation" has scaled down the screenshot, to avoid 158f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // that animation becoming janky. Likewise, the fireflies are 159f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // stopped in their tracks as soon as we finish the animation, 160f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // to make the finishing animation smooth. 1610c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen final boolean mHardwareAccelerated; 162f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen final FireflyRenderer mFireflyRenderer; 1635438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 164a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen String mToastString; 1655438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly Bitmap mScreenshotBitmap; 1660c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 16757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen int mState; 168f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen int mRenderedFrames; 169f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 170f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Used for holding the surface 171f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen SurfaceTexture mSurface; 172f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen int mSurfaceWidth; 173f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen int mSurfaceHeight; 1745438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 1755438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly interface Callback { 176b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly public void onSendConfirmed(); 1775438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 1785438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 1795438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public SendUi(Context context, Callback callback) { 1805438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mContext = context; 1815438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mCallback = callback; 1825438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 1835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMetrics = new DisplayMetrics(); 1845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMatrix = new Matrix(); 1855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 1860c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mStatusBarManager = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); 1870c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 1885438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplay = mWindowManager.getDefaultDisplay(); 1895438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 1905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mLayoutInflater = (LayoutInflater) 1915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 1925438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mScreenshotLayout = mLayoutInflater.inflate(R.layout.screenshot, null); 193f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 1945438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.screenshot); 1955438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mScreenshotLayout.setFocusable(true); 1965438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 197be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen mTextHint = (TextView) mScreenshotLayout.findViewById(R.id.calltoaction); 1981a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextRetry = (TextView) mScreenshotLayout.findViewById(R.id.retrytext); 1991a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer = (ImageView) mScreenshotLayout.findViewById(R.id.blacklayer); 200217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen mTextureView = (TextureView) mScreenshotLayout.findViewById(R.id.fireflies); 201217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen mTextureView.setSurfaceTextureListener(this); 202217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 2030c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen // We're only allowed to use hardware acceleration if 2040c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen // isHighEndGfx() returns true - otherwise, we're too limited 2050c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen // on resources to do it. 206525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mHardwareAccelerated = ActivityManager.isHighEndGfx(); 2070c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen int hwAccelerationFlags = mHardwareAccelerated ? 208f7966d1dadff2d78f01bbdb134e8252b53343179Dianne Hackborn WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0; 2090c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 2105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mWindowLayoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 2110c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, 2120c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 2135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly WindowManager.LayoutParams.FLAG_FULLSCREEN 2140c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen | hwAccelerationFlags 215b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, 2165438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly PixelFormat.OPAQUE); 217525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mWindowLayoutParams.privateFlags |= 218525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2195438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mWindowLayoutParams.token = new Binder(); 2205438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 221f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator = new TimeAnimator(); 222f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator.setTimeListener(this); 223f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 2245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly PropertyValuesHolder preX = PropertyValuesHolder.ofFloat("scaleX", PRE_SCREENSHOT_SCALE); 2255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly PropertyValuesHolder preY = PropertyValuesHolder.ofFloat("scaleY", PRE_SCREENSHOT_SCALE); 2265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mPreAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, preX, preY); 22769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mPreAnimator.setInterpolator(new DecelerateInterpolator()); 2285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mPreAnimator.setDuration(PRE_DURATION_MS); 2295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mPreAnimator.addListener(this); 2305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 231f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", SEND_SCREENSHOT_SCALE); 232f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", SEND_SCREENSHOT_SCALE); 2334dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha", 2344dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen new float[]{1.0f, 0.0f}); 2354dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen 236217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen mSlowSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, postY); 237674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mSlowSendAnimator.setInterpolator(new DecelerateInterpolator()); 238217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen mSlowSendAnimator.setDuration(SLOW_SEND_DURATION_MS); 23969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 240f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, 2414dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen postY, alphaDown); 242f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator.setInterpolator(new DecelerateInterpolator()); 243f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator.setDuration(FAST_SEND_DURATION_MS); 244f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator.addListener(this); 24569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 24669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", SCALE_UP_SCREENSHOT_SCALE); 24769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", SCALE_UP_SCREENSHOT_SCALE); 2484dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen 24969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mScaleUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, scaleUpX, scaleUpY); 250674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mScaleUpAnimator.setInterpolator(new DecelerateInterpolator()); 25169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mScaleUpAnimator.setDuration(SCALE_UP_DURATION_MS); 25269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mScaleUpAnimator.addListener(this); 25369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 254674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", 1.0f); 255674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mFadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, fadeIn); 256674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mFadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); 257674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mFadeInAnimator.setDuration(FADE_IN_DURATION_MS); 258674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mFadeInAnimator.setStartDelay(FADE_IN_START_DELAY_MS); 259674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mFadeInAnimator.addListener(this); 260674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely 261be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", TEXT_HINT_ALPHA_RANGE); 262be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen mHintAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextHint, alphaUp); 263be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen mHintAnimator.setInterpolator(null); 264be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen mHintAnimator.setDuration(TEXT_HINT_ALPHA_DURATION_MS); 265674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely mHintAnimator.setStartDelay(TEXT_HINT_ALPHA_START_DELAY_MS); 266be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen 2671a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen alphaDown = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_DOWN_RANGE); 2681a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaDown); 2691a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.setInterpolator(new DecelerateInterpolator()); 2701a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.setDuration(400); 2711a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 2721a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen alphaUp = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_UP_RANGE); 2731a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaUp); 2741a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator.setInterpolator(new DecelerateInterpolator()); 2751a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator.setDuration(200); 2761a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 27769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mSuccessAnimatorSet = new AnimatorSet(); 278f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSuccessAnimatorSet.playSequentially(mFastSendAnimator, mFadeInAnimator); 2795438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 280f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen if (mHardwareAccelerated) { 281f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFireflyRenderer = new FireflyRenderer(context); 282f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } else { 283f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFireflyRenderer = null; 284f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } 28557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen mState = STATE_IDLE; 2865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 2875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 2885438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public void takeScreenshot() { 28957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen // There's no point in taking the screenshot if 29057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen // we're still finishing the previous animation. 291595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (mState >= STATE_W4_CONFIRM) { 29257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen return; 29357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen } 294595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_SCREENSHOT; 29557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen new ScreenshotTask().execute(); 2965438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 2975438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 29869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen /** Show pre-send animation */ 299e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly public void showPreSend() { 300595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen switch (mState) { 301595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_IDLE: 302595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Unexpected showPreSend() in STATE_IDLE"); 303595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 304595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_SCREENSHOT: 305595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Still waiting for screenshot, store request in state 306595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // and wait for screenshot completion. 307595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_SCREENSHOT_PRESEND_REQUESTED; 308595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 309595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_SCREENSHOT_PRESEND_REQUESTED: 310595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Unexpected showPreSend() in STATE_W4_SCREENSHOT_PRESEND_REQUESTED"); 311595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 312595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_PRESEND: 313595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Expected path, continue below 314595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen break; 315595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen default: 316595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Unexpected showPreSend() in state " + Integer.toString(mState)); 317595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 31857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen } 31990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Update display metrics 32090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen mDisplay.getRealMetrics(mDisplayMetrics); 32190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen 32290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen final int statusBarHeight = mContext.getResources().getDimensionPixelSize( 32390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen com.android.internal.R.dimen.status_bar_height); 32490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen 3251a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setVisibility(View.GONE); 3261a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setAlpha(0f); 327595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mScreenshotLayout.setOnTouchListener(this); 3285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mScreenshotView.setImageBitmap(mScreenshotBitmap); 3290c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mScreenshotView.setTranslationX(0f); 3300c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mScreenshotView.setAlpha(1.0f); 33190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen mScreenshotView.setPadding(0, statusBarHeight, 0, 0); 33269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 33390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen mScreenshotLayout.requestFocus(); 33469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 3351a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextHint.setText(mContext.getResources().getString(R.string.touch)); 336e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly mTextHint.setAlpha(0.0f); 337e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly mTextHint.setVisibility(View.VISIBLE); 338e31749eae9b242d5019eb5cf5f09069d60df9f71Nick Pelly mHintAnimator.start(); 339be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen 34069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // Lock the orientation. 34169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // The orientation from the configuration does not specify whether 34269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // the orientation is reverse or not (ie landscape or reverse landscape). 34369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // So we have to use SENSOR_LANDSCAPE or SENSOR_PORTRAIT to make sure 34469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // we lock in portrait / landscape and have the sensor determine 34569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // which way is up. 34669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen int orientation = mContext.getResources().getConfiguration().orientation; 34769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 34869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen switch (orientation) { 34969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen case Configuration.ORIENTATION_LANDSCAPE: 35069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mWindowLayoutParams.screenOrientation = 35169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; 35269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen break; 35369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen case Configuration.ORIENTATION_PORTRAIT: 35469ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mWindowLayoutParams.screenOrientation = 35569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; 35669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen break; 35769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen default: 35869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mWindowLayoutParams.screenOrientation = 35969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; 36069ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen break; 36169ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen } 36269ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 3635438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); 3640c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen // Disable statusbar pull-down 3650c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); 3660c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 367a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen mToastString = null; 368f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 369f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen if (!mHardwareAccelerated) { 370f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mPreAnimator.start(); 371f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } // else, we will start the animation once we get the hardware surface 372595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_CONFIRM; 37369ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen } 3745438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 37569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen /** Show starting send animation */ 37669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen public void showStartSend() { 37757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen if (mState < STATE_SENDING) return; 378217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 3791a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextRetry.setVisibility(View.GONE); 380f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Update the starting scale - touchscreen-mashers may trigger 381f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // this before the pre-animation completes. 38290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen float currentScale = mScreenshotView.getScaleX(); 383217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", 384217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen new float[] {currentScale, 0.0f}); 385217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", 386217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen new float[] {currentScale, 0.0f}); 387217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 388f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSlowSendAnimator.setValues(postX, postY); 3891a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 3901a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen float currentAlpha = mBlackLayer.getAlpha(); 3911a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen if (mBlackLayer.isShown() && currentAlpha > 0.0f) { 3921a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha", 3931a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen new float[] {currentAlpha, 0.0f}); 3941a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.setValues(alphaDown); 3951a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.start(); 3961a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen } 397f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSlowSendAnimator.start(); 39869ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen } 39969ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 400a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen public void finishAndToast(int finishMode, String toast) { 401a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen mToastString = toast; 402a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen 403a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen finish(finishMode); 404a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen } 405a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen 40669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen /** Return to initial state */ 4070c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen public void finish(int finishMode) { 408595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen switch (mState) { 409595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_IDLE: 410595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 411595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_SCREENSHOT: 412595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_SCREENSHOT_PRESEND_REQUESTED: 413595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Screenshot is still being captured on a separate thread. 414595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Update state, and stop everything when the capture is done. 415595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_SCREENSHOT_THEN_STOP; 416595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 417595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_SCREENSHOT_THEN_STOP: 418595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Unexpected call to finish() in STATE_W4_SCREENSHOT_THEN_STOP"); 419595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 420595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen case STATE_W4_PRESEND: 421595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // We didn't build up any animation state yet, but 422595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // did store the bitmap. Clear out the bitmap, reset 423595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // state and bail. 424595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mScreenshotBitmap = null; 425595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_IDLE; 426595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen return; 427595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen default: 428595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // We've started animations and attached a view; tear stuff down below. 429595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen break; 430595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } 431f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 432f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Stop rendering the fireflies 433f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen if (mFireflyRenderer != null) { 434f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFireflyRenderer.stop(); 43569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen } 436f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 437be7d37a1c6622c8907869fd30e9e6da73fd77290Martijn Coenen mTextHint.setVisibility(View.GONE); 4381a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextRetry.setVisibility(View.GONE); 439f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 440f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen float currentScale = mScreenshotView.getScaleX(); 441f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen float currentAlpha = mScreenshotView.getAlpha(); 442f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 443f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen if (finishMode == FINISH_SCALE_UP) { 4441a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setVisibility(View.GONE); 445674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", 446674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely new float[] {currentScale, 1.0f}); 447674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", 448674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely new float[] {currentScale, 1.0f}); 449674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely PropertyValuesHolder scaleUpAlpha = PropertyValuesHolder.ofFloat("alpha", 450674cd01fd74b403a4625efbfd2743e179c3d9ecaBrandon Keely new float[] {currentAlpha, 1.0f}); 451f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mScaleUpAnimator.setValues(scaleUpX, scaleUpY, scaleUpAlpha); 452f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 4530c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mScaleUpAnimator.start(); 454f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } else if (finishMode == FINISH_SEND_SUCCESS){ 455f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Modify the fast send parameters to match the current scale 456f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", 457f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen new float[] {currentScale, 0.0f}); 458f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", 459f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen new float[] {currentScale, 0.0f}); 460f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 4611a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen new float[] {currentAlpha, 0.0f}); 462f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator.setValues(postX, postY, alpha); 463f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 464f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Reset the fadeIn parameters to start from alpha 1 465f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", 466f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen new float[] {0.0f, 1.0f}); 467f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFadeInAnimator.setValues(fadeIn); 468f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 469f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSlowSendAnimator.cancel(); 470f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSuccessAnimatorSet.start(); 4710c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen } 47257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen mState = STATE_COMPLETE; 4735438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 4745438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 475595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen void dismiss() { 476595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (mState < STATE_W4_CONFIRM) return; 47757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen // Immediately set to IDLE, to prevent .cancel() calls 4784e0ab3174beafb4915388d8c11286a48e362ed7cMartijn Coenen // below from immediately calling into dismiss() again. 47957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen // (They can do so on the same thread). 48057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen mState = STATE_IDLE; 481f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSurface = null; 482f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator.cancel(); 4835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mPreAnimator.cancel(); 484217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen mSlowSendAnimator.cancel(); 485f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFastSendAnimator.cancel(); 48669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mSuccessAnimatorSet.cancel(); 48769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mScaleUpAnimator.cancel(); 4881a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator.cancel(); 4891a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.cancel(); 4905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mWindowManager.removeView(mScreenshotLayout); 4910c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); 49257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen mScreenshotBitmap = null; 493a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen if (mToastString != null) { 494a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen Toast.makeText(mContext, mToastString, Toast.LENGTH_LONG).show(); 495a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen } 496a3715d12aeba988c1104726e935462ea4f39eca7Martijn Coenen mToastString = null; 4975438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 4985438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 4995438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly /** 5005438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * @return the current display rotation in degrees 5015438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */ 5025438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly static float getDegreesForRotation(int value) { 5035438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly switch (value) { 5045438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly case Surface.ROTATION_90: 5055438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return 90f; 5065438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly case Surface.ROTATION_180: 5075438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return 180f; 5085438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly case Surface.ROTATION_270: 5095438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return 270f; 5105438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 5115438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return 0f; 5125438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 5135438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 51457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen final class ScreenshotTask extends AsyncTask<Void, Void, Bitmap> { 51557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen @Override 51657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen protected Bitmap doInBackground(Void... params) { 51757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen return createScreenshot(); 51857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen } 51957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen 52057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen @Override 52157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen protected void onPostExecute(Bitmap result) { 522595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (mState == STATE_W4_SCREENSHOT) { 523595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Screenshot done, wait for request to start preSend anim 524595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_PRESEND; 525595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } else if (mState == STATE_W4_SCREENSHOT_THEN_STOP) { 526595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // We were asked to finish, move to idle state and exit 527595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_IDLE; 528595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } else if (mState == STATE_W4_SCREENSHOT_PRESEND_REQUESTED) { 529595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (result != null) { 530595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mScreenshotBitmap = result; 531595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_W4_PRESEND; 532595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen showPreSend(); 533595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } else { 534595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // Failed to take screenshot; reset state to idle 535595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen // and don't do anything 536595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Failed to create screenshot"); 537595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen mState = STATE_IDLE; 538595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } 539595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen } else { 540595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen Log.e(TAG, "Invalid state on screenshot completion: " + Integer.toString(mState)); 54157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen } 54257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen } 54357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen }; 54457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen 5455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly /** 5465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly * Returns a screenshot of the current display contents. 5475438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly */ 5485438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly Bitmap createScreenshot() { 5495438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // We need to orient the screenshot correctly (and the Surface api seems to 5505438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // take screenshots only in the natural orientation of the device :!) 5510c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 5525438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplay.getRealMetrics(mDisplayMetrics); 553e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen boolean hasNavBar = mContext.getResources().getBoolean( 554e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen com.android.internal.R.bool.config_showNavigationBar); 5550c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen 5565438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels}; 5575438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly float degrees = getDegreesForRotation(mDisplay.getRotation()); 55890e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen final int statusBarHeight = mContext.getResources().getDimensionPixelSize( 55990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen com.android.internal.R.dimen.status_bar_height); 560e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen 56190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Navbar has different sizes, depending on orientation 562e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize( 563e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen com.android.internal.R.dimen.navigation_bar_height) : 0; 564525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize( 565525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project com.android.internal.R.dimen.navigation_bar_height_landscape) : 0; 566525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project 567e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize( 568e3cfbec7045220294c172d55122daf55ab6cb058Martijn Coenen com.android.internal.R.dimen.navigation_bar_width) : 0; 56990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen 5705438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly boolean requiresRotation = (degrees > 0); 5715438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly if (requiresRotation) { 5725438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // Get the dimensions of the device in its native orientation 5735438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMatrix.reset(); 5745438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMatrix.preRotate(-degrees); 5755438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMatrix.mapPoints(dims); 5765438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly dims[0] = Math.abs(dims[0]); 5775438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly dims[1] = Math.abs(dims[1]); 5785438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 5795438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 58082792d9a73138f209d1f46f156604c4c65f69c0bMathias Agopian Bitmap bitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]); 5815438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // Bail if we couldn't take the screenshot 5825438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly if (bitmap == null) { 5835438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return null; 5845438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 5855438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 5865438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly if (requiresRotation) { 5875438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly // Rotate the screenshot to the current orientation 5885438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels, 5895438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888); 5905438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly Canvas c = new Canvas(ss); 5915438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly c.translate(ss.getWidth() / 2, ss.getHeight() / 2); 5925438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly c.rotate(360f - degrees); 5935438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly c.translate(-dims[0] / 2, -dims[1] / 2); 5945438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly c.drawBitmap(bitmap, 0, 0, null); 5955438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 5965438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly bitmap = ss; 5975438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 5985438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 59990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // TODO this is somewhat device-specific; need generic solution. 60090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Crop off the status bar and the nav bar 60190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Portrait: 0, statusBarHeight, width, height - status - nav 60290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Landscape: 0, statusBarHeight, width - navBar, height - status 60390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen int newLeft = 0; 60490e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen int newTop = statusBarHeight; 60590e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen int newWidth = bitmap.getWidth(); 60690e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen int newHeight = bitmap.getHeight(); 607525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project float smallestWidth = (float)Math.min(newWidth, newHeight); 608525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f); 60990e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen if (bitmap.getWidth() < bitmap.getHeight()) { 61090e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen // Portrait mode: status bar is at the top, navbar bottom, width unchanged 61190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight; 61290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen } else { 613525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project // Landscape mode: status bar is at the top 614525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project // Navbar: bottom on >599dp width devices, otherwise to the side 615525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project if (smallestWidthDp > 599) { 616525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape; 617525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } else { 618525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project newHeight = bitmap.getHeight() - statusBarHeight; 619525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project newWidth = bitmap.getWidth() - navBarWidth; 620525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 62190e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen } 62290e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight); 62390e1b000b385d7fa11481ddca4d61d6b425d7579Martijn Coenen 6245438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly return bitmap; 6255438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 6265438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 6275438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly @Override 6285438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public void onAnimationStart(Animator animation) { } 6295438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 6305438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly @Override 6315438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public void onAnimationEnd(Animator animation) { 6320c4fce176e6acb1a1a74e9248cf83eb0314490aaMartijn Coenen if (animation == mScaleUpAnimator || animation == mSuccessAnimatorSet || 633f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen animation == mFadeInAnimator) { 634f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // These all indicate the end of the animation 6355438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly dismiss(); 636f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } else if (animation == mFastSendAnimator) { 637f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // After sending is done and we've faded out, reset the scale to 1 6384dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen // so we can fade it back in. 6394dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen mScreenshotView.setScaleX(1.0f); 6404dd3c020b434aec0ccca030afeb57a861bc9a2f3Martijn Coenen mScreenshotView.setScaleY(1.0f); 641f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } else if (animation == mPreAnimator) { 642595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (mHardwareAccelerated && (mState == STATE_W4_CONFIRM)) { 643f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFireflyRenderer.start(mSurface, mSurfaceWidth, mSurfaceHeight); 644f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } 6455438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 6465438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly } 6475438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 6485438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly @Override 6495438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public void onAnimationCancel(Animator animation) { } 6505438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly 6515438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly @Override 6525438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly public void onAnimationRepeat(Animator animation) { } 653b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly 654b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly @Override 655f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 656f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // This gets called on animation vsync 657f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen if (++mRenderedFrames < 4) { 658f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // For the first 3 frames, call invalidate(); this calls eglSwapBuffers 659f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // on the surface, which will allocate large buffers the first three calls 660f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // as Android uses triple buffering. 661f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mScreenshotLayout.invalidate(); 662f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } else { 663f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Buffers should be allocated, start the real animation 664f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator.cancel(); 665f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mPreAnimator.start(); 666f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } 667f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen } 668f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 669f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen @Override 670b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly public boolean onTouch(View v, MotionEvent event) { 671595ab7e9788f61125fa14d1ff2768f995ac7b7e7Martijn Coenen if (mState != STATE_W4_CONFIRM) { 672b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly return false; 673b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly } 67457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen mState = STATE_SENDING; 67569ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen // Ignore future touches 67669ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen mScreenshotView.setOnTouchListener(null); 67769ca6627125c91c44b9e0d8bfa5df83281c2ebe1Martijn Coenen 678f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen // Cancel any ongoing animations 679f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator.cancel(); 680f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mPreAnimator.cancel(); 681f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 682b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly mCallback.onSendConfirmed(); 683b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly return true; 684b2112cff553c3b6658440bf06060c7a08f82df5cNick Pelly } 685217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 686217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen @Override 687217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 68857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen if (mHardwareAccelerated && mState < STATE_COMPLETE) { 689f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mRenderedFrames = 0; 690f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 691f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mFrameCounterAnimator.start(); 692f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSurface = surface; 693f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSurfaceWidth = width; 694f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSurfaceHeight = height; 695217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen } 696217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen } 697217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 698217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen @Override 699217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 700217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen // Since we've disabled orientation changes, we can safely ignore this 701217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen } 702217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 703217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen @Override 704217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 705f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen mSurface = null; 706f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 707217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen return true; 708217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen } 709217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen 710217edd31f93c3917a8bb02420366b88d27c431c2Martijn Coenen @Override 711f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen public void onSurfaceTextureUpdated(SurfaceTexture surface) { } 712f570dca6b0fa0ce883f5c950815e43acae4f51b2Martijn Coenen 7131a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen public void showSendHint() { 7141a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen if (mAlphaDownAnimator.isRunning()) { 7151a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaDownAnimator.cancel(); 7161a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen } 7171a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen if (mSlowSendAnimator.isRunning()) { 7181a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mSlowSendAnimator.cancel(); 7191a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen } 7201a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setScaleX(mScreenshotView.getScaleX()); 7211a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setScaleY(mScreenshotView.getScaleY()); 7221a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mBlackLayer.setVisibility(View.VISIBLE); 7231a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextHint.setVisibility(View.GONE); 7241a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 7251a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextRetry.setText(mContext.getResources().getString(R.string.beam_try_again)); 7261a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mTextRetry.setVisibility(View.VISIBLE); 7271a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen 7281a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", 7291a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen new float[] {mBlackLayer.getAlpha(), 0.9f}); 7301a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator.setValues(alphaUp); 7311a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen mAlphaUpAnimator.start(); 7321a158c7f354d1e1b031fba88928dbaa022e0d0dfMartijn Coenen } 7335438ab0e17064e20870ac893a2dd2b9e1219eef1Nick Pelly} 734