157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang/* 257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * Copyright (C) 2012 The Android Open Source Project 357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * 457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * you may not use this file except in compliance with the License. 657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * You may obtain a copy of the License at 757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * 857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * http://www.apache.org/licenses/LICENSE-2.0 957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * 1057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * Unless required by applicable law or agreed to in writing, software 1157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 1257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * See the License for the specific language governing permissions and 1457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * limitations under the License. 1557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang */ 1657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangpackage com.example.android.supportv7.media; 1857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1961636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.annotation.TargetApi; 2057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.content.Context; 21cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhangimport android.graphics.Bitmap; 2257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.graphics.SurfaceTexture; 2357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.hardware.display.DisplayManager; 248e006e629800b4a2643416f97bca2711af728837Jeff Brownimport android.os.Build; 2561636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.util.DisplayMetrics; 2657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.util.Log; 2757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.Display; 2857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.GestureDetector; 2957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.Gravity; 3057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.LayoutInflater; 3157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.MotionEvent; 3257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.ScaleGestureDetector; 3361636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.view.Surface; 348e006e629800b4a2643416f97bca2711af728837Jeff Brownimport android.view.SurfaceHolder; 358e006e629800b4a2643416f97bca2711af728837Jeff Brownimport android.view.SurfaceView; 3657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.TextureView; 3761636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.view.TextureView.SurfaceTextureListener; 3857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.View; 3957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.view.WindowManager; 4057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhangimport android.widget.TextView; 4157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 4261636870e0a12db5909955eca58e0070357dde42Donghyun Choimport com.example.android.supportv7.R; 4361636870e0a12db5909955eca58e0070357dde42Donghyun Cho 4457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang/** 4557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang * Manages an overlay display window, used for simulating remote playback. 4657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang */ 478e006e629800b4a2643416f97bca2711af728837Jeff Brownpublic abstract class OverlayDisplayWindow { 4857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang private static final String TAG = "OverlayDisplayWindow"; 4957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang private static final boolean DEBUG = false; 5057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 518e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final float WINDOW_ALPHA = 0.8f; 528e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final float INITIAL_SCALE = 0.5f; 538e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final float MIN_SCALE = 0.3f; 548e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final float MAX_SCALE = 1.0f; 5557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 568e006e629800b4a2643416f97bca2711af728837Jeff Brown protected final Context mContext; 578e006e629800b4a2643416f97bca2711af728837Jeff Brown protected final String mName; 588e006e629800b4a2643416f97bca2711af728837Jeff Brown protected final int mWidth; 598e006e629800b4a2643416f97bca2711af728837Jeff Brown protected final int mHeight; 608e006e629800b4a2643416f97bca2711af728837Jeff Brown protected final int mGravity; 618e006e629800b4a2643416f97bca2711af728837Jeff Brown protected OverlayWindowListener mListener; 6257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 638e006e629800b4a2643416f97bca2711af728837Jeff Brown protected OverlayDisplayWindow(Context context, String name, 6457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang int width, int height, int gravity) { 6557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang mContext = context; 668e006e629800b4a2643416f97bca2711af728837Jeff Brown mName = name; 6757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang mWidth = width; 6857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang mHeight = height; 6957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang mGravity = gravity; 708e006e629800b4a2643416f97bca2711af728837Jeff Brown } 7157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 728e006e629800b4a2643416f97bca2711af728837Jeff Brown public static OverlayDisplayWindow create(Context context, String name, 738e006e629800b4a2643416f97bca2711af728837Jeff Brown int width, int height, int gravity) { 748e006e629800b4a2643416f97bca2711af728837Jeff Brown if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 758e006e629800b4a2643416f97bca2711af728837Jeff Brown return new JellybeanMr1Impl(context, name, width, height, gravity); 768e006e629800b4a2643416f97bca2711af728837Jeff Brown } else { 778e006e629800b4a2643416f97bca2711af728837Jeff Brown return new LegacyImpl(context, name, width, height, gravity); 788e006e629800b4a2643416f97bca2711af728837Jeff Brown } 7957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 8057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 8157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang public void setOverlayWindowListener(OverlayWindowListener listener) { 8257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang mListener = listener; 8357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 8457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 8557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang public Context getContext() { 8657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang return mContext; 8757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 8857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 898e006e629800b4a2643416f97bca2711af728837Jeff Brown public abstract void show(); 9057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 918e006e629800b4a2643416f97bca2711af728837Jeff Brown public abstract void dismiss(); 9257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 938e006e629800b4a2643416f97bca2711af728837Jeff Brown public abstract void updateAspectRatio(int width, int height); 948e006e629800b4a2643416f97bca2711af728837Jeff Brown 95cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang public abstract Bitmap getSnapshot(); 96cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang 978e006e629800b4a2643416f97bca2711af728837Jeff Brown // Watches for significant changes in the overlay display window lifecycle. 988e006e629800b4a2643416f97bca2711af728837Jeff Brown public interface OverlayWindowListener { 9976d965dc41863b33f887db33d283cb7f1523f60dJae Seo void onWindowCreated(Surface surface); 10076d965dc41863b33f887db33d283cb7f1523f60dJae Seo void onWindowCreated(SurfaceHolder surfaceHolder); 10176d965dc41863b33f887db33d283cb7f1523f60dJae Seo void onWindowDestroyed(); 10257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 10357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1048e006e629800b4a2643416f97bca2711af728837Jeff Brown /** 1058e006e629800b4a2643416f97bca2711af728837Jeff Brown * Implementation for older versions. 1068e006e629800b4a2643416f97bca2711af728837Jeff Brown */ 107e8e0eae2600001c8b1e9d5a9f0331cf045193746Aurimas Liutikas @SuppressWarnings("deprecation") // Intentionally using deprecated APIs for pre JB MR1 devices. 1088e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final class LegacyImpl extends OverlayDisplayWindow { 1098e006e629800b4a2643416f97bca2711af728837Jeff Brown private final WindowManager mWindowManager; 1108e006e629800b4a2643416f97bca2711af728837Jeff Brown 1118e006e629800b4a2643416f97bca2711af728837Jeff Brown private boolean mWindowVisible; 1128e006e629800b4a2643416f97bca2711af728837Jeff Brown private SurfaceView mSurfaceView; 1138e006e629800b4a2643416f97bca2711af728837Jeff Brown 1148e006e629800b4a2643416f97bca2711af728837Jeff Brown public LegacyImpl(Context context, String name, 1158e006e629800b4a2643416f97bca2711af728837Jeff Brown int width, int height, int gravity) { 1168e006e629800b4a2643416f97bca2711af728837Jeff Brown super(context, name, width, height, gravity); 1178e006e629800b4a2643416f97bca2711af728837Jeff Brown 1188e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager = (WindowManager)context.getSystemService( 1198e006e629800b4a2643416f97bca2711af728837Jeff Brown Context.WINDOW_SERVICE); 12057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 12157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1228e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 1238e006e629800b4a2643416f97bca2711af728837Jeff Brown public void show() { 1248e006e629800b4a2643416f97bca2711af728837Jeff Brown if (!mWindowVisible) { 1258e006e629800b4a2643416f97bca2711af728837Jeff Brown mSurfaceView = new SurfaceView(mContext); 1268e006e629800b4a2643416f97bca2711af728837Jeff Brown 1278e006e629800b4a2643416f97bca2711af728837Jeff Brown Display display = mWindowManager.getDefaultDisplay(); 1288e006e629800b4a2643416f97bca2711af728837Jeff Brown 1298e006e629800b4a2643416f97bca2711af728837Jeff Brown WindowManager.LayoutParams params = new WindowManager.LayoutParams( 1308e006e629800b4a2643416f97bca2711af728837Jeff Brown WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1318e006e629800b4a2643416f97bca2711af728837Jeff Brown params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 1328e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 1338e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1348e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 1358e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 1368e006e629800b4a2643416f97bca2711af728837Jeff Brown params.alpha = WINDOW_ALPHA; 1378e006e629800b4a2643416f97bca2711af728837Jeff Brown params.gravity = Gravity.LEFT | Gravity.BOTTOM; 1388e006e629800b4a2643416f97bca2711af728837Jeff Brown params.setTitle(mName); 1398e006e629800b4a2643416f97bca2711af728837Jeff Brown 1408e006e629800b4a2643416f97bca2711af728837Jeff Brown int width = (int)(display.getWidth() * INITIAL_SCALE); 1418e006e629800b4a2643416f97bca2711af728837Jeff Brown int height = (int)(display.getHeight() * INITIAL_SCALE); 1428e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mWidth > mHeight) { 1438e006e629800b4a2643416f97bca2711af728837Jeff Brown height = mHeight * width / mWidth; 1448e006e629800b4a2643416f97bca2711af728837Jeff Brown } else { 1458e006e629800b4a2643416f97bca2711af728837Jeff Brown width = mWidth * height / mHeight; 1468e006e629800b4a2643416f97bca2711af728837Jeff Brown } 1478e006e629800b4a2643416f97bca2711af728837Jeff Brown params.width = width; 1488e006e629800b4a2643416f97bca2711af728837Jeff Brown params.height = height; 1498e006e629800b4a2643416f97bca2711af728837Jeff Brown 1508e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager.addView(mSurfaceView, params); 1518e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowVisible = true; 1528e006e629800b4a2643416f97bca2711af728837Jeff Brown 1534523ef115a83bf0f655dc58262bd156d7555c91bChong Zhang SurfaceHolder holder = mSurfaceView.getHolder(); 1544523ef115a83bf0f655dc58262bd156d7555c91bChong Zhang holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 1554523ef115a83bf0f655dc58262bd156d7555c91bChong Zhang mListener.onWindowCreated(holder); 1568e006e629800b4a2643416f97bca2711af728837Jeff Brown } 15757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 15857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1598e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 1608e006e629800b4a2643416f97bca2711af728837Jeff Brown public void dismiss() { 1618e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mWindowVisible) { 1628e006e629800b4a2643416f97bca2711af728837Jeff Brown mListener.onWindowDestroyed(); 16357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1648e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager.removeView(mSurfaceView); 1658e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowVisible = false; 1668e006e629800b4a2643416f97bca2711af728837Jeff Brown } 16757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 16857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1698e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 1708e006e629800b4a2643416f97bca2711af728837Jeff Brown public void updateAspectRatio(int width, int height) { 17157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 172cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang 173cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang @Override 174cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang public Bitmap getSnapshot() { 175cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang return null; 176cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang } 1778e006e629800b4a2643416f97bca2711af728837Jeff Brown } 17857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1798e006e629800b4a2643416f97bca2711af728837Jeff Brown /** 1808e006e629800b4a2643416f97bca2711af728837Jeff Brown * Implementation for API version 17+. 1818e006e629800b4a2643416f97bca2711af728837Jeff Brown */ 18261636870e0a12db5909955eca58e0070357dde42Donghyun Cho @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 1838e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final class JellybeanMr1Impl extends OverlayDisplayWindow { 1848e006e629800b4a2643416f97bca2711af728837Jeff Brown // When true, disables support for moving and resizing the overlay. 1858e006e629800b4a2643416f97bca2711af728837Jeff Brown // The window is made non-touchable, which makes it possible to 1868e006e629800b4a2643416f97bca2711af728837Jeff Brown // directly interact with the content underneath. 1878e006e629800b4a2643416f97bca2711af728837Jeff Brown private static final boolean DISABLE_MOVE_AND_RESIZE = false; 18857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1898e006e629800b4a2643416f97bca2711af728837Jeff Brown private final DisplayManager mDisplayManager; 1908e006e629800b4a2643416f97bca2711af728837Jeff Brown private final WindowManager mWindowManager; 19157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1928e006e629800b4a2643416f97bca2711af728837Jeff Brown private final Display mDefaultDisplay; 1938e006e629800b4a2643416f97bca2711af728837Jeff Brown private final DisplayMetrics mDefaultDisplayMetrics = new DisplayMetrics(); 19457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 1958e006e629800b4a2643416f97bca2711af728837Jeff Brown private View mWindowContent; 1968e006e629800b4a2643416f97bca2711af728837Jeff Brown private WindowManager.LayoutParams mWindowParams; 1978e006e629800b4a2643416f97bca2711af728837Jeff Brown private TextureView mTextureView; 1988e006e629800b4a2643416f97bca2711af728837Jeff Brown private TextView mNameTextView; 19957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 2008e006e629800b4a2643416f97bca2711af728837Jeff Brown private GestureDetector mGestureDetector; 2018e006e629800b4a2643416f97bca2711af728837Jeff Brown private ScaleGestureDetector mScaleGestureDetector; 20257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 2038e006e629800b4a2643416f97bca2711af728837Jeff Brown private boolean mWindowVisible; 2048e006e629800b4a2643416f97bca2711af728837Jeff Brown private int mWindowX; 2058e006e629800b4a2643416f97bca2711af728837Jeff Brown private int mWindowY; 2068e006e629800b4a2643416f97bca2711af728837Jeff Brown private float mWindowScale; 2078e006e629800b4a2643416f97bca2711af728837Jeff Brown 2088e006e629800b4a2643416f97bca2711af728837Jeff Brown private float mLiveTranslationX; 2098e006e629800b4a2643416f97bca2711af728837Jeff Brown private float mLiveTranslationY; 2108e006e629800b4a2643416f97bca2711af728837Jeff Brown private float mLiveScale = 1.0f; 2118e006e629800b4a2643416f97bca2711af728837Jeff Brown 2128e006e629800b4a2643416f97bca2711af728837Jeff Brown public JellybeanMr1Impl(Context context, String name, 2138e006e629800b4a2643416f97bca2711af728837Jeff Brown int width, int height, int gravity) { 2148e006e629800b4a2643416f97bca2711af728837Jeff Brown super(context, name, width, height, gravity); 2158e006e629800b4a2643416f97bca2711af728837Jeff Brown 2168e006e629800b4a2643416f97bca2711af728837Jeff Brown mDisplayManager = (DisplayManager)context.getSystemService( 2178e006e629800b4a2643416f97bca2711af728837Jeff Brown Context.DISPLAY_SERVICE); 2188e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager = (WindowManager)context.getSystemService( 2198e006e629800b4a2643416f97bca2711af728837Jeff Brown Context.WINDOW_SERVICE); 2208e006e629800b4a2643416f97bca2711af728837Jeff Brown 2218e006e629800b4a2643416f97bca2711af728837Jeff Brown mDefaultDisplay = mWindowManager.getDefaultDisplay(); 2228e006e629800b4a2643416f97bca2711af728837Jeff Brown updateDefaultDisplayInfo(); 2238e006e629800b4a2643416f97bca2711af728837Jeff Brown 2248e006e629800b4a2643416f97bca2711af728837Jeff Brown createWindow(); 22557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 22657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 22757456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang @Override 2288e006e629800b4a2643416f97bca2711af728837Jeff Brown public void show() { 2298e006e629800b4a2643416f97bca2711af728837Jeff Brown if (!mWindowVisible) { 2308e006e629800b4a2643416f97bca2711af728837Jeff Brown mDisplayManager.registerDisplayListener(mDisplayListener, null); 2318e006e629800b4a2643416f97bca2711af728837Jeff Brown if (!updateDefaultDisplayInfo()) { 2328e006e629800b4a2643416f97bca2711af728837Jeff Brown mDisplayManager.unregisterDisplayListener(mDisplayListener); 2338e006e629800b4a2643416f97bca2711af728837Jeff Brown return; 23457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 2358e006e629800b4a2643416f97bca2711af728837Jeff Brown 2368e006e629800b4a2643416f97bca2711af728837Jeff Brown clearLiveState(); 2378e006e629800b4a2643416f97bca2711af728837Jeff Brown updateWindowParams(); 2388e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager.addView(mWindowContent, mWindowParams); 2398e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowVisible = true; 24057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 24157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 24257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 24357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang @Override 2448e006e629800b4a2643416f97bca2711af728837Jeff Brown public void dismiss() { 2458e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mWindowVisible) { 2468e006e629800b4a2643416f97bca2711af728837Jeff Brown mDisplayManager.unregisterDisplayListener(mDisplayListener); 2478e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager.removeView(mWindowContent); 2488e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowVisible = false; 24957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 25057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 25157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 25257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang @Override 2538e006e629800b4a2643416f97bca2711af728837Jeff Brown public void updateAspectRatio(int width, int height) { 2548e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mWidth * height < mHeight * width) { 2558e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().width = mWidth; 2568e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().height = mWidth * height / width; 2578e006e629800b4a2643416f97bca2711af728837Jeff Brown } else { 2588e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().width = mHeight * width / height; 2598e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().height = mHeight; 26057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 2618e006e629800b4a2643416f97bca2711af728837Jeff Brown relayout(); 26257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 26357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 264cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang @Override 265cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang public Bitmap getSnapshot() { 266cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang return mTextureView.getBitmap(); 267cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang } 268cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang 2698e006e629800b4a2643416f97bca2711af728837Jeff Brown private void relayout() { 2708e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mWindowVisible) { 2718e006e629800b4a2643416f97bca2711af728837Jeff Brown updateWindowParams(); 2728e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowManager.updateViewLayout(mWindowContent, mWindowParams); 27357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 27457456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 27557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 2768e006e629800b4a2643416f97bca2711af728837Jeff Brown private boolean updateDefaultDisplayInfo() { 2778e006e629800b4a2643416f97bca2711af728837Jeff Brown mDefaultDisplay.getMetrics(mDefaultDisplayMetrics); 2788e006e629800b4a2643416f97bca2711af728837Jeff Brown return true; 27957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 28057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 2818e006e629800b4a2643416f97bca2711af728837Jeff Brown private void createWindow() { 2828e006e629800b4a2643416f97bca2711af728837Jeff Brown LayoutInflater inflater = LayoutInflater.from(mContext); 2838e006e629800b4a2643416f97bca2711af728837Jeff Brown 2848e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowContent = inflater.inflate( 2858e006e629800b4a2643416f97bca2711af728837Jeff Brown R.layout.overlay_display_window, null); 2868e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowContent.setOnTouchListener(mOnTouchListener); 2878e006e629800b4a2643416f97bca2711af728837Jeff Brown 2888e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView = (TextureView)mWindowContent.findViewById( 2898e006e629800b4a2643416f97bca2711af728837Jeff Brown R.id.overlay_display_window_texture); 2908e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setPivotX(0); 2918e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setPivotY(0); 2928e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().width = mWidth; 2938e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.getLayoutParams().height = mHeight; 2948e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setOpaque(false); 2958e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); 2968e006e629800b4a2643416f97bca2711af728837Jeff Brown 2978e006e629800b4a2643416f97bca2711af728837Jeff Brown mNameTextView = (TextView)mWindowContent.findViewById( 2988e006e629800b4a2643416f97bca2711af728837Jeff Brown R.id.overlay_display_window_title); 2998e006e629800b4a2643416f97bca2711af728837Jeff Brown mNameTextView.setText(mName); 3008e006e629800b4a2643416f97bca2711af728837Jeff Brown 3018e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams = new WindowManager.LayoutParams( 3028e006e629800b4a2643416f97bca2711af728837Jeff Brown WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 3038e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 3048e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 3058e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 3068e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 3078e006e629800b4a2643416f97bca2711af728837Jeff Brown | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 3088e006e629800b4a2643416f97bca2711af728837Jeff Brown if (DISABLE_MOVE_AND_RESIZE) { 3098e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 3108e006e629800b4a2643416f97bca2711af728837Jeff Brown } 3118e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.alpha = WINDOW_ALPHA; 3128e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.gravity = Gravity.TOP | Gravity.LEFT; 3138e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.setTitle(mName); 3148e006e629800b4a2643416f97bca2711af728837Jeff Brown 3158e006e629800b4a2643416f97bca2711af728837Jeff Brown mGestureDetector = new GestureDetector(mContext, mOnGestureListener); 3168e006e629800b4a2643416f97bca2711af728837Jeff Brown mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener); 3178e006e629800b4a2643416f97bca2711af728837Jeff Brown 3188e006e629800b4a2643416f97bca2711af728837Jeff Brown // Set the initial position and scale. 3198e006e629800b4a2643416f97bca2711af728837Jeff Brown // The position and scale will be clamped when the display is first shown. 3208e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ? 3218e006e629800b4a2643416f97bca2711af728837Jeff Brown 0 : mDefaultDisplayMetrics.widthPixels; 3228e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ? 3238e006e629800b4a2643416f97bca2711af728837Jeff Brown 0 : mDefaultDisplayMetrics.heightPixels; 3248e006e629800b4a2643416f97bca2711af728837Jeff Brown Log.d(TAG, mDefaultDisplayMetrics.toString()); 3258e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowScale = INITIAL_SCALE; 3268e006e629800b4a2643416f97bca2711af728837Jeff Brown 3278e006e629800b4a2643416f97bca2711af728837Jeff Brown // calculate and save initial settings 3288e006e629800b4a2643416f97bca2711af728837Jeff Brown updateWindowParams(); 3298e006e629800b4a2643416f97bca2711af728837Jeff Brown saveWindowParams(); 33057456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 33157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 3328e006e629800b4a2643416f97bca2711af728837Jeff Brown private void updateWindowParams() { 3338e006e629800b4a2643416f97bca2711af728837Jeff Brown float scale = mWindowScale * mLiveScale; 3348e006e629800b4a2643416f97bca2711af728837Jeff Brown scale = Math.min(scale, (float)mDefaultDisplayMetrics.widthPixels / mWidth); 3358e006e629800b4a2643416f97bca2711af728837Jeff Brown scale = Math.min(scale, (float)mDefaultDisplayMetrics.heightPixels / mHeight); 3368e006e629800b4a2643416f97bca2711af728837Jeff Brown scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale)); 3378e006e629800b4a2643416f97bca2711af728837Jeff Brown 3388e006e629800b4a2643416f97bca2711af728837Jeff Brown float offsetScale = (scale / mWindowScale - 1.0f) * 0.5f; 3398e006e629800b4a2643416f97bca2711af728837Jeff Brown int width = (int)(mWidth * scale); 3408e006e629800b4a2643416f97bca2711af728837Jeff Brown int height = (int)(mHeight * scale); 3418e006e629800b4a2643416f97bca2711af728837Jeff Brown int x = (int)(mWindowX + mLiveTranslationX - width * offsetScale); 3428e006e629800b4a2643416f97bca2711af728837Jeff Brown int y = (int)(mWindowY + mLiveTranslationY - height * offsetScale); 3438e006e629800b4a2643416f97bca2711af728837Jeff Brown x = Math.max(0, Math.min(x, mDefaultDisplayMetrics.widthPixels - width)); 3448e006e629800b4a2643416f97bca2711af728837Jeff Brown y = Math.max(0, Math.min(y, mDefaultDisplayMetrics.heightPixels - height)); 3458e006e629800b4a2643416f97bca2711af728837Jeff Brown 3468e006e629800b4a2643416f97bca2711af728837Jeff Brown if (DEBUG) { 3478e006e629800b4a2643416f97bca2711af728837Jeff Brown Log.d(TAG, "updateWindowParams: scale=" + scale 3488e006e629800b4a2643416f97bca2711af728837Jeff Brown + ", offsetScale=" + offsetScale 3498e006e629800b4a2643416f97bca2711af728837Jeff Brown + ", x=" + x + ", y=" + y 3508e006e629800b4a2643416f97bca2711af728837Jeff Brown + ", width=" + width + ", height=" + height); 35157456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 35257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 3538e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setScaleX(scale); 3548e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setScaleY(scale); 3558e006e629800b4a2643416f97bca2711af728837Jeff Brown 3568e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setTranslationX( 3578e006e629800b4a2643416f97bca2711af728837Jeff Brown (mWidth - mTextureView.getLayoutParams().width) * scale / 2); 3588e006e629800b4a2643416f97bca2711af728837Jeff Brown mTextureView.setTranslationY( 3598e006e629800b4a2643416f97bca2711af728837Jeff Brown (mHeight - mTextureView.getLayoutParams().height) * scale / 2); 3608e006e629800b4a2643416f97bca2711af728837Jeff Brown 3618e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.x = x; 3628e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.y = y; 3638e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.width = width; 3648e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowParams.height = height; 36557456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 36657456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 3678e006e629800b4a2643416f97bca2711af728837Jeff Brown private void saveWindowParams() { 3688e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowX = mWindowParams.x; 3698e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowY = mWindowParams.y; 3708e006e629800b4a2643416f97bca2711af728837Jeff Brown mWindowScale = mTextureView.getScaleX(); 3718e006e629800b4a2643416f97bca2711af728837Jeff Brown clearLiveState(); 37257456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 37357456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 3748e006e629800b4a2643416f97bca2711af728837Jeff Brown private void clearLiveState() { 3758e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveTranslationX = 0f; 3768e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveTranslationY = 0f; 3778e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveScale = 1.0f; 37857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 37957456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang 3808e006e629800b4a2643416f97bca2711af728837Jeff Brown private final DisplayManager.DisplayListener mDisplayListener = 3818e006e629800b4a2643416f97bca2711af728837Jeff Brown new DisplayManager.DisplayListener() { 3828e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 3838e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onDisplayAdded(int displayId) { 3848e006e629800b4a2643416f97bca2711af728837Jeff Brown } 3858e006e629800b4a2643416f97bca2711af728837Jeff Brown 3868e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 3878e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onDisplayChanged(int displayId) { 3888e006e629800b4a2643416f97bca2711af728837Jeff Brown if (displayId == mDefaultDisplay.getDisplayId()) { 3898e006e629800b4a2643416f97bca2711af728837Jeff Brown if (updateDefaultDisplayInfo()) { 3908e006e629800b4a2643416f97bca2711af728837Jeff Brown relayout(); 3918e006e629800b4a2643416f97bca2711af728837Jeff Brown } else { 3928e006e629800b4a2643416f97bca2711af728837Jeff Brown dismiss(); 3938e006e629800b4a2643416f97bca2711af728837Jeff Brown } 3948e006e629800b4a2643416f97bca2711af728837Jeff Brown } 3958e006e629800b4a2643416f97bca2711af728837Jeff Brown } 3968e006e629800b4a2643416f97bca2711af728837Jeff Brown 3978e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 3988e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onDisplayRemoved(int displayId) { 3998e006e629800b4a2643416f97bca2711af728837Jeff Brown if (displayId == mDefaultDisplay.getDisplayId()) { 4008e006e629800b4a2643416f97bca2711af728837Jeff Brown dismiss(); 4018e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4028e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4038e006e629800b4a2643416f97bca2711af728837Jeff Brown }; 4048e006e629800b4a2643416f97bca2711af728837Jeff Brown 4058e006e629800b4a2643416f97bca2711af728837Jeff Brown private final SurfaceTextureListener mSurfaceTextureListener = 4068e006e629800b4a2643416f97bca2711af728837Jeff Brown new SurfaceTextureListener() { 4078e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4088e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, 4098e006e629800b4a2643416f97bca2711af728837Jeff Brown int width, int height) { 4108e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mListener != null) { 4118e006e629800b4a2643416f97bca2711af728837Jeff Brown mListener.onWindowCreated(new Surface(surfaceTexture)); 4128e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4138e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4148e006e629800b4a2643416f97bca2711af728837Jeff Brown 4158e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4168e006e629800b4a2643416f97bca2711af728837Jeff Brown public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { 4178e006e629800b4a2643416f97bca2711af728837Jeff Brown if (mListener != null) { 4188e006e629800b4a2643416f97bca2711af728837Jeff Brown mListener.onWindowDestroyed(); 4198e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4208e006e629800b4a2643416f97bca2711af728837Jeff Brown return true; 4218e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4228e006e629800b4a2643416f97bca2711af728837Jeff Brown 4238e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4248e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, 4258e006e629800b4a2643416f97bca2711af728837Jeff Brown int width, int height) { 4268e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4278e006e629800b4a2643416f97bca2711af728837Jeff Brown 4288e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4298e006e629800b4a2643416f97bca2711af728837Jeff Brown public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { 4308e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4318e006e629800b4a2643416f97bca2711af728837Jeff Brown }; 4328e006e629800b4a2643416f97bca2711af728837Jeff Brown 4338e006e629800b4a2643416f97bca2711af728837Jeff Brown private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() { 4348e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4358e006e629800b4a2643416f97bca2711af728837Jeff Brown public boolean onTouch(View view, MotionEvent event) { 4368e006e629800b4a2643416f97bca2711af728837Jeff Brown // Work in screen coordinates. 4378e006e629800b4a2643416f97bca2711af728837Jeff Brown final float oldX = event.getX(); 4388e006e629800b4a2643416f97bca2711af728837Jeff Brown final float oldY = event.getY(); 4398e006e629800b4a2643416f97bca2711af728837Jeff Brown event.setLocation(event.getRawX(), event.getRawY()); 4408e006e629800b4a2643416f97bca2711af728837Jeff Brown 4418e006e629800b4a2643416f97bca2711af728837Jeff Brown mGestureDetector.onTouchEvent(event); 4428e006e629800b4a2643416f97bca2711af728837Jeff Brown mScaleGestureDetector.onTouchEvent(event); 4438e006e629800b4a2643416f97bca2711af728837Jeff Brown 4448e006e629800b4a2643416f97bca2711af728837Jeff Brown switch (event.getActionMasked()) { 4458e006e629800b4a2643416f97bca2711af728837Jeff Brown case MotionEvent.ACTION_UP: 4468e006e629800b4a2643416f97bca2711af728837Jeff Brown case MotionEvent.ACTION_CANCEL: 4478e006e629800b4a2643416f97bca2711af728837Jeff Brown saveWindowParams(); 4488e006e629800b4a2643416f97bca2711af728837Jeff Brown break; 4498e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4508e006e629800b4a2643416f97bca2711af728837Jeff Brown 4518e006e629800b4a2643416f97bca2711af728837Jeff Brown // Revert to window coordinates. 4528e006e629800b4a2643416f97bca2711af728837Jeff Brown event.setLocation(oldX, oldY); 4538e006e629800b4a2643416f97bca2711af728837Jeff Brown return true; 4548e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4558e006e629800b4a2643416f97bca2711af728837Jeff Brown }; 4568e006e629800b4a2643416f97bca2711af728837Jeff Brown 4578e006e629800b4a2643416f97bca2711af728837Jeff Brown private final GestureDetector.OnGestureListener mOnGestureListener = 4588e006e629800b4a2643416f97bca2711af728837Jeff Brown new GestureDetector.SimpleOnGestureListener() { 4598e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4608e006e629800b4a2643416f97bca2711af728837Jeff Brown public boolean onScroll(MotionEvent e1, MotionEvent e2, 4618e006e629800b4a2643416f97bca2711af728837Jeff Brown float distanceX, float distanceY) { 4628e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveTranslationX -= distanceX; 4638e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveTranslationY -= distanceY; 4648e006e629800b4a2643416f97bca2711af728837Jeff Brown relayout(); 4658e006e629800b4a2643416f97bca2711af728837Jeff Brown return true; 4668e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4678e006e629800b4a2643416f97bca2711af728837Jeff Brown }; 4688e006e629800b4a2643416f97bca2711af728837Jeff Brown 4698e006e629800b4a2643416f97bca2711af728837Jeff Brown private final ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = 4708e006e629800b4a2643416f97bca2711af728837Jeff Brown new ScaleGestureDetector.SimpleOnScaleGestureListener() { 4718e006e629800b4a2643416f97bca2711af728837Jeff Brown @Override 4728e006e629800b4a2643416f97bca2711af728837Jeff Brown public boolean onScale(ScaleGestureDetector detector) { 4738e006e629800b4a2643416f97bca2711af728837Jeff Brown mLiveScale *= detector.getScaleFactor(); 4748e006e629800b4a2643416f97bca2711af728837Jeff Brown relayout(); 4758e006e629800b4a2643416f97bca2711af728837Jeff Brown return true; 4768e006e629800b4a2643416f97bca2711af728837Jeff Brown } 4778e006e629800b4a2643416f97bca2711af728837Jeff Brown }; 47857456222f52fbfc1dcfb1b99030aad6acc02ad23Chong Zhang } 4794523ef115a83bf0f655dc58262bd156d7555c91bChong Zhang} 480