diff options
-rw-r--r-- | assets/star.png | bin | 0 -> 978 bytes | |||
-rw-r--r-- | res/drawable-hdpi/back.png | bin | 0 -> 32598 bytes | |||
-rw-r--r-- | res/layout/screenshot.xml | 16 | ||||
-rw-r--r-- | src/com/android/nfc/FireflyRenderThread.java | 415 | ||||
-rw-r--r-- | src/com/android/nfc/SendUi.java | 118 |
5 files changed, 528 insertions, 21 deletions
diff --git a/assets/star.png b/assets/star.png Binary files differnew file mode 100644 index 00000000..77b9ca99 --- /dev/null +++ b/assets/star.png diff --git a/res/drawable-hdpi/back.png b/res/drawable-hdpi/back.png Binary files differnew file mode 100644 index 00000000..dcad41dc --- /dev/null +++ b/res/drawable-hdpi/back.png diff --git a/res/layout/screenshot.xml b/res/layout/screenshot.xml index 180d0450..9e62af7e 100644 --- a/res/layout/screenshot.xml +++ b/res/layout/screenshot.xml @@ -18,6 +18,18 @@ android:layout_height="match_parent" android:background="#FF000000" > + <TextureView android:id="@+id/fireflies" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + /> + <ImageView android:id="@+id/back" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:adjustViewBounds="true" + android:src="@drawable/back" + android:scaleType="centerCrop" + android:visibility="gone" + /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > @@ -34,12 +46,12 @@ android:textColor="?android:attr/textColorPrimary" /> </RelativeLayout> - <ImageView android:id="@+id/screenshot" + <ImageView android:id="@+id/clone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" /> - <ImageView android:id="@+id/clone" + <ImageView android:id="@+id/screenshot" android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" diff --git a/src/com/android/nfc/FireflyRenderThread.java b/src/com/android/nfc/FireflyRenderThread.java new file mode 100644 index 00000000..13b9a120 --- /dev/null +++ b/src/com/android/nfc/FireflyRenderThread.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.nfc; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.SurfaceTexture; +import android.opengl.GLUtils; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; +import javax.microedition.khronos.opengles.GL10; + +public class FireflyRenderThread extends Thread { + private static final String LOG_TAG = "NfcFireflyThread"; + + SurfaceTexture mSurface; + + EGL10 mEgl; + EGLDisplay mEglDisplay; + EGLConfig mEglConfig; + EGLContext mEglContext; + EGLSurface mEglSurface; + GL10 mGL; + + static final int NUM_FIREFLIES = 100; + static final int PIXELS_PER_SECOND = 50; // Speed of fireflies + + static final int[] sEglConfig = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 0, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_STENCIL_SIZE, 0, + EGL10.EGL_NONE + }; + + // Vertices for drawing a 32x32 rect + static final float mVertices[] = { + 0.0f, 0.0f, 0.0f, // 0, Top Left + 0.0f, 32.0f, 0.0f, // 1, Bottom Left + 32.0f, 32.0f, 0.0f, // 2, Bottom Right + 32.0f, 0.0f, 0.0f, // 3, Top Right + }; + + // Mapping coordinates for the texture + static final float mTextCoords[] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f + }; + + // Connecting order (draws a square) + static final short[] mIndices = { 0, 1, 2, 0, 2, 3 }; + + // Buffer holding the vertices + FloatBuffer mVertexBuffer; + + // Buffer holding the indices + ShortBuffer mIndexBuffer; + + // Buffer holding the texture mapping coordinates + FloatBuffer mTextureBuffer; + + // Holding the handle to the texture + int mTextureId; + + final Context mContext; + final int mDisplayWidth; + final int mDisplayHeight; + + Firefly[] mFireflies; + long mStartTime; + + // Read/written by multiple threads + volatile boolean mFinished; + volatile boolean mFadeOut; + + public FireflyRenderThread(Context context, SurfaceTexture surface, int width, int height) { + mSurface = surface; + mContext = context; + mDisplayWidth = width; + mDisplayHeight = height; + mFinished = false; + } + + public void finish() { + mFinished = true; + } + + public void fadeOut() { + mFadeOut = true; + } + + void initShapes() { + // First, build the vertex, texture and index buffers + ByteBuffer vbb = ByteBuffer.allocateDirect(mVertices.length * 4); // Float => 4 bytes + vbb.order(ByteOrder.nativeOrder()); + mVertexBuffer = vbb.asFloatBuffer(); + mVertexBuffer.put(mVertices); + mVertexBuffer.position(0); + + ByteBuffer ibb = ByteBuffer.allocateDirect(mIndices.length * 2); // Short => 2 bytes + ibb.order(ByteOrder.nativeOrder()); + mIndexBuffer = ibb.asShortBuffer(); + mIndexBuffer.put(mIndices); + mIndexBuffer.position(0); + + ByteBuffer tbb = ByteBuffer.allocateDirect(mTextCoords.length * 4); + tbb.order(ByteOrder.nativeOrder()); + mTextureBuffer = tbb.asFloatBuffer(); + mTextureBuffer.put(mTextCoords); + mTextureBuffer.position(0); + + mFadeOut = false; + + mFireflies = new Firefly[NUM_FIREFLIES]; + for (int i = 0; i < NUM_FIREFLIES; i++) { + mFireflies[i] = new Firefly(); + } + loadStarTexture(); + } + + void loadStarTexture() { + int[] textureIds = new int[1]; + mGL.glGenTextures(1, textureIds, 0); + mTextureId = textureIds[0]; + + InputStream in = null; + try { + // Remember that both texture dimensions must be a power of 2! + in = mContext.getAssets().open("star.png"); + + Bitmap bitmap = BitmapFactory.decodeStream(in); + mGL.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId); + + mGL.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); + mGL.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); + + bitmap.recycle(); + + } catch (IOException e) { + Log.e(LOG_TAG, "IOException opening assets."); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { } + } + } + } + + @Override + public void run() { + if (!initGL()) { + finishGL(); + return; + } + + mGL.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + initShapes(); + + mGL.glViewport(0, 0, mDisplayWidth, mDisplayHeight); + + // make adjustments for screen ratio + mGL.glMatrixMode(GL10.GL_PROJECTION); + mGL.glLoadIdentity(); + mGL.glOrthof(0, mDisplayWidth, mDisplayHeight, 0, -1, 1); + + // Switch back to modelview + mGL.glMatrixMode(GL10.GL_MODELVIEW); + mGL.glLoadIdentity(); + + // Reset firefly models + for (Firefly firefly : mFireflies) { + firefly.reset(); + } + + while (!mFinished) { + long timeElapsedMs = System.currentTimeMillis() - mStartTime; + mStartTime = System.currentTimeMillis(); + + checkCurrent(); + + mGL.glClear(GL10.GL_COLOR_BUFFER_BIT); + mGL.glLoadIdentity(); + + mGL.glEnable(GL10.GL_TEXTURE_2D); + + mGL.glEnable(GL10.GL_BLEND); + + mGL.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE); + + for (Firefly firefly : mFireflies) { + firefly.updatePositionAndScale(timeElapsedMs); + firefly.draw(); + } + + if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) { + Log.e(LOG_TAG, "Could not swap buffers"); + mFinished = true; + } + + long elapsed = System.currentTimeMillis() - mStartTime; + try { + Thread.sleep(Math.max(30 - elapsed, 0)); + } catch (InterruptedException e) { + + } + } + finishGL(); + } + + boolean initGL() { + // Initialize openGL engine + mEgl = (EGL10) EGLContext.getEGL(); + + mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL10.EGL_NO_DISPLAY) { + Log.e(LOG_TAG, "eglGetDisplay failed " + + GLUtils.getEGLErrorString(mEgl.eglGetError())); + return false; + } + + int[] version = new int[2]; + if (!mEgl.eglInitialize(mEglDisplay, version)) { + Log.e(LOG_TAG, "eglInitialize failed " + + GLUtils.getEGLErrorString(mEgl.eglGetError())); + return false; + } + + mEglConfig = chooseEglConfig(); + if (mEglConfig == null) { + Log.e(LOG_TAG, "eglConfig not initialized."); + return false; + } + + mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, null); + + mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null); + + if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) { + int error = mEgl.eglGetError(); + Log.e(LOG_TAG,"createWindowSurface returned error"); + return false; + } + + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + Log.e(LOG_TAG, "eglMakeCurrent failed " + + GLUtils.getEGLErrorString(mEgl.eglGetError())); + return false; + } + + mGL = (GL10) mEglContext.getGL(); + + return true; + } + + private void finishGL() { + if (mEgl == null || mEglDisplay == null) { + // Nothing to free + return; + } + // Unbind the current surface and context from the display + mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_CONTEXT); + if (mEglContext != null) { + mEgl.eglDestroyContext(mEglDisplay, mEglContext); + } + if (mEglSurface != null) { + mEgl.eglDestroySurface(mEglDisplay, mEglSurface); + } + } + + private void checkCurrent() { + if (!mEglContext.equals(mEgl.eglGetCurrentContext()) || + !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) { + if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + throw new RuntimeException("eglMakeCurrent failed " + + GLUtils.getEGLErrorString(mEgl.eglGetError())); + } + } + } + + private EGLConfig chooseEglConfig() { + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + if (!mEgl.eglChooseConfig(mEglDisplay, sEglConfig, configs, 1, configsCount)) { + throw new IllegalArgumentException("eglChooseConfig failed " + + GLUtils.getEGLErrorString(mEgl.eglGetError())); + } else if (configsCount[0] > 0) { + return configs[0]; + } + return null; + } + + public class Firefly { + static final int STEADY_INTERVAL_MS = 1250; // Time fireflies continue in same direction + static final float MIN_SCALE = 0.5f; // The minimum amount fireflies are scaled to + + float mX; + float mY; + float mAngle; + float mScale; + float mAlpha; + boolean mScalingDown; + int mTimeRemaining; + + public Firefly() { + reset(); + } + + void reset() { + float randomVal = (float) Math.random(); + + mX = randomVal * mDisplayWidth; + mY = (float) (Math.random() * mDisplayHeight); + mAngle = randomVal * 360f; + mScalingDown = (randomVal > 0.5f) ? true : false; + mTimeRemaining = (int) (randomVal * STEADY_INTERVAL_MS); + mAlpha = 1; + } + + public void updatePositionAndScale(long timeElapsedMs) { + if (mFadeOut) { + // Diminish alpha and return + if (mAlpha > 0) { + mAlpha -= timeElapsedMs * 0.003; + } + return; + } + mX += Math.cos(Math.toRadians(mAngle)) * timeElapsedMs / 1000 * PIXELS_PER_SECOND; + mY += Math.sin(Math.toRadians(mAngle)) * timeElapsedMs / 1000 * PIXELS_PER_SECOND; + + mX %= mDisplayWidth; + if (mX < 0) { + mX += mDisplayWidth; + } + mY %= mDisplayHeight; + if (mY < 0) { + mY += mDisplayHeight; + } + + if (mScalingDown) { + mScale = 1.0f - (((float)mTimeRemaining / STEADY_INTERVAL_MS) * MIN_SCALE); + } else { + mScale = MIN_SCALE + (((float)mTimeRemaining / STEADY_INTERVAL_MS) * MIN_SCALE); + } + + mTimeRemaining -= timeElapsedMs; + if (mTimeRemaining < 0) { + // Update our angle, reverse our scaling + mAngle = (float) (Math.random() * 360f); + mScalingDown = !mScalingDown; + mTimeRemaining = STEADY_INTERVAL_MS; + } + } + + public void draw() { + mGL.glLoadIdentity(); + + // Counter clockwise winding + mGL.glFrontFace(GL10.GL_CCW); + + mGL.glEnableClientState(GL10.GL_VERTEX_ARRAY); + mGL.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); + + mGL.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer); + mGL.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer); + + mGL.glTranslatef(mX, mY, 0); + mGL.glScalef(mScale, mScale, 0); + mGL.glColor4f(1, 1, 1, mAlpha); + + mGL.glDrawElements(GL10.GL_TRIANGLES, mIndices.length, GL10.GL_UNSIGNED_SHORT, + mIndexBuffer); + + mGL.glColor4f(1, 1, 1, 1); + mGL.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); + mGL.glDisableClientState(GL10.GL_VERTEX_ARRAY); + } + } +} diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/SendUi.java index 39b3758b..0bb8916f 100644 --- a/src/com/android/nfc/SendUi.java +++ b/src/com/android/nfc/SendUi.java @@ -31,6 +31,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PixelFormat; +import android.graphics.SurfaceTexture; import android.os.Binder; import android.util.DisplayMetrics; import android.util.Log; @@ -38,6 +39,7 @@ import android.view.Display; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; +import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -50,7 +52,8 @@ import android.widget.TextView; /** * All methods must be called on UI thread */ -public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { +public class SendUi implements Animator.AnimatorListener, View.OnTouchListener, + TextureView.SurfaceTextureListener { private static final String LOG_TAG = "SendUI"; static final float INTERMEDIATE_SCALE = 0.6f; @@ -59,7 +62,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { static final int PRE_DURATION_MS = 300; static final float[] CLONE_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 0.0f}; - static final int SLOW_CLONE_DURATION_MS = 3000; // Stretch out sending over 3s + static final int SLOW_SEND_DURATION_MS = 3000; // Stretch out sending over 3s static final int FAST_CLONE_DURATION_MS = 200; static final float[] SCALE_UP_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 1.0f}; @@ -70,6 +73,9 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { static final float[] TEXT_HINT_ALPHA_RANGE = {0.0f, 1.0f}; static final int TEXT_HINT_ALPHA_DURATION_MS = 500; + static final float[] BACKGROUND_SCALE_RANGE = {1.0f, 2.0f}; + static final int BACKGROUND_SCALE_DURATION_MS = 5000; + static final int FINISH_SCALE_UP = 0; static final int FINISH_SLIDE_OUT = 1; @@ -85,18 +91,22 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { final View mScreenshotLayout; final ImageView mScreenshotView; final ImageView mCloneView; + final ImageView mBackgroundImage; + final TextureView mTextureView; final TextView mTextHint; final Callback mCallback; final ObjectAnimator mPreAnimator; - final ObjectAnimator mSlowCloneAnimator; + final ObjectAnimator mSlowSendAnimator; final ObjectAnimator mFastCloneAnimator; final ObjectAnimator mScaleUpAnimator; final ObjectAnimator mHintAnimator; final AnimatorSet mSuccessAnimatorSet; + final ObjectAnimator mBackgroundAnimator; final boolean mHardwareAccelerated; Bitmap mScreenshotBitmap; ObjectAnimator mSlideoutAnimator; + FireflyRenderThread mFireflyRenderThread; boolean mAttached; @@ -125,6 +135,10 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { mTextHint = (TextView) mScreenshotLayout.findViewById(R.id.calltoaction); + mTextureView = (TextureView) mScreenshotLayout.findViewById(R.id.fireflies); + mTextureView.setSurfaceTextureListener(this); + + mBackgroundImage = (ImageView) mScreenshotLayout.findViewById(R.id.back); // We're only allowed to use hardware acceleration if // isHighEndGfx() returns true - otherwise, we're too limited // on resources to do it. @@ -132,6 +146,11 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { int hwAccelerationFlags = mHardwareAccelerated ? WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0; + if (!mHardwareAccelerated) { + // Only show background in case we're not hw-accelerated + mBackgroundImage.setVisibility(View.VISIBLE); + } + mWindowLayoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, @@ -151,9 +170,9 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", CLONE_SCREENSHOT_SCALE); PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", CLONE_SCREENSHOT_SCALE); - mSlowCloneAnimator = ObjectAnimator.ofPropertyValuesHolder(mCloneView, postX, postY); - mSlowCloneAnimator.setInterpolator(null); // linear - mSlowCloneAnimator.setDuration(SLOW_CLONE_DURATION_MS); + mSlowSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, postY); + mSlowSendAnimator.setInterpolator(null); // linear + mSlowSendAnimator.setDuration(SLOW_SEND_DURATION_MS); mFastCloneAnimator = ObjectAnimator.ofPropertyValuesHolder(mCloneView, postX, postY); mFastCloneAnimator.setInterpolator(null); // linear @@ -174,6 +193,12 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { mSuccessAnimatorSet = new AnimatorSet(); mSuccessAnimatorSet.playSequentially(mFastCloneAnimator, mScaleUpAnimator); + scaleUpX = PropertyValuesHolder.ofFloat("scaleX", BACKGROUND_SCALE_RANGE); + scaleUpY = PropertyValuesHolder.ofFloat("scaleY", BACKGROUND_SCALE_RANGE); + mBackgroundAnimator = ObjectAnimator.ofPropertyValuesHolder(mBackgroundImage, scaleUpX, scaleUpY); + mBackgroundAnimator.setInterpolator(new DecelerateInterpolator(2.0f)); + mBackgroundAnimator.setDuration(BACKGROUND_SCALE_DURATION_MS); + mAttached = false; } @@ -204,7 +229,6 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { mCloneView.setScaleX(INTERMEDIATE_SCALE); mCloneView.setScaleY(INTERMEDIATE_SCALE); - mTextHint.setVisibility(showHint ? View.VISIBLE : View.GONE); mTextHint.setAlpha(1.0f); @@ -231,12 +255,23 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { break; } + // Reset scale up parameters + PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", + SCALE_UP_SCREENSHOT_SCALE); + PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", + SCALE_UP_SCREENSHOT_SCALE); + mScaleUpAnimator.setValues(scaleUpX, scaleUpY); + mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); // Disable statusbar pull-down mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); mAttached = true; mPreAnimator.start(); + + if (!mHardwareAccelerated) { + mBackgroundAnimator.start(); + } } /** Show starting send animation */ @@ -244,11 +279,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { if (!mAttached) { return; } - mScreenshotView.setAlpha(0.7f); - mCloneView.setScaleX(INTERMEDIATE_SCALE); - mCloneView.setScaleY(INTERMEDIATE_SCALE); - mCloneView.setVisibility(View.VISIBLE); - mSlowCloneAnimator.start(); + mSlowSendAnimator.start(); } /** Show post-send animation */ @@ -257,15 +288,33 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { return; } - mSlowCloneAnimator.cancel(); + mSlowSendAnimator.cancel(); mTextHint.setVisibility(View.GONE); - // Modify the fast clone parameters to match the current scale - float currentScale = mCloneView.getScaleX(); - currentScale = mCloneView.getScaleX(); - PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", new float[] {currentScale, 0.0f}); - PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", new float[] {currentScale, 0.0f}); + float currentScale = mScreenshotView.getScaleX(); + mScreenshotView.setAlpha(0.7f); + + // Make the clone visible for scaling to the background + mCloneView.setScaleX(currentScale); + mCloneView.setScaleY(currentScale); + mCloneView.setVisibility(View.VISIBLE); + + // Modify the fast clone parameters to match the current scale + PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", + new float[] {currentScale, 0.0f}); + PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", + new float[] {currentScale, 0.0f}); mFastCloneAnimator.setValues(postX, postY); + // Modify the scale up parameters to match the current scale + PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", + new float[] {currentScale, 1.0f}); + PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", + new float[] {currentScale, 1.0f}); + mScaleUpAnimator.setValues(scaleUpX, scaleUpY); + + if (mFireflyRenderThread != null) { + mFireflyRenderThread.fadeOut(); + } mSuccessAnimatorSet.start(); } @@ -294,7 +343,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { return; } mPreAnimator.cancel(); - mSlowCloneAnimator.cancel(); + mSlowSendAnimator.cancel(); mFastCloneAnimator.cancel(); mSuccessAnimatorSet.cancel(); mScaleUpAnimator.cancel(); @@ -397,4 +446,35 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener { mCallback.onSendConfirmed(); return true; } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + if (mHardwareAccelerated) { + mFireflyRenderThread = new FireflyRenderThread(mContext, surface, width, height); + mFireflyRenderThread.start(); + } + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + // Since we've disabled orientation changes, we can safely ignore this + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + if (mFireflyRenderThread != null) { + mFireflyRenderThread.finish(); + try { + mFireflyRenderThread.join(); + } catch (InterruptedException e) { + Log.e(LOG_TAG, "Couldn't wait for FireflyRenderThread."); + } + mFireflyRenderThread = null; + } + return true; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + } } |