├── .gitattributes ├── .gitignore ├── Aladdin ├── .classpath ├── .project ├── .settings │ └── org.eclipse.core.resources.prefs ├── AndroidManifest.xml ├── lint.xml ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable-ldpi │ │ ├── bg_small.png │ │ └── pic.png │ ├── layout │ │ ├── aladdin_view.xml │ │ ├── custom_layout.xml │ │ └── float_window_layout.xml │ └── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── tochange │ └── yang │ └── floatladdin │ ├── LauncherActivity.java │ ├── aladdin │ ├── AbstractDrawGrid.java │ ├── AladdinAnimation.java │ ├── AladdinDrawGrid.java │ ├── MainView.java │ └── SettingLayoutActivity.java │ └── floatwindow │ ├── FloatWindowCustomView.java │ ├── FloatWindowManager.java │ └── FloatWindowService.java ├── FloatWindowAladdin.apk ├── NoActivityAladdin └── Aladdin │ ├── .classpath │ ├── .project │ ├── .settings │ └── org.eclipse.core.resources.prefs │ ├── AndroidManifest.xml │ ├── lint.xml │ ├── proguard-project.txt │ ├── project.properties │ ├── res │ ├── drawable-ldpi │ │ ├── bg_small.png │ │ └── pic.png │ ├── layout │ │ ├── aladdin_view.xml │ │ ├── custom_layout.xml │ │ └── float_window_layout.xml │ └── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── src │ └── com │ └── tochange │ └── yang │ └── floatladdin │ ├── LauncherActivity.java │ ├── aladdin │ ├── AbstractDrawGrid.java │ ├── AladdinAnimation.java │ ├── AladdinDrawGrid.java │ └── MainView.java │ └── floatwindow │ ├── FloatWindowCustomView.java │ ├── FloatWindowManager.java │ └── FloatWindowService.java ├── README.md ├── aa.gif └── mac.jpg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | -------------------------------------------------------------------------------- /Aladdin/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Aladdin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | FloatWindowAladdin 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /Aladdin/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Wed May 28 15:12:38 CST 2014 2 | eclipse.preferences.version=1 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /Aladdin/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Aladdin/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Aladdin/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /Aladdin/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-8 15 | android.library.reference.1=../../../Savigation/trunk/lib 16 | -------------------------------------------------------------------------------- /Aladdin/res/drawable-ldpi/bg_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/Aladdin/res/drawable-ldpi/bg_small.png -------------------------------------------------------------------------------- /Aladdin/res/drawable-ldpi/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/Aladdin/res/drawable-ldpi/pic.png -------------------------------------------------------------------------------- /Aladdin/res/layout/aladdin_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 25 | 26 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Aladdin/res/layout/custom_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 21 | 22 | 30 | 31 | 39 | 40 | 46 | 47 | 48 | 55 | 56 | 61 | 62 | 71 | 72 | 73 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Aladdin/res/layout/float_window_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Aladdin/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /Aladdin/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Aladdin 5 | Settings 6 | Hello world! 7 | 沿此动画 8 | 9 | -------------------------------------------------------------------------------- /Aladdin/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 24 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/LauncherActivity.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import com.tochange.yang.floatladdin.floatwindow.FloatWindowService; 8 | import com.tochange.yang.lib.Utils; 9 | import com.tochange.yang.lib.ui.ScreenLib; 10 | 11 | public class LauncherActivity extends Activity { 12 | 13 | public static boolean IS_TABLTE = false;//not final type! 14 | public static final boolean DEBUG_MODE = false; 15 | public static final String KEY_X = "x"; 16 | public static final String KEY_Y = "y"; 17 | public static final String KEY_IMAGE = "image"; 18 | public static final int MAGIC_VERTICAL = 15; 19 | public static final int ANIMATION_TIME_SHORT = 600; 20 | public static final int ANIMATION_TIME_LONG = 2000; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | Intent intent = new Intent(LauncherActivity.this, FloatWindowService.class); 26 | startService(intent); 27 | if(ScreenLib.isTabletDevice(this)){ 28 | IS_TABLTE = true; 29 | } 30 | finish(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/aladdin/AbstractDrawGrid.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | //import com.tochange.yang.lib.log; 4 | 5 | public abstract class AbstractDrawGrid 6 | { 7 | 8 | public static final int VERTICAL_OFFSET = 15; 9 | 10 | protected int mHorizontalSplit; 11 | 12 | protected int mVerticalSplit; 13 | 14 | protected int mBmpWidth = -1; 15 | 16 | protected int mBmpHeight = -1; 17 | 18 | protected final float[] mVertices; 19 | 20 | public AbstractDrawGrid(int width, int height) 21 | { 22 | mHorizontalSplit = width; 23 | mVerticalSplit = height; 24 | mVertices = new float[(mHorizontalSplit + 1) * (mVerticalSplit + 1) * 2]; 25 | } 26 | 27 | public float[] getVertices() 28 | { 29 | return mVertices; 30 | } 31 | 32 | public int getWidth() 33 | { 34 | return mHorizontalSplit; 35 | } 36 | 37 | public int getHeight() 38 | { 39 | return mVerticalSplit; 40 | } 41 | 42 | public static void setXY(float[] array, int index, float x, float y) 43 | { 44 | array[index * 2 + 0] = x; 45 | array[index * 2 + 1] = y; 46 | } 47 | 48 | public void setBitmapSize(int w, int h) 49 | { 50 | mBmpWidth = w; 51 | mBmpHeight = h; 52 | } 53 | 54 | public abstract void buildPaths(float endX, float endY); 55 | 56 | public abstract void buildMeshes(int index); 57 | 58 | public void buildMeshes(float w, float h) 59 | { 60 | int index = 0; 61 | for (int y = 0; y <= mVerticalSplit; y++) 62 | { 63 | float fy = y * h / mVerticalSplit + VERTICAL_OFFSET; 64 | for (int x = 0; x <= mHorizontalSplit; x++) 65 | { 66 | float fx = x * w / mHorizontalSplit; 67 | setXY(mVertices, index, fx, fy); 68 | index++; 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/aladdin/AladdinAnimation.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import com.tochange.yang.lib.log; 4 | 5 | import android.view.animation.Animation; 6 | import android.view.animation.Interpolator; 7 | import android.view.animation.Transformation; 8 | 9 | public class AladdinAnimation extends Animation 10 | { 11 | 12 | public interface IAnimationUpdateListener 13 | { 14 | public void onAnimUpdate(int index); 15 | } 16 | 17 | private int mFromIndex; 18 | 19 | private int mEndIndex; 20 | 21 | private boolean mReverse; 22 | 23 | private IAnimationUpdateListener mListener; 24 | 25 | public AladdinAnimation(int fromIndex, int endIndex, boolean reverse, 26 | IAnimationUpdateListener listener) 27 | { 28 | mFromIndex = fromIndex; 29 | mEndIndex = endIndex; 30 | mReverse = reverse; 31 | mListener = listener; 32 | } 33 | 34 | public boolean getTransformation(long currentTime, 35 | Transformation outTransformation) 36 | { 37 | return super.getTransformation(currentTime, outTransformation); 38 | } 39 | 40 | int lastTimeIndex; 41 | 42 | @Override 43 | protected void applyTransformation(float interpolatedTime, Transformation t) 44 | { 45 | Interpolator interpolator = this.getInterpolator(); 46 | if (null != interpolator) 47 | { 48 | float value = interpolator.getInterpolation(interpolatedTime); 49 | interpolatedTime = value; 50 | } 51 | // log.e(""+(mReverse = true)); 52 | if (mReverse) 53 | interpolatedTime = 1.0f - interpolatedTime; 54 | 55 | int currentIndex = (int) (mFromIndex + (mEndIndex - mFromIndex) 56 | * interpolatedTime); 57 | if (currentIndex == lastTimeIndex) 58 | return; 59 | lastTimeIndex = currentIndex; 60 | 61 | if (null != mListener) 62 | mListener.onAnimUpdate(currentIndex); 63 | } 64 | } -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/aladdin/AladdinDrawGrid.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import com.tochange.yang.lib.log; 4 | 5 | import android.graphics.Path; 6 | import android.graphics.PathMeasure; 7 | 8 | public class AladdinDrawGrid extends AbstractDrawGrid 9 | { 10 | private Path mFirstPath; 11 | 12 | private Path mSecondPath; 13 | 14 | private PathMeasure mFirstPathMeasure; 15 | 16 | private PathMeasure mSecondPathMeasure; 17 | 18 | public AladdinDrawGrid(int width, int height) 19 | { 20 | super(width, height); 21 | // log.e(""); 22 | mFirstPath = new Path(); 23 | mSecondPath = new Path(); 24 | mFirstPathMeasure = new PathMeasure(); 25 | mSecondPathMeasure = new PathMeasure(); 26 | } 27 | 28 | @Override 29 | public void buildPaths(float endX, float endY) 30 | { 31 | 32 | if (mBmpWidth <= 0 || mBmpHeight <= 0) 33 | { 34 | throw new IllegalArgumentException( 35 | "Bitmap size must be > 0, did you call setBitmapSize(int, int) method?"); 36 | } 37 | mFirstPathMeasure.setPath(mFirstPath, false); 38 | mSecondPathMeasure.setPath(mSecondPath, false); 39 | 40 | float w = mBmpWidth; 41 | float h = mBmpHeight; 42 | 43 | mFirstPath.reset(); 44 | mSecondPath.reset(); 45 | 46 | mFirstPath.moveTo(0, VERTICAL_OFFSET);// start point of bezier 47 | mSecondPath.moveTo(w, VERTICAL_OFFSET); 48 | // mFirstPath.lineTo(0, h + VERTICAL_OFFSET);//line to the position 49 | // mSecondPath.lineTo(w, h + VERTICAL_OFFSET); 50 | 51 | mFirstPath.cubicTo(0, 6 * (endY + VERTICAL_OFFSET) / 12, endX / 2 + 30, 52 | 5 * (endY + VERTICAL_OFFSET) / 12, endX - 30, endY); 53 | mSecondPath.cubicTo(endX / 2, (endY + VERTICAL_OFFSET) / 4, endX, 54 | 2 * (endY + VERTICAL_OFFSET) / 3, endX - 10, endY); 55 | } 56 | 57 | @Override 58 | public void buildMeshes(int timeIndex) 59 | { 60 | 61 | if (mBmpWidth <= 0 || mBmpHeight <= 0) 62 | { 63 | throw new IllegalArgumentException( 64 | "Bitmap size must be > 0, did you call setBitmapSize(int, int) method?"); 65 | } 66 | mFirstPathMeasure.setPath(mFirstPath, false); 67 | mSecondPathMeasure.setPath(mSecondPath, false); 68 | 69 | int index = 0; 70 | float[] pos1 = { 0.0f, 0.0f }; 71 | float[] pos2 = { 0.0f, 0.0f }; 72 | 73 | // all length of the curve 74 | float firstLen = mFirstPathMeasure.getLength(); 75 | float secondLen = mSecondPathMeasure.getLength(); 76 | 77 | float len1 = firstLen / mVerticalSplit; 78 | float len2 = secondLen / mVerticalSplit; 79 | 80 | float firstPointDist = timeIndex * len1; 81 | float secondPointDist = timeIndex * len2; 82 | float height = mBmpHeight; 83 | 84 | mFirstPathMeasure.getPosTan(firstPointDist, pos1, null); 85 | mFirstPathMeasure.getPosTan(firstPointDist + height, pos2, null); 86 | 87 | float x1 = pos1[0]; 88 | float x2 = pos2[0]; 89 | float y1 = pos1[1]; 90 | float y2 = pos2[1]; 91 | float firstDist = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) 92 | * (y1 - y2)); 93 | float firstSplitDist = firstDist / mVerticalSplit; 94 | 95 | mSecondPathMeasure.getPosTan(secondPointDist, pos1, null); 96 | mSecondPathMeasure.getPosTan(secondPointDist + height, pos2, null); 97 | x1 = pos1[0]; 98 | x2 = pos2[0]; 99 | y1 = pos1[1]; 100 | y2 = pos2[1]; 101 | 102 | float secondDist = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) 103 | * (y1 - y2)); 104 | float secondSplitDist = secondDist / mVerticalSplit; 105 | 106 | for (int y = 0; y <= mVerticalSplit; y++) 107 | { 108 | mFirstPathMeasure.getPosTan(y * firstSplitDist + firstPointDist, 109 | pos1, null); 110 | mSecondPathMeasure.getPosTan(y * secondSplitDist + secondPointDist, 111 | pos2, null); 112 | 113 | float fx1 = pos1[0]; 114 | float fx2 = pos2[0]; 115 | float fy1 = pos1[1]; 116 | float fy2 = pos2[1]; 117 | 118 | float dy = fy2 - fy1; 119 | float dx = fx2 - fx1; 120 | 121 | // horizon,mHorizontalSplit pixels 122 | for (int x = 0; x <= mHorizontalSplit; x++, index++) 123 | { 124 | float fx = dx * x / mHorizontalSplit; 125 | float fy = dy * x / mHorizontalSplit; 126 | mVertices[index * 2 + 0] = fx + fx1; 127 | mVertices[index * 2 + 1] = fy + fy1; 128 | } 129 | } 130 | } 131 | 132 | public Path[] getPaths() 133 | { 134 | return new Path[] { mFirstPath, mSecondPath }; 135 | } 136 | } -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/aladdin/MainView.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuff.Mode; 11 | import android.graphics.PorterDuffXfermode; 12 | import android.util.AttributeSet; 13 | import android.view.MotionEvent; 14 | import android.view.View; 15 | import android.view.animation.Animation; 16 | import android.view.animation.Animation.AnimationListener; 17 | 18 | import com.tochange.yang.floatladdin.aladdin.AladdinDrawGrid; 19 | import com.tochange.yang.floatladdin.LauncherActivity; 20 | import com.tochange.yang.floatladdin.R; 21 | import com.tochange.yang.lib.log; 22 | 23 | public class MainView extends View 24 | { 25 | 26 | private static final int HORIZONTAL_SPLIT = 40; 27 | 28 | private static final int VERTICAL_SPLIT = 40; 29 | 30 | private Bitmap mBitmap; 31 | 32 | private Paint mPaint; 33 | 34 | private float[] mInhalePoint; 35 | 36 | private SettingLayoutActivity mMainActivity; 37 | 38 | private boolean clearCanvas = true; 39 | 40 | private AladdinDrawGrid mAladdinDrawGrid; 41 | 42 | public MainView(Context context, AttributeSet attrs) 43 | { 44 | super(context, attrs); 45 | mPaint = new Paint(); 46 | mInhalePoint = new float[] { 0, 0 }; 47 | mAladdinDrawGrid = new AladdinDrawGrid(HORIZONTAL_SPLIT, VERTICAL_SPLIT); 48 | } 49 | 50 | @Override 51 | public boolean onTouchEvent(MotionEvent event) 52 | { 53 | return true; 54 | } 55 | 56 | @Override 57 | protected void onSizeChanged(int w, int h, int oldw, int oldh) 58 | { 59 | super.onSizeChanged(w, h, oldw, oldh); 60 | log.e(""); 61 | buildPaths(w, h); 62 | // not need original image,yangxj@20140723 63 | // float bitmapWidth = mBitmap.getWidth(); 64 | // float bitmapHeight = mBitmap.getHeight(); 65 | // mAladdinDrawGrid.buildMeshes(bitmapWidth, bitmapHeight); 66 | } 67 | 68 | private void buildPaths(float endX, float endY) 69 | { 70 | mInhalePoint[0] = endX; 71 | mInhalePoint[1] = endY; 72 | mAladdinDrawGrid.buildPaths(endX, endY); 73 | } 74 | 75 | private boolean clearCanvas(Canvas canvas) 76 | { 77 | Paint paint = new Paint(); 78 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 79 | canvas.drawPaint(paint); 80 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 81 | log.e("clearing canvas"); 82 | return true; 83 | } 84 | 85 | public boolean startAnimation(boolean reverse, 86 | SettingLayoutActivity mainActivity) 87 | { 88 | if (mainActivity != null) 89 | mMainActivity = mainActivity; 90 | log.e("will clear canvas"); 91 | clearCanvas = true; 92 | startAnimationImp(reverse); 93 | return true; 94 | } 95 | 96 | private void startAnimationImp(boolean reverse) 97 | { 98 | Animation anim = this.getAnimation(); 99 | if (null != anim && !anim.hasEnded()) 100 | return; 101 | final AladdinAnimation animation = new AladdinAnimation(0, 102 | VERTICAL_SPLIT + 1, reverse, 103 | new AladdinAnimation.IAnimationUpdateListener() { 104 | @Override 105 | public void onAnimUpdate(int index) 106 | { 107 | log.e("build-" + (index) + ""); 108 | mAladdinDrawGrid.buildMeshes(index); 109 | invalidate(); 110 | } 111 | }); 112 | 113 | if (null != animation) 114 | { 115 | setAnimationTimeAndListener(animation); 116 | startAnimation(animation); 117 | } 118 | } 119 | 120 | @Override 121 | protected void onDraw(Canvas canvas) 122 | { 123 | if (clearCanvas && clearCanvas(canvas)) 124 | { 125 | clearCanvas = false; 126 | return; 127 | } 128 | log.e(""); 129 | canvas.drawBitmapMesh(mBitmap, mAladdinDrawGrid.getWidth(), 130 | mAladdinDrawGrid.getHeight(), mAladdinDrawGrid.getVertices(), 131 | 0, null, 0, mPaint); 132 | 133 | if (LauncherActivity.DEBUG_MODE) 134 | { 135 | setTextAndPointPaint(mPaint); 136 | canvas.drawTextOnPath( 137 | this.getResources().getString(R.string.path_words), 138 | mAladdinDrawGrid.getPaths()[1], 0, 0, mPaint); 139 | canvas.drawPoints(mAladdinDrawGrid.getVertices(), mPaint); 140 | 141 | setPathPaint(mPaint); 142 | Path[] paths = mAladdinDrawGrid.getPaths(); 143 | for (Path path : paths) 144 | canvas.drawPath(path, mPaint); 145 | } 146 | } 147 | 148 | private void setPathPaint(Paint mPaint2) 149 | { 150 | mPaint.setColor(Color.CYAN); 151 | mPaint.setStrokeWidth(1); 152 | mPaint.setAntiAlias(true); 153 | mPaint.setStyle(Paint.Style.STROKE); 154 | 155 | } 156 | 157 | private void setTextAndPointPaint(Paint mPaint) 158 | { 159 | mPaint.setColor(Color.MAGENTA); 160 | mPaint.setStyle(Paint.Style.FILL); 161 | mPaint.setTextAlign(Paint.Align.CENTER); 162 | mPaint.setTextSize(25); 163 | 164 | } 165 | 166 | public void setBitmap(Bitmap bitmap) 167 | { 168 | if (bitmap != null) 169 | { 170 | mBitmap = bitmap; 171 | mAladdinDrawGrid.setBitmapSize(mBitmap.getWidth(), 172 | mBitmap.getHeight()); 173 | } 174 | } 175 | 176 | private void setAnimationTimeAndListener(AladdinAnimation animation) 177 | { 178 | animation 179 | .setDuration(LauncherActivity.DEBUG_MODE ? LauncherActivity.ANIMATION_TIME_LONG 180 | : LauncherActivity.ANIMATION_TIME_SHORT); 181 | animation.setAnimationListener(new AnimationListener() { 182 | 183 | @Override 184 | public void onAnimationStart(Animation animation) 185 | { 186 | } 187 | 188 | @Override 189 | public void onAnimationRepeat(Animation animation) 190 | { 191 | } 192 | 193 | @Override 194 | public void onAnimationEnd(Animation animation) 195 | { 196 | if (mMainActivity != null) 197 | mMainActivity.finish(); 198 | } 199 | }); 200 | } 201 | } -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/aladdin/SettingLayoutActivity.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.os.Bundle; 7 | import android.widget.LinearLayout.LayoutParams; 8 | import android.widget.TextView; 9 | 10 | import com.tochange.yang.floatladdin.LauncherActivity; 11 | import com.tochange.yang.floatladdin.R; 12 | 13 | public class SettingLayoutActivity extends Activity 14 | { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) 18 | { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.aladdin_view); 21 | 22 | final MainView mainView = (MainView) findViewById(R.id.view); 23 | setParameter(mainView); 24 | mainView.startAnimation(false, this); 25 | } 26 | 27 | private void setParameter(MainView mainView) 28 | { 29 | Intent i = getIntent(); 30 | 31 | setLeftMargin(i.getIntExtra(LauncherActivity.KEY_X, -1)); 32 | setTopMargin(mainView, i.getIntExtra(LauncherActivity.KEY_Y, -1)); 33 | mainView.setBitmap((Bitmap) (i 34 | .getParcelableExtra(LauncherActivity.KEY_IMAGE))); 35 | } 36 | 37 | private void setTopMargin(MainView mainView, int y) 38 | { 39 | LayoutParams lp = (LayoutParams) mainView.getLayoutParams(); 40 | // lp.leftMargin = x; 41 | lp.topMargin = y - LauncherActivity.MAGIC_VERTICAL; 42 | mainView.setLayoutParams(lp); 43 | 44 | } 45 | 46 | private void setLeftMargin(int x) 47 | { 48 | TextView tv = (TextView) findViewById(R.id.space_h); 49 | LayoutParams lpp = (LayoutParams) tv.getLayoutParams(); 50 | lpp.width = x; 51 | lpp.height = 1; 52 | tv.setLayoutParams(lpp); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowCustomView.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.view.LayoutInflater; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.view.WindowManager; 10 | import android.view.animation.Animation; 11 | import android.view.animation.ScaleAnimation; 12 | import android.widget.EditText; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import com.tochange.yang.floatladdin.LauncherActivity; 19 | import com.tochange.yang.floatladdin.R; 20 | import com.tochange.yang.floatladdin.aladdin.SettingLayoutActivity; 21 | import com.tochange.yang.lib.ui.BadgeView; 22 | import com.tochange.yang.lib.ui.Graphics; 23 | import com.tochange.yang.lib.ui.ScreenLib; 24 | import com.tochange.yang.lib.Utils; 25 | import com.tochange.yang.lib.log; 26 | 27 | public class FloatWindowCustomView extends LinearLayout 28 | { 29 | public static int windowViewWidth; 30 | 31 | public static int windowViewHeight; 32 | 33 | private WindowManager windowManager; 34 | 35 | private LinearLayout customWindowLayout; 36 | 37 | private WindowManager.LayoutParams mParams; 38 | 39 | private float xInScreen; 40 | 41 | private float yInScreen; 42 | 43 | private float xInView; 44 | 45 | private float yInView; 46 | 47 | private Context mContext; 48 | 49 | private OnClickListener mGetFocusClickListenrt = new OnClickListener() { 50 | 51 | @Override 52 | public void onClick(View v) 53 | { 54 | v.setFocusable(true); 55 | v.setFocusableInTouchMode(true); 56 | } 57 | }; 58 | 59 | public FloatWindowCustomView(final Context context) 60 | { 61 | super(context); 62 | mContext = context; 63 | windowManager = (WindowManager) context 64 | .getSystemService(Context.WINDOW_SERVICE); 65 | LayoutInflater.from(context) 66 | .inflate(R.layout.float_window_layout, this); 67 | customWindowLayout = (LinearLayout) findViewById(R.id.custom_layout); 68 | windowViewWidth = customWindowLayout.getLayoutParams().width; 69 | windowViewHeight = customWindowLayout.getLayoutParams().height; 70 | 71 | final int[] wh = getCustomWindowLayoutWidthAndHeight(customWindowLayout); 72 | setBadgeView(context, wh); 73 | setPercentView(context); 74 | setEditText(context); 75 | } 76 | 77 | private void setEditText(final Context context) 78 | { 79 | final EditText et = (EditText) findViewById(R.id.edittext); 80 | et.setOnFocusChangeListener(new OnFocusChangeListener() { 81 | 82 | @Override 83 | public void onFocusChange(View v, boolean hasFocus) 84 | { 85 | android.view.WindowManager.LayoutParams lp = (android.view.WindowManager.LayoutParams) FloatWindowCustomView.this 86 | .getLayoutParams(); 87 | String m; 88 | if (hasFocus) 89 | { 90 | m = "can"; 91 | lp.flags = 32; 92 | } 93 | else 94 | { 95 | m = "cann't"; 96 | lp.flags = 32 | 8; 97 | } 98 | FloatWindowCustomView.this.setLayoutParams(lp); 99 | Toast.makeText(context, m + " input.", 5000).show(); 100 | windowManager.updateViewLayout(FloatWindowCustomView.this, mParams); 101 | } 102 | }); 103 | et.setOnClickListener(mGetFocusClickListenrt); 104 | } 105 | 106 | private void setPercentView(Context context) 107 | { 108 | final TextView percentView = (TextView) findViewById(R.id.percent); 109 | percentView.setText(FloatWindowManager.getUsedPercentValue(context)); 110 | percentView.setOnClickListener(mGetFocusClickListenrt); 111 | } 112 | 113 | private void setBadgeView(final Context context, final int[] wh) 114 | { 115 | final ImageView view = (ImageView) findViewById(R.id.close); 116 | final BadgeView badge = new BadgeView(context, view); 117 | badge.setBadgePosition(wh[0] - view.getMeasuredHeight(), 0, 0, 0) 118 | .setBadgeBackgroundShape(BadgeView.BACKGROUND_SHAPE_RECTANGLE) 119 | .setText(" × "); 120 | badge.setTextSize(25); 121 | badge.setOnClickListener(new View.OnClickListener() { 122 | public void onClick(View v) 123 | { 124 | Intent i = new Intent(context, SettingLayoutActivity.class); 125 | i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 126 | 127 | int[] position = getPosition(wh); 128 | i.putExtra(LauncherActivity.KEY_X, position[0]); 129 | i.putExtra(LauncherActivity.KEY_Y, position[1]); 130 | i.putExtra(LauncherActivity.KEY_IMAGE, 131 | Graphics.getBitmapFromView(FloatWindowCustomView.this)); 132 | setButtonPressedEffect(badge); 133 | context.startActivity(i); 134 | } 135 | 136 | private void setButtonPressedEffect(BadgeView badge) 137 | { 138 | Animation a = new ScaleAnimation(1, 1.2F, 1, 1.2F, 139 | Animation.RELATIVE_TO_SELF, 0.8f, 140 | Animation.RELATIVE_TO_SELF, 0.8f); 141 | a.setDuration(100); 142 | badge.setBackgroundColor(Color.parseColor("#c00000")); 143 | badge.startAnimation(a); 144 | // if (!LauncherActivity.DEBUG_MODE) 145 | // Utils.vibrate(context); 146 | } 147 | 148 | private int[] getPosition(int[] wh) 149 | { 150 | int maxX = windowManager.getDefaultDisplay().getWidth() - wh[0]; 151 | int x = mParams.x > maxX ? maxX : mParams.x; 152 | 153 | int maxY = windowManager.getDefaultDisplay().getHeight() 154 | - wh[1]; 155 | int magic = LauncherActivity.IS_TABLTE ? 0 : 2; 156 | int y = mParams.y > maxY ? maxY - magic 157 | * LauncherActivity.MAGIC_VERTICAL : mParams.y; 158 | y = y > 0 ? y : 0; 159 | 160 | int[] ret = { x, y }; 161 | return ret; 162 | } 163 | }); 164 | badge.show(); 165 | 166 | } 167 | 168 | private int[] getCustomWindowLayoutWidthAndHeight( 169 | LinearLayout customWindowLayout2) 170 | { 171 | int widthMeasureSpec, heightMeasureSpec; 172 | widthMeasureSpec = heightMeasureSpec = View.MeasureSpec 173 | .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 174 | customWindowLayout.measure(widthMeasureSpec, heightMeasureSpec); 175 | int w = customWindowLayout.getMeasuredWidth(); 176 | int h = customWindowLayout.getMeasuredHeight(); 177 | int[] ret = { w, h }; 178 | return ret; 179 | } 180 | 181 | @Override 182 | public boolean onTouchEvent(MotionEvent event) 183 | { 184 | switch (event.getAction()) 185 | { 186 | 187 | case MotionEvent.ACTION_DOWN: 188 | xInView = event.getX(); 189 | yInView = event.getY(); 190 | break; 191 | case MotionEvent.ACTION_MOVE: 192 | xInScreen = event.getRawX(); 193 | // if pad,then status bar will be in the bottom,can not minus 194 | // status bar height,but pad not ensure status bar in the bottom 195 | yInScreen = LauncherActivity.IS_TABLTE ? event.getRawY() 196 | : event.getRawY() - ScreenLib.getStatusBarHeight(mContext); 197 | updateViewStatus(); 198 | updateViewPosition(); 199 | break; 200 | case MotionEvent.ACTION_UP: 201 | break; 202 | default: 203 | break; 204 | } 205 | return true; 206 | } 207 | 208 | public void setParams(WindowManager.LayoutParams params) 209 | { 210 | mParams = params; 211 | } 212 | 213 | private void updateViewPosition() 214 | { 215 | mParams.x = (int) (xInScreen - xInView); 216 | mParams.y = (int) (yInScreen - yInView); 217 | windowManager.updateViewLayout(this, mParams); 218 | } 219 | 220 | private void updateViewStatus() 221 | { 222 | mParams.width = windowViewWidth; 223 | mParams.height = windowViewHeight; 224 | windowManager.updateViewLayout(this, mParams); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowManager.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | 7 | import com.tochange.yang.floatladdin.R; 8 | import com.tochange.yang.lib.log; 9 | 10 | 11 | import android.app.ActivityManager; 12 | import android.content.Context; 13 | import android.graphics.PixelFormat; 14 | import android.view.Gravity; 15 | import android.view.WindowManager; 16 | import android.view.WindowManager.LayoutParams; 17 | import android.widget.TextView; 18 | 19 | public class FloatWindowManager { 20 | 21 | private static LayoutParams customWindowParams; 22 | private static FloatWindowCustomView customWindow; 23 | private static WindowManager mWindowManager; 24 | private static ActivityManager mActivityManager; 25 | 26 | public static void createCustomWindow(Context context) { 27 | WindowManager windowManager = getWindowManager(context); 28 | int screenWidth = windowManager.getDefaultDisplay().getWidth(); 29 | int screenHeight = windowManager.getDefaultDisplay().getHeight(); 30 | if (customWindow == null) { 31 | customWindow = new FloatWindowCustomView(context); 32 | if (customWindowParams == null) { 33 | customWindowParams = new LayoutParams(); 34 | customWindowParams.type = LayoutParams.TYPE_SYSTEM_ALERT; 35 | customWindowParams.format = PixelFormat.RGBA_8888; 36 | customWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL 37 | | LayoutParams.FLAG_NOT_FOCUSABLE; 38 | customWindowParams.gravity = Gravity.LEFT | Gravity.TOP; 39 | customWindowParams.width = FloatWindowCustomView.windowViewWidth; 40 | customWindowParams.height = FloatWindowCustomView.windowViewHeight; 41 | customWindowParams.x = screenWidth / 4; 42 | customWindowParams.y = screenHeight / 3; 43 | } 44 | customWindow.setParams(customWindowParams); 45 | windowManager.addView(customWindow, customWindowParams); 46 | } 47 | } 48 | 49 | public static void removeCustomWindow(Context context) { 50 | if (customWindow != null) { 51 | WindowManager windowManager = getWindowManager(context); 52 | windowManager.removeView(customWindow); 53 | customWindow = null; 54 | } 55 | } 56 | 57 | public static void updateUsedPercent(Context context) { 58 | if (customWindow != null) { 59 | TextView percentView = (TextView) customWindow 60 | .findViewById(R.id.percent); 61 | percentView.setText(getUsedPercentValue(context)); 62 | } 63 | } 64 | 65 | public static boolean isWindowShowing() { 66 | return customWindow != null; 67 | } 68 | 69 | private static WindowManager getWindowManager(Context context) { 70 | if (mWindowManager == null) { 71 | mWindowManager = (WindowManager) context 72 | .getSystemService(Context.WINDOW_SERVICE); 73 | } 74 | return mWindowManager; 75 | } 76 | 77 | private static ActivityManager getActivityManager(Context context) { 78 | if (mActivityManager == null) { 79 | mActivityManager = (ActivityManager) context 80 | .getSystemService(Context.ACTIVITY_SERVICE); 81 | } 82 | return mActivityManager; 83 | } 84 | 85 | public static String getUsedPercentValue(Context context) { 86 | String dir = "/proc/meminfo"; 87 | try { 88 | FileReader fr = new FileReader(dir); 89 | BufferedReader br = new BufferedReader(fr, 2048); 90 | String memoryLine = br.readLine(); 91 | String subMemoryLine = memoryLine.substring(memoryLine 92 | .indexOf("MemTotal:")); 93 | br.close(); 94 | long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll( 95 | "\\D+", "")); 96 | long availableSize = getAvailableMemory(context) / 1024; 97 | int percent = (int) ((totalMemorySize - availableSize) 98 | / (float) totalMemorySize * 100); 99 | return percent + "%"; 100 | } catch (IOException e) { 101 | e.printStackTrace(); 102 | } 103 | return "floating windows"; 104 | } 105 | 106 | private static long getAvailableMemory(Context context) { 107 | ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); 108 | getActivityManager(context).getMemoryInfo(mi); 109 | return mi.availMem; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowService.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Timer; 6 | import java.util.TimerTask; 7 | 8 | import android.app.ActivityManager; 9 | import android.app.ActivityManager.RunningTaskInfo; 10 | import android.app.Service; 11 | import android.content.Context; 12 | import android.content.Intent; 13 | import android.content.pm.PackageManager; 14 | import android.content.pm.ResolveInfo; 15 | import android.os.Handler; 16 | import android.os.IBinder; 17 | 18 | public class FloatWindowService extends Service { 19 | 20 | private Handler handler = new Handler(); 21 | private Timer timer; 22 | 23 | @Override 24 | public IBinder onBind(Intent intent) { 25 | return null; 26 | } 27 | 28 | @Override 29 | public int onStartCommand(Intent intent, int flags, int startId) { 30 | // 开启定时器,每隔0.5秒刷新一次 31 | if (timer == null) { 32 | timer = new Timer(); 33 | timer.scheduleAtFixedRate(new RefreshTask(), 0, 500); 34 | } 35 | return super.onStartCommand(intent, flags, startId); 36 | } 37 | 38 | @Override 39 | public void onDestroy() { 40 | super.onDestroy(); 41 | timer.cancel(); 42 | timer = null; 43 | } 44 | 45 | class RefreshTask extends TimerTask { 46 | 47 | @Override 48 | public void run() { 49 | // 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。 50 | if (isHome() && !FloatWindowManager.isWindowShowing()) { 51 | handler.post(new Runnable() { 52 | @Override 53 | public void run() { 54 | FloatWindowManager.createCustomWindow(getApplicationContext()); 55 | } 56 | }); 57 | } 58 | // 当前界面不是桌面,且有悬浮窗显示,则移除悬浮窗。 59 | else if (!isHome() && FloatWindowManager.isWindowShowing()) { 60 | handler.post(new Runnable() { 61 | @Override 62 | public void run() { 63 | FloatWindowManager.removeCustomWindow(getApplicationContext()); 64 | } 65 | }); 66 | } 67 | // 当前界面是桌面,且有悬浮窗显示,则更新内存数据。 68 | else if (isHome() && FloatWindowManager.isWindowShowing()) { 69 | handler.post(new Runnable() { 70 | @Override 71 | public void run() { 72 | FloatWindowManager.updateUsedPercent(getApplicationContext()); 73 | } 74 | }); 75 | } 76 | } 77 | 78 | } 79 | 80 | /** 81 | * 判断当前界面是否是桌面 82 | */ 83 | private boolean isHome() { 84 | ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 85 | List rti = mActivityManager.getRunningTasks(1); 86 | return getHomes().contains(rti.get(0).topActivity.getPackageName()); 87 | } 88 | 89 | /** 90 | * 获得属于桌面的应用的应用包名称 91 | * 92 | * @return 返回包含所有包名的字符串列表 93 | */ 94 | private List getHomes() { 95 | List names = new ArrayList(); 96 | PackageManager packageManager = this.getPackageManager(); 97 | Intent intent = new Intent(Intent.ACTION_MAIN); 98 | intent.addCategory(Intent.CATEGORY_HOME); 99 | List resolveInfo = packageManager.queryIntentActivities(intent, 100 | PackageManager.MATCH_DEFAULT_ONLY); 101 | for (ResolveInfo ri : resolveInfo) { 102 | names.add(ri.activityInfo.packageName); 103 | } 104 | return names; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /FloatWindowAladdin.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/FloatWindowAladdin.apk -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | NotActivityFloatWindowAladdin 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Wed May 28 15:12:38 CST 2014 2 | eclipse.preferences.version=1 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-8 15 | android.library.reference.1=../../../../lib/lib.git/trunk 16 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/drawable-ldpi/bg_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/NoActivityAladdin/Aladdin/res/drawable-ldpi/bg_small.png -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/drawable-ldpi/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/NoActivityAladdin/Aladdin/res/drawable-ldpi/pic.png -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/layout/aladdin_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/layout/custom_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 21 | 22 | 29 | 30 | 39 | 40 | 45 | 46 | 47 | 55 | 56 | 63 | 64 | 73 | 74 | 75 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/layout/float_window_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Aladdin 5 | Settings 6 | Hello world! 7 | 沿此动画 8 | 9 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/LauncherActivity.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import com.tochange.yang.floatladdin.floatwindow.FloatWindowService; 8 | import com.tochange.yang.lib.ui.ScreenLib; 9 | 10 | public class LauncherActivity extends Activity { 11 | 12 | public static final String KEY_X = "x"; 13 | public static final String KEY_Y = "y"; 14 | public static final String KEY_IMAGE = "image"; 15 | public static final String DELETED_BUTTON_TEXT_CONTENT = " × "; 16 | public static final int DELETED_BUTTON_TEXT_SIZE = 25 ; 17 | public static final int VERTICAL_OFFSET = 15; 18 | public static final int ANIMATION_TIME_SHORT = 600;//600 19 | public static final int ANIMATION_TIME_LONG = 5000;//2000 20 | public static final int ANIMATION_SPLIT_HORIZONTAL = 40; 21 | public static final int ANIMATION_SPLIT_VERTICAL = 40; 22 | public static final int BASE_SCREEN_WIDTH = 480; 23 | public static final float BASE_SCREEN_DENSITY = 1.5F; 24 | 25 | public static boolean DEBUG_MODE; 26 | public static boolean IS_TABLTE; 27 | public static int ANIMATION_TIME; 28 | public static int SCREEN_WIDTH; 29 | public static int SCREEN_HEIGHT; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | Intent intent = new Intent(LauncherActivity.this, FloatWindowService.class); 35 | startService(intent); 36 | if(ScreenLib.isTabletDevice(this)){ 37 | IS_TABLTE = true; 38 | } 39 | ANIMATION_TIME = DEBUG_MODE?ANIMATION_TIME_LONG:ANIMATION_TIME_SHORT; 40 | finish(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/aladdin/AbstractDrawGrid.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import com.tochange.yang.floatladdin.LauncherActivity; 4 | 5 | //import com.tochange.yang.lib.log; 6 | 7 | public abstract class AbstractDrawGrid 8 | { 9 | 10 | protected int mHorizontalSplit; 11 | 12 | protected int mVerticalSplit; 13 | 14 | protected int mBmpWidth = -1; 15 | 16 | protected int mBmpHeight = -1; 17 | 18 | protected final float[] mVertices; 19 | 20 | public AbstractDrawGrid(int width, int height) 21 | { 22 | mHorizontalSplit = width; 23 | mVerticalSplit = height; 24 | mVertices = new float[(mHorizontalSplit + 1) * (mVerticalSplit + 1) * 2]; 25 | } 26 | 27 | public float[] getVertices() 28 | { 29 | return mVertices; 30 | } 31 | 32 | public int getWidth() 33 | { 34 | return mHorizontalSplit; 35 | } 36 | 37 | public int getHeight() 38 | { 39 | return mVerticalSplit; 40 | } 41 | 42 | public static void setXY(float[] array, int index, float x, float y) 43 | { 44 | array[index * 2 + 0] = x; 45 | array[index * 2 + 1] = y; 46 | } 47 | 48 | public void setBitmapSize(int w, int h) 49 | { 50 | mBmpWidth = w; 51 | mBmpHeight = h; 52 | } 53 | 54 | public abstract void buildPaths(float endX, float endY); 55 | 56 | public abstract void buildMeshes(int index); 57 | 58 | public void buildMeshes(float w, float h) 59 | { 60 | int index = 0; 61 | for (int y = 0; y <= mVerticalSplit; y++) 62 | { 63 | float fy = y * h / mVerticalSplit + LauncherActivity.VERTICAL_OFFSET; 64 | for (int x = 0; x <= mHorizontalSplit; x++) 65 | { 66 | float fx = x * w / mHorizontalSplit; 67 | setXY(mVertices, index, fx, fy); 68 | index++; 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/aladdin/AladdinAnimation.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import com.tochange.yang.lib.log; 4 | 5 | import android.view.animation.Animation; 6 | import android.view.animation.Interpolator; 7 | import android.view.animation.Transformation; 8 | 9 | public class AladdinAnimation extends Animation 10 | { 11 | 12 | public interface IAnimationUpdateListener 13 | { 14 | public void onAnimUpdate(int index); 15 | } 16 | 17 | private int mFromIndex; 18 | 19 | private int mEndIndex; 20 | 21 | private boolean mReverse; 22 | 23 | private IAnimationUpdateListener mListener; 24 | 25 | public AladdinAnimation(int fromIndex, int endIndex, boolean reverse, 26 | IAnimationUpdateListener listener) 27 | { 28 | mFromIndex = fromIndex; 29 | mEndIndex = endIndex; 30 | mReverse = reverse; 31 | mListener = listener; 32 | } 33 | 34 | public boolean getTransformation(long currentTime, 35 | Transformation outTransformation) 36 | { 37 | return super.getTransformation(currentTime, outTransformation); 38 | } 39 | 40 | // not -1 but 0,because it will generate plenty of 0. 41 | int lastTimeIndex = 0; 42 | 43 | @Override 44 | protected void applyTransformation(float interpolatedTime, Transformation t) 45 | { 46 | Interpolator interpolator = this.getInterpolator(); 47 | if (null != interpolator) 48 | { 49 | float value = interpolator.getInterpolation(interpolatedTime); 50 | interpolatedTime = value; 51 | } 52 | 53 | if (mReverse) 54 | interpolatedTime = 1.0f - interpolatedTime; 55 | 56 | int currentIndex = (int) (mFromIndex + (mEndIndex - mFromIndex) 57 | * interpolatedTime); 58 | if (currentIndex == lastTimeIndex) 59 | return; 60 | lastTimeIndex = currentIndex; 61 | 62 | if (null != mListener) 63 | mListener.onAnimUpdate(currentIndex); 64 | } 65 | } -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/aladdin/AladdinDrawGrid.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import com.tochange.yang.floatladdin.LauncherActivity; 4 | import com.tochange.yang.lib.log; 5 | 6 | import android.graphics.Path; 7 | import android.graphics.PathMeasure; 8 | 9 | public class AladdinDrawGrid extends AbstractDrawGrid 10 | { 11 | private Path mFirstPath; 12 | 13 | private Path mSecondPath; 14 | 15 | private PathMeasure mFirstPathMeasure; 16 | 17 | private PathMeasure mSecondPathMeasure; 18 | 19 | public AladdinDrawGrid(int width, int height) 20 | { 21 | super(width, height); 22 | // log.e(""); 23 | mFirstPath = new Path(); 24 | mSecondPath = new Path(); 25 | mFirstPathMeasure = new PathMeasure(); 26 | mSecondPathMeasure = new PathMeasure(); 27 | } 28 | 29 | @Override 30 | public void buildPaths(float endX, float endY) 31 | { 32 | 33 | if (mBmpWidth <= 0 || mBmpHeight <= 0) 34 | { 35 | throw new IllegalArgumentException( 36 | "Bitmap size must be > 0, did you call setBitmapSize(int, int) method?"); 37 | } 38 | mFirstPathMeasure.setPath(mFirstPath, false); 39 | mSecondPathMeasure.setPath(mSecondPath, false); 40 | 41 | float w = mBmpWidth; 42 | float h = mBmpHeight; 43 | 44 | mFirstPath.reset(); 45 | mSecondPath.reset(); 46 | 47 | mFirstPath.moveTo(0, LauncherActivity.VERTICAL_OFFSET);// start point of bezier 48 | mSecondPath.moveTo(w, LauncherActivity.VERTICAL_OFFSET); 49 | // mFirstPath.lineTo(0, h + VERTICAL_OFFSET);//line to the position 50 | // mSecondPath.lineTo(w, h + VERTICAL_OFFSET); 51 | 52 | mFirstPath.cubicTo(0, 6 * (endY + LauncherActivity.VERTICAL_OFFSET) / 12, endX / 2 + 30, 53 | 5 * (endY + LauncherActivity.VERTICAL_OFFSET) / 12, endX - 30, endY); 54 | mSecondPath.cubicTo(endX / 2, (endY + LauncherActivity.VERTICAL_OFFSET) / 4, endX, 55 | 2 * (endY + LauncherActivity.VERTICAL_OFFSET) / 3, endX - 10, endY); 56 | } 57 | 58 | @Override 59 | public void buildMeshes(int timeIndex) 60 | { 61 | 62 | if (mBmpWidth <= 0 || mBmpHeight <= 0) 63 | { 64 | throw new IllegalArgumentException( 65 | "Bitmap size must be > 0, did you call setBitmapSize(int, int) method?"); 66 | } 67 | mFirstPathMeasure.setPath(mFirstPath, false); 68 | mSecondPathMeasure.setPath(mSecondPath, false); 69 | 70 | int index = 0; 71 | float[] pos1 = { 0.0f, 0.0f }; 72 | float[] pos2 = { 0.0f, 0.0f }; 73 | 74 | // all length of the curve 75 | float firstLen = mFirstPathMeasure.getLength(); 76 | float secondLen = mSecondPathMeasure.getLength(); 77 | 78 | float len1 = firstLen / mVerticalSplit; 79 | float len2 = secondLen / mVerticalSplit; 80 | 81 | float firstPointDist = timeIndex * len1; 82 | float secondPointDist = timeIndex * len2; 83 | float height = mBmpHeight; 84 | 85 | mFirstPathMeasure.getPosTan(firstPointDist, pos1, null); 86 | mFirstPathMeasure.getPosTan(firstPointDist + height, pos2, null); 87 | 88 | float x1 = pos1[0]; 89 | float x2 = pos2[0]; 90 | float y1 = pos1[1]; 91 | float y2 = pos2[1]; 92 | float firstDist = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) 93 | * (y1 - y2)); 94 | float firstSplitDist = firstDist / mVerticalSplit; 95 | 96 | mSecondPathMeasure.getPosTan(secondPointDist, pos1, null); 97 | mSecondPathMeasure.getPosTan(secondPointDist + height, pos2, null); 98 | x1 = pos1[0]; 99 | x2 = pos2[0]; 100 | y1 = pos1[1]; 101 | y2 = pos2[1]; 102 | 103 | float secondDist = (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) 104 | * (y1 - y2)); 105 | float secondSplitDist = secondDist / mVerticalSplit; 106 | 107 | for (int y = 0; y <= mVerticalSplit; y++) 108 | { 109 | mFirstPathMeasure.getPosTan(y * firstSplitDist + firstPointDist, 110 | pos1, null); 111 | mSecondPathMeasure.getPosTan(y * secondSplitDist + secondPointDist, 112 | pos2, null); 113 | 114 | float fx1 = pos1[0]; 115 | float fx2 = pos2[0]; 116 | float fy1 = pos1[1]; 117 | float fy2 = pos2[1]; 118 | 119 | float dy = fy2 - fy1; 120 | float dx = fx2 - fx1; 121 | 122 | // horizon,mHorizontalSplit pixels 123 | for (int x = 0; x <= mHorizontalSplit; x++, index++) 124 | { 125 | float fx = dx * x / mHorizontalSplit; 126 | float fy = dy * x / mHorizontalSplit; 127 | mVertices[index * 2 + 0] = fx + fx1; 128 | mVertices[index * 2 + 1] = fy + fy1; 129 | } 130 | } 131 | } 132 | 133 | public Path[] getPaths() 134 | { 135 | return new Path[] { mFirstPath, mSecondPath }; 136 | } 137 | } -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/aladdin/MainView.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.aladdin; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuff.Mode; 11 | import android.graphics.PorterDuffXfermode; 12 | import android.util.AttributeSet; 13 | import android.view.MotionEvent; 14 | import android.view.View; 15 | import android.view.animation.AlphaAnimation; 16 | import android.view.animation.Animation; 17 | import android.view.animation.Animation.AnimationListener; 18 | import android.view.animation.AnimationSet; 19 | 20 | import com.tochange.yang.floatladdin.LauncherActivity; 21 | import com.tochange.yang.floatladdin.R; 22 | import com.tochange.yang.floatladdin.floatwindow.FloatWindowService; 23 | import com.tochange.yang.lib.log; 24 | 25 | public class MainView extends View { 26 | 27 | private Bitmap mBitmap; 28 | 29 | private Paint mPaint; 30 | 31 | private float[] mInhalePoint; 32 | 33 | private boolean clearCanvas = true; 34 | 35 | private AladdinDrawGrid mAladdinDrawGrid; 36 | 37 | public MainView(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | mPaint = new Paint(); 40 | mInhalePoint = new float[] { 0, 0 }; 41 | mAladdinDrawGrid = new AladdinDrawGrid(LauncherActivity.ANIMATION_SPLIT_HORIZONTAL, LauncherActivity.ANIMATION_SPLIT_VERTICAL); 42 | } 43 | 44 | @Override 45 | public boolean onTouchEvent(MotionEvent event) { 46 | return true; 47 | } 48 | 49 | @Override 50 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 51 | super.onSizeChanged(w, h, oldw, oldh); 52 | log.d(""); 53 | buildPaths(w, h); 54 | // not need to draw the original image,yangxj@20140723 55 | // float bitmapWidth = mBitmap.getWidth(); 56 | // float bitmapHeight = mBitmap.getHeight(); 57 | // mAladdinDrawGrid.buildMeshes(bitmapWidth, bitmapHeight); 58 | } 59 | 60 | private void buildPaths(float endX, float endY) { 61 | mInhalePoint[0] = endX; 62 | mInhalePoint[1] = endY; 63 | mAladdinDrawGrid.buildPaths(endX, endY); 64 | } 65 | 66 | private boolean clearCanvas(Canvas canvas) { 67 | log.d("clearing canvas."); 68 | Paint paint = new Paint(); 69 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 70 | canvas.drawPaint(paint); 71 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC)); 72 | return true; 73 | } 74 | 75 | public boolean startAnimation(boolean reverse) { 76 | log.d("will clear canvas."); 77 | clearCanvas = true; 78 | invalidate();// add 79 | startAnimationImp(reverse); 80 | return true; 81 | } 82 | 83 | private void startAnimationImp(boolean reverse) { 84 | Animation anim = this.getAnimation(); 85 | if (null != anim && !anim.hasEnded()) 86 | return; 87 | AnimationSet animationSet = new AnimationSet(getContext(), null); 88 | 89 | final AladdinAnimation animation = new AladdinAnimation(0, 90 | LauncherActivity.ANIMATION_SPLIT_VERTICAL + 1, reverse, 91 | new AladdinAnimation.IAnimationUpdateListener() { 92 | @Override 93 | public void onAnimUpdate(int index) { 94 | // log.e("build-" + (index) + ""); 95 | mAladdinDrawGrid.buildMeshes(index); 96 | invalidate(); 97 | } 98 | }); 99 | 100 | if (null != animation) { 101 | setAnimationTimeAndListener(animation); 102 | animationSet.addAnimation(getAlphaAnimation()); 103 | animationSet.addAnimation(animation); 104 | startAnimation(animationSet); 105 | } 106 | } 107 | 108 | private Animation getAlphaAnimation() { 109 | Animation alphaAnimation = new AlphaAnimation(0, 1); 110 | alphaAnimation.setDuration(LauncherActivity.ANIMATION_TIME / 2); 111 | return alphaAnimation; 112 | } 113 | 114 | @Override 115 | protected void onDraw(Canvas canvas) { 116 | if (clearCanvas && clearCanvas(canvas)) { 117 | clearCanvas = false; 118 | return; 119 | } 120 | if (mBitmap == null && clearCanvas(canvas)) { 121 | return; 122 | } 123 | // log.e(""); 124 | if (LauncherActivity.DEBUG_MODE) { 125 | setTextAndPointPaint(mPaint); 126 | canvas.drawTextOnPath( 127 | this.getResources().getString(R.string.path_words), 128 | mAladdinDrawGrid.getPaths()[1], 0, 0, mPaint); 129 | canvas.drawPoints(mAladdinDrawGrid.getVertices(), mPaint); 130 | 131 | setPathPaint(mPaint); 132 | Path[] paths = mAladdinDrawGrid.getPaths(); 133 | for (Path path : paths) 134 | canvas.drawPath(path, mPaint); 135 | } 136 | canvas.drawBitmapMesh(mBitmap, mAladdinDrawGrid.getWidth(), 137 | mAladdinDrawGrid.getHeight(), mAladdinDrawGrid.getVertices(), 138 | 0, null, 0, mPaint); 139 | } 140 | 141 | private void setPathPaint(Paint mPaint2) { 142 | mPaint.setColor(Color.CYAN); 143 | mPaint.setStrokeWidth(1); 144 | mPaint.setAntiAlias(true); 145 | mPaint.setStyle(Paint.Style.STROKE); 146 | 147 | } 148 | 149 | private void setTextAndPointPaint(Paint mPaint) { 150 | mPaint.setColor(Color.MAGENTA); 151 | mPaint.setStyle(Paint.Style.FILL); 152 | mPaint.setTextAlign(Paint.Align.CENTER); 153 | mPaint.setTextSize(25); 154 | 155 | } 156 | 157 | public void setBitmap(Bitmap bitmap) { 158 | if (bitmap != null) { 159 | mBitmap = bitmap; 160 | mAladdinDrawGrid.setBitmapSize(mBitmap.getWidth(), 161 | mBitmap.getHeight()); 162 | } 163 | } 164 | 165 | private void setAnimationTimeAndListener(AladdinAnimation animation) { 166 | animation 167 | .setDuration(LauncherActivity.DEBUG_MODE ? LauncherActivity.ANIMATION_TIME_LONG 168 | : LauncherActivity.ANIMATION_TIME_SHORT); 169 | animation.setAnimationListener(new AnimationListener() { 170 | 171 | @Override 172 | public void onAnimationStart(Animation animation) { 173 | } 174 | 175 | @Override 176 | public void onAnimationRepeat(Animation animation) { 177 | } 178 | 179 | @Override 180 | public void onAnimationEnd(Animation animation) { 181 | FloatWindowService.mFloatWindowService.onDestroy(); 182 | System.exit(0); 183 | } 184 | }); 185 | } 186 | } -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowCustomView.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.util.DisplayMetrics; 7 | import android.view.LayoutInflater; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | import android.view.animation.AlphaAnimation; 12 | import android.view.animation.Animation; 13 | import android.view.animation.Animation.AnimationListener; 14 | import android.view.animation.ScaleAnimation; 15 | import android.widget.ImageView; 16 | import android.widget.LinearLayout; 17 | import android.widget.TextView; 18 | import android.widget.Toast; 19 | 20 | import com.tochange.yang.floatladdin.LauncherActivity; 21 | import com.tochange.yang.floatladdin.R; 22 | import com.tochange.yang.floatladdin.aladdin.MainView; 23 | import com.tochange.yang.lib.ui.BadgeView; 24 | import com.tochange.yang.lib.ui.ClearEditText; 25 | import com.tochange.yang.lib.ui.ScreenLib; 26 | import com.tochange.yang.lib.ui.Graphics; 27 | import com.tochange.yang.lib.Utils; 28 | import com.tochange.yang.lib.log; 29 | 30 | public class FloatWindowCustomView extends LinearLayout 31 | { 32 | private WindowManager windowManager; 33 | 34 | private LinearLayout mCustomWindowLayout; 35 | 36 | private WindowManager.LayoutParams mParams; 37 | 38 | private float xInScreen; 39 | 40 | private float yInScreen; 41 | 42 | private float xInView; 43 | 44 | private float yInView; 45 | 46 | private ClearEditText mClearEditText; 47 | 48 | private Context mContext; 49 | 50 | private OnClickListener mGetFocusClickListenr = new OnClickListener() { 51 | 52 | @Override 53 | public void onClick(View v) 54 | { 55 | v.setFocusable(true); 56 | v.setFocusableInTouchMode(true); 57 | if (v.getId() == R.id.percent) 58 | { 59 | if (mClearEditText.getText().toString().trim().equals("")) 60 | mClearEditText.startAnimation(mClearEditText 61 | .getShakeAnimation(5)); 62 | LauncherActivity.DEBUG_MODE = !LauncherActivity.DEBUG_MODE; 63 | } 64 | } 65 | }; 66 | 67 | AnimationListener mAnimationListener = new AnimationListener() { 68 | 69 | @Override 70 | public void onAnimationStart(Animation animation) 71 | { 72 | } 73 | 74 | @Override 75 | public void onAnimationRepeat(Animation animation) 76 | { 77 | } 78 | 79 | @Override 80 | public void onAnimationEnd(Animation animation) 81 | { 82 | FloatWindowCustomView.this.removeAllViews(); 83 | } 84 | }; 85 | 86 | public FloatWindowCustomView(final Context context) 87 | { 88 | super(context); 89 | mContext = context; 90 | windowManager = (WindowManager) context 91 | .getSystemService(Context.WINDOW_SERVICE); 92 | LayoutInflater.from(context) 93 | .inflate(R.layout.float_window_layout, this); 94 | mCustomWindowLayout = (LinearLayout) findViewById(R.id.custom_layout); 95 | final int[] wh = getCustomWindowLayoutWidthAndHeight(mCustomWindowLayout); 96 | setBadgeView(context, wh); 97 | setPercentView(context); 98 | setEditText(context); 99 | } 100 | 101 | private void setEditText(final Context context) 102 | { 103 | mClearEditText = (ClearEditText) findViewById(R.id.edittext); 104 | mClearEditText.setOnFocusChangeListener(new OnFocusChangeListener() { 105 | 106 | @Override 107 | public void onFocusChange(View v, boolean hasFocus) 108 | { 109 | android.view.WindowManager.LayoutParams lp = (android.view.WindowManager.LayoutParams) FloatWindowCustomView.this 110 | .getLayoutParams(); 111 | String m; 112 | if (hasFocus) 113 | { 114 | m = "can"; 115 | /* 116 | * LayoutParams.FLAG_NOT_TOUCH_MODAL | 117 | * LayoutParams.FLAG_NOT_FOCUSABLE | 118 | */ 119 | lp.flags = 32 | 262144; 120 | } 121 | else 122 | { 123 | m = "cann't"; 124 | /* 125 | * LayoutParams.FLAG_NOT_TOUCH_MODAL | 126 | * LayoutParams.FLAG_NOT_FOCUSABLE | 127 | * LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; 128 | */ 129 | lp.flags = 32 | 8 | 262144; 130 | } 131 | FloatWindowCustomView.this.setLayoutParams(lp); 132 | Toast.makeText(context, m + " input.", Toast.LENGTH_LONG) 133 | .show(); 134 | windowManager.updateViewLayout(FloatWindowCustomView.this, 135 | mParams); 136 | mClearEditText.setOnFocusChangeListenerCallBack(v, hasFocus); 137 | } 138 | }); 139 | mClearEditText.setOnClickListener(mGetFocusClickListenr); 140 | } 141 | 142 | private void setPercentView(Context context) 143 | { 144 | final TextView percentView = (TextView) findViewById(R.id.percent); 145 | percentView.setText(FloatWindowManager.getUsedPercentValue(context)); 146 | percentView.setOnClickListener(mGetFocusClickListenr); 147 | } 148 | 149 | private void setBadgeView(final Context context, final int[] wh) 150 | { 151 | final ImageView view = (ImageView) findViewById(R.id.close); 152 | final BadgeView badge = new BadgeView(context, view); 153 | badge.setBadgePosition(wh[0] - view.getMeasuredHeight(), 0, 0, 0) 154 | .setBadgeBackgroundShape(BadgeView.BACKGROUND_SHAPE_RECTANGLE) 155 | .setText(LauncherActivity.DELETED_BUTTON_TEXT_CONTENT); 156 | badge.setTextSize(LauncherActivity.DELETED_BUTTON_TEXT_SIZE); 157 | badge.setOnClickListener(new View.OnClickListener() { 158 | public void onClick(View v) 159 | { 160 | setButtonPressedEffect(badge); 161 | View rootView = LayoutInflater.from(context).inflate( 162 | R.layout.aladdin_view, null); 163 | View child = FloatWindowCustomView.this.getFocusedChild(); 164 | child.startAnimation(getAlphaAnimation(LauncherActivity.ANIMATION_TIME / 2)); 165 | Bitmap b = Graphics.getBitmapFromView(child); 166 | int[] position = getPosition(wh); 167 | MainView mainView = (MainView) rootView.findViewById(R.id.view); 168 | setParameter(mainView, position, b, rootView); 169 | windowManager.addView(rootView, mParams); 170 | mainView.startAnimation(false); 171 | } 172 | 173 | private Animation getAlphaAnimation(int i) 174 | { 175 | Animation alphaAnimation = new AlphaAnimation(1, 0); 176 | alphaAnimation.setDuration(i); 177 | alphaAnimation.setAnimationListener(mAnimationListener); 178 | return alphaAnimation; 179 | } 180 | 181 | private void setParameter(MainView mainView, int[] position, 182 | Bitmap bitmap, View rootView) 183 | { 184 | setLeftMargin(position, rootView); 185 | setTopMargin(mainView, position); 186 | mainView.setBitmap(bitmap); 187 | } 188 | 189 | private void setTopMargin(MainView mainView, int[] position) 190 | { 191 | LayoutParams lp = (LayoutParams) mainView.getLayoutParams(); 192 | // lp.leftMargin = position[0]; 193 | lp.topMargin = position[1] - LauncherActivity.VERTICAL_OFFSET; 194 | mainView.setLayoutParams(lp); 195 | 196 | } 197 | 198 | private void setLeftMargin(int[] position, View rootView) 199 | { 200 | TextView tv = (TextView) rootView.findViewById(R.id.space_h); 201 | LayoutParams lpp = (LayoutParams) tv.getLayoutParams(); 202 | // log.e("position[0]=" + position[0]); 203 | float magic = LauncherActivity.SCREEN_WIDTH 204 | - (float) (getDensity() / LauncherActivity.BASE_SCREEN_DENSITY) 205 | * LauncherActivity.BASE_SCREEN_WIDTH; 206 | lpp.width = (int) (position[0] - magic); 207 | // lpp.height = position[1]; 208 | tv.setLayoutParams(lpp); 209 | } 210 | 211 | private double getDensity() 212 | { 213 | DisplayMetrics m = new DisplayMetrics(); 214 | windowManager.getDefaultDisplay().getMetrics(m); 215 | return m.density; 216 | } 217 | 218 | private void setButtonPressedEffect(BadgeView badge) 219 | { 220 | Animation a = new ScaleAnimation(1, 1.2F, 1, 1.2F, 221 | Animation.RELATIVE_TO_SELF, 0.8f, 222 | Animation.RELATIVE_TO_SELF, 0.8f); 223 | a.setDuration(100); 224 | badge.setBackgroundColor(Color.parseColor("#c00000")); 225 | badge.startAnimation(a); 226 | if (!LauncherActivity.DEBUG_MODE) 227 | Utils.vibrate(context); 228 | } 229 | 230 | private int[] getPosition(int[] wh) 231 | { 232 | log.d("wh[0]=" + wh[0] + " wh[1]=" + wh[1]); 233 | int maxX = LauncherActivity.SCREEN_WIDTH - wh[0]; 234 | int x = mParams.x > maxX ? maxX : mParams.x; 235 | x = x > 0 ? x : 0; 236 | 237 | int maxY = LauncherActivity.SCREEN_HEIGHT - wh[1]; 238 | int magic = LauncherActivity.IS_TABLTE ? 0 : 2; 239 | int y = mParams.y > maxY ? maxY - magic 240 | * LauncherActivity.VERTICAL_OFFSET : mParams.y; 241 | y = y > 0 ? y : 0; 242 | 243 | log.d("mParams.x=" + mParams.x + " mParams.y=" + mParams.y 244 | + " x=" + x + " y=" + y); 245 | int[] ret = { x, y }; 246 | return ret; 247 | } 248 | }); 249 | badge.show(); 250 | 251 | } 252 | 253 | private int[] getCustomWindowLayoutWidthAndHeight( 254 | LinearLayout customWindowLayout2) 255 | { 256 | int widthMeasureSpec, heightMeasureSpec; 257 | widthMeasureSpec = heightMeasureSpec = View.MeasureSpec 258 | .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 259 | mCustomWindowLayout.measure(widthMeasureSpec, heightMeasureSpec); 260 | int w = mCustomWindowLayout.getMeasuredWidth(); 261 | int h = mCustomWindowLayout.getMeasuredHeight(); 262 | log.d("w=" + w + " h=" + h); 263 | int[] ret = { w, h }; 264 | return ret; 265 | } 266 | 267 | @Override 268 | public boolean onTouchEvent(MotionEvent event) 269 | { 270 | switch (event.getAction()) 271 | { 272 | 273 | case MotionEvent.ACTION_DOWN: 274 | xInView = event.getX(); 275 | yInView = event.getY(); 276 | break; 277 | case MotionEvent.ACTION_MOVE: 278 | xInScreen = event.getRawX(); 279 | // if pad,then status bar will be in the bottom,can not minus 280 | // status bar height,but pad not ensure status bar in the bottom 281 | yInScreen = LauncherActivity.IS_TABLTE ? event.getRawY() 282 | : event.getRawY() 283 | - ScreenLib.getStatusBarHeight(mContext); 284 | updateViewPosition(); 285 | break; 286 | case MotionEvent.ACTION_UP: 287 | break; 288 | default: 289 | break; 290 | } 291 | return true; 292 | } 293 | 294 | public void setParams(WindowManager.LayoutParams params) 295 | { 296 | mParams = params; 297 | } 298 | 299 | private void updateViewPosition() 300 | { 301 | mParams.x = (int) (xInScreen - xInView) > 0 ? (int) (xInScreen - xInView) 302 | : 0; 303 | mParams.y = (int) (yInScreen - yInView); 304 | // log.e("x=" + mParams.x + " y=" + mParams.y); 305 | windowManager.updateViewLayout(this, mParams); 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowManager.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | 7 | import com.tochange.yang.floatladdin.LauncherActivity; 8 | import com.tochange.yang.floatladdin.R; 9 | import com.tochange.yang.lib.log; 10 | 11 | import android.app.ActivityManager; 12 | import android.content.Context; 13 | import android.graphics.PixelFormat; 14 | import android.view.Gravity; 15 | import android.view.WindowManager; 16 | import android.view.WindowManager.LayoutParams; 17 | import android.widget.TextView; 18 | 19 | public class FloatWindowManager 20 | { 21 | 22 | private static LayoutParams customWindowParams; 23 | 24 | private static FloatWindowCustomView customWindow; 25 | 26 | private static WindowManager mWindowManager; 27 | 28 | private static ActivityManager mActivityManager; 29 | 30 | public static void createCustomWindow(Context context) 31 | { 32 | if (customWindow == null) 33 | { 34 | WindowManager windowManager = getWindowManager(context); 35 | customWindow = new FloatWindowCustomView(context); 36 | if (customWindowParams == null) 37 | { 38 | customWindowParams = new LayoutParams(); 39 | customWindowParams.type = LayoutParams.TYPE_SYSTEM_ALERT; 40 | customWindowParams.format = PixelFormat.RGBA_8888; 41 | customWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL 42 | | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 43 | | LayoutParams.FLAG_NOT_FOCUSABLE; 44 | customWindowParams.gravity = Gravity.LEFT | Gravity.TOP; 45 | customWindowParams.width = LayoutParams.WRAP_CONTENT; 46 | customWindowParams.height = LayoutParams.WRAP_CONTENT; 47 | LauncherActivity.SCREEN_WIDTH = windowManager 48 | .getDefaultDisplay().getWidth(); 49 | LauncherActivity.SCREEN_HEIGHT = windowManager 50 | .getDefaultDisplay().getHeight(); 51 | customWindowParams.x = LauncherActivity.SCREEN_WIDTH / 4; 52 | customWindowParams.y = LauncherActivity.SCREEN_HEIGHT * 2 / 3; 53 | } 54 | customWindow.setParams(customWindowParams); 55 | windowManager.addView(customWindow, customWindowParams); 56 | } 57 | } 58 | 59 | public static void removeCustomWindow(Context context) 60 | { 61 | if (customWindow != null) 62 | { 63 | WindowManager windowManager = getWindowManager(context); 64 | windowManager.removeView(customWindow); 65 | customWindow = null; 66 | } 67 | } 68 | 69 | public static void updateUsedPercent(Context context) 70 | { 71 | if (customWindow != null) 72 | { 73 | TextView percentView = (TextView) customWindow 74 | .findViewById(R.id.percent); 75 | if (percentView != null) 76 | percentView.setText(getUsedPercentValue(context)); 77 | } 78 | } 79 | 80 | public static boolean isWindowShowing() 81 | { 82 | return customWindow != null; 83 | } 84 | 85 | private static WindowManager getWindowManager(Context context) 86 | { 87 | if (mWindowManager == null) 88 | { 89 | mWindowManager = (WindowManager) context 90 | .getSystemService(Context.WINDOW_SERVICE); 91 | } 92 | return mWindowManager; 93 | } 94 | 95 | private static ActivityManager getActivityManager(Context context) 96 | { 97 | if (mActivityManager == null) 98 | { 99 | mActivityManager = (ActivityManager) context 100 | .getSystemService(Context.ACTIVITY_SERVICE); 101 | } 102 | return mActivityManager; 103 | } 104 | 105 | public static String getUsedPercentValue(Context context) 106 | { 107 | String dir = "/proc/meminfo"; 108 | try 109 | { 110 | FileReader fr = new FileReader(dir); 111 | BufferedReader br = new BufferedReader(fr, 2048); 112 | String memoryLine = br.readLine(); 113 | String subMemoryLine = memoryLine.substring(memoryLine 114 | .indexOf("MemTotal:")); 115 | br.close(); 116 | long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll( 117 | "\\D+", "")); 118 | long availableSize = getAvailableMemory(context) / 1024; 119 | int percent = (int) ((totalMemorySize - availableSize) 120 | / (float) totalMemorySize * 100); 121 | return percent + "%"; 122 | } 123 | catch (IOException e) 124 | { 125 | log.e(e.toString()); 126 | } 127 | return "floating windows"; 128 | } 129 | 130 | private static long getAvailableMemory(Context context) 131 | { 132 | ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); 133 | getActivityManager(context).getMemoryInfo(mi); 134 | return mi.availMem; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /NoActivityAladdin/Aladdin/src/com/tochange/yang/floatladdin/floatwindow/FloatWindowService.java: -------------------------------------------------------------------------------- 1 | package com.tochange.yang.floatladdin.floatwindow; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Timer; 6 | import java.util.TimerTask; 7 | 8 | import com.tochange.yang.lib.log; 9 | 10 | import android.app.ActivityManager; 11 | import android.app.ActivityManager.RunningTaskInfo; 12 | import android.app.Service; 13 | import android.content.Context; 14 | import android.content.Intent; 15 | import android.content.pm.PackageManager; 16 | import android.content.pm.ResolveInfo; 17 | import android.os.Handler; 18 | import android.os.IBinder; 19 | 20 | public class FloatWindowService extends Service { 21 | public static FloatWindowService mFloatWindowService; 22 | private Handler handler = new Handler(); 23 | private Timer timer; 24 | 25 | @Override 26 | public IBinder onBind(Intent intent) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public int onStartCommand(Intent intent, int flags, int startId) { 32 | // 开启定时器,每隔0.5秒刷新一次 33 | // log.e(""); 34 | if (timer == null) { 35 | timer = new Timer(); 36 | timer.scheduleAtFixedRate(new RefreshTask(), 0, 500); 37 | } 38 | mFloatWindowService = this; 39 | return super.onStartCommand(intent, flags, startId); 40 | } 41 | 42 | @Override 43 | public void onDestroy() { 44 | // log.e(""); 45 | FloatWindowManager.removeCustomWindow(getApplicationContext()); 46 | super.onDestroy(); 47 | timer.cancel(); 48 | timer = null; 49 | } 50 | 51 | class RefreshTask extends TimerTask { 52 | 53 | @Override 54 | public void run() { 55 | // 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。 56 | if (isHome() && !FloatWindowManager.isWindowShowing()) { 57 | handler.post(new Runnable() { 58 | @Override 59 | public void run() { 60 | FloatWindowManager.createCustomWindow(getApplicationContext()); 61 | } 62 | }); 63 | } 64 | // 当前界面不是桌面,且有悬浮窗显示,则移除悬浮窗。 65 | else if (!isHome() && FloatWindowManager.isWindowShowing()) { 66 | handler.post(new Runnable() { 67 | @Override 68 | public void run() { 69 | // FloatWindowManager.removeCustomWindow(getApplicationContext()); 70 | } 71 | }); 72 | } 73 | // 当前界面是桌面,且有悬浮窗显示,则更新内存数据。 74 | else if (isHome() && FloatWindowManager.isWindowShowing()) { 75 | handler.post(new Runnable() { 76 | @Override 77 | public void run() { 78 | FloatWindowManager.updateUsedPercent(getApplicationContext()); 79 | } 80 | }); 81 | } 82 | } 83 | 84 | } 85 | 86 | /** 87 | * 判断当前界面是否是桌面 88 | */ 89 | private boolean isHome() { 90 | ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 91 | List rti = mActivityManager.getRunningTasks(1); 92 | return getHomes().contains(rti.get(0).topActivity.getPackageName()); 93 | } 94 | 95 | /** 96 | * 获得属于桌面的应用的应用包名称 97 | * 98 | * @return 返回包含所有包名的字符串列表 99 | */ 100 | private List getHomes() { 101 | List names = new ArrayList(); 102 | PackageManager packageManager = this.getPackageManager(); 103 | Intent intent = new Intent(Intent.ACTION_MAIN); 104 | intent.addCategory(Intent.CATEGORY_HOME); 105 | List resolveInfo = packageManager.queryIntentActivities(intent, 106 | PackageManager.MATCH_DEFAULT_ONLY); 107 | for (ResolveInfo ri : resolveInfo) { 108 | names.add(ri.activityInfo.packageName); 109 | } 110 | return names; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/README.md -------------------------------------------------------------------------------- /aa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/aa.gif -------------------------------------------------------------------------------- /mac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tochange/Aladdin/51c2708874aa4b66be596e2bfde966d79897c997/mac.jpg --------------------------------------------------------------------------------